diff options
Diffstat (limited to 'sql/mysqld.cc')
-rw-r--r-- | sql/mysqld.cc | 225 |
1 files changed, 178 insertions, 47 deletions
diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 4d688d795f7..b8df51e9e58 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -138,6 +138,13 @@ extern "C" { // Because of SCO 3.2V4.2 #include <sys/mman.h> #endif +#ifdef __WIN__ +#include <crtdbg.h> +#define SIGNAL_FMT "exception 0x%x" +#else +#define SIGNAL_FMT "signal %d" +#endif + #ifdef __NETWARE__ #define zVOLSTATE_ACTIVE 6 #define zVOLSTATE_DEACTIVE 2 @@ -227,6 +234,7 @@ inline void set_proper_floating_point_mode() extern "C" int gethostname(char *name, int namelen); #endif +extern "C" sig_handler handle_segfault(int sig); /* Constants */ @@ -1030,9 +1038,6 @@ static void __cdecl kill_server(int sig_ptr) #endif close_connections(); if (sig != MYSQL_KILL_SIGNAL && -#ifdef __WIN__ - sig != SIGINT && /* Bug#18235 */ -#endif sig != 0) unireg_abort(1); /* purecov: inspected */ else @@ -1591,8 +1596,7 @@ static void network_init(void) FORMAT_MESSAGE_FROM_SYSTEM, NULL, error, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR) &lpMsgBuf, 0, NULL ); - MessageBox(NULL, (LPTSTR) lpMsgBuf, "Error from CreateNamedPipe", - MB_OK|MB_ICONINFORMATION); + sql_perror((char *)lpMsgBuf); LocalFree(lpMsgBuf); unireg_abort(1); } @@ -1795,17 +1799,163 @@ extern "C" sig_handler abort_thread(int sig __attribute__((unused))) ******************************************************************************/ -#if defined(__WIN__) || defined(OS2) +#if defined(__WIN__) + + +/* + On Windows, we use native SetConsoleCtrlHandler for handle events like Ctrl-C + with graceful shutdown. + Also, we do not use signal(), but SetUnhandledExceptionFilter instead - as it + provides possibility to pass the exception to just-in-time debugger, collect + dumps and potentially also the exception and thread context used to output + callstack. +*/ + +static BOOL WINAPI console_event_handler( DWORD type ) +{ + DBUG_ENTER("console_event_handler"); + if(type == CTRL_C_EVENT) + { + /* + Do not shutdown before startup is finished and shutdown + thread is initialized. Otherwise there is a race condition + between main thread doing initialization and CTRL-C thread doing + cleanup, which can result into crash. + */ + if(hEventShutdown) + kill_mysql(); + else + sql_print_warning("CTRL-C ignored during startup"); + DBUG_RETURN(TRUE); + } + DBUG_RETURN(FALSE); +} + + +/* + In Visual Studio 2005 and later, default SIGABRT handler will overwrite + any unhandled exception filter set by the application and will try to + call JIT debugger. This is not what we want, this we calling __debugbreak + to stop in debugger, if process is being debugged or to generate + EXCEPTION_BREAKPOINT and then handle_segfault will do its magic. +*/ + +#if (_MSC_VER >= 1400) +static void my_sigabrt_handler(int sig) +{ + __debugbreak(); +} +#endif /*_MSC_VER >=1400 */ + +void win_install_sigabrt_handler(void) +{ +#if (_MSC_VER >=1400) + /*abort() should not override our exception filter*/ + _set_abort_behavior(0,_CALL_REPORTFAULT); + signal(SIGABRT,my_sigabrt_handler); +#endif /* _MSC_VER >=1400 */ +} + +#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER +#define DEBUGGER_ATTACH_TIMEOUT 120 +/* + Wait for debugger to attach and break into debugger. If debugger is not attached, + resume after timeout. +*/ +static void wait_for_debugger(int timeout_sec) +{ + if(!IsDebuggerPresent()) + { + int i; + printf("Waiting for debugger to attach, pid=%u\n",GetCurrentProcessId()); + fflush(stdout); + for(i= 0; i < timeout_sec; i++) + { + Sleep(1000); + if(IsDebuggerPresent()) + { + /* Break into debugger */ + __debugbreak(); + return; + } + } + printf("pid=%u, debugger not attached after %d seconds, resuming\n",GetCurrentProcessId(), + timeout_sec); + fflush(stdout); + } +} +#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */ + +LONG WINAPI my_unhandler_exception_filter(EXCEPTION_POINTERS *ex_pointers) +{ + static BOOL first_time= TRUE; + if(!first_time) + { + /* + This routine can be called twice, typically + when detaching in JIT debugger. + Return EXCEPTION_EXECUTE_HANDLER to terminate process. + */ + return EXCEPTION_EXECUTE_HANDLER; + } + first_time= FALSE; +#ifdef DEBUG_UNHANDLED_EXCEPTION_FILTER + /* + Unfortunately there is no clean way to debug unhandled exception filters, + as debugger does not stop there(also documented in MSDN) + To overcome, one could put a MessageBox, but this will not work in service. + Better solution is to print error message and sleep some minutes + until debugger is attached + */ + wait_for_debugger(DEBUGGER_ATTACH_TIMEOUT); +#endif /* DEBUG_UNHANDLED_EXCEPTION_FILTER */ + __try + { + set_exception_pointers(ex_pointers); + handle_segfault(ex_pointers->ExceptionRecord->ExceptionCode); + } + __except(EXCEPTION_EXECUTE_HANDLER) + { + DWORD written; + const char msg[] = "Got exception in exception handler!\n"; + WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),msg, sizeof(msg)-1, + &written,NULL); + } + /* + Return EXCEPTION_CONTINUE_SEARCH to give JIT debugger + (drwtsn32 or vsjitdebugger) possibility to attach, + if JIT debugger is configured. + Windows Error reporting might generate a dump here. + */ + return EXCEPTION_CONTINUE_SEARCH; +} + + static void init_signals(void) { - int signals[] = {SIGINT,SIGILL,SIGFPE,SIGSEGV,SIGTERM,SIGABRT } ; - for (uint i=0 ; i < sizeof(signals)/sizeof(int) ; i++) - signal(signals[i], kill_server) ; -#if defined(__WIN__) - signal(SIGBREAK,SIG_IGN); //ignore SIGBREAK for NT -#else - signal(SIGBREAK, kill_server); -#endif + win_install_sigabrt_handler(); + if(opt_console) + SetConsoleCtrlHandler(console_event_handler,TRUE); + else + { + /* Avoid MessageBox()es*/ + _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); + _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); + + /* + Do not use SEM_NOGPFAULTERRORBOX in the following SetErrorMode (), + because it would prevent JIT debugger and Windows error reporting + from working. We need WER or JIT-debugging, since our own unhandled + exception filter is not guaranteed to work in all situation + (like heap corruption or stack overflow) + */ + SetErrorMode(SetErrorMode(0)|SEM_FAILCRITICALERRORS|SEM_NOOPENFILEERRORBOX); + } + SetUnhandledExceptionFilter(my_unhandler_exception_filter); } static void start_signal_handler(void) @@ -2093,8 +2243,8 @@ static void start_signal_handler(void) static void check_data_home(const char *path) {} +#endif /*__WIN__ || __NETWARE || __EMX__*/ -#else /* if ! __WIN__ && ! __EMX__ */ #ifdef HAVE_LINUXTHREADS #define UNSAFE_DEFAULT_LINUX_THREADS 200 @@ -2114,7 +2264,7 @@ extern "C" sig_handler handle_segfault(int sig) */ if (segfaulted) { - fprintf(stderr, "Fatal signal %d while backtracing\n", sig); + fprintf(stderr, "Fatal " SIGNAL_FMT " while backtracing\n", sig); exit(1); } @@ -2124,7 +2274,7 @@ extern "C" sig_handler handle_segfault(int sig) localtime_r(&curr_time, &tm); fprintf(stderr,"\ -%02d%02d%02d %2d:%02d:%02d - mysqld got signal %d;\n\ +%02d%02d%02d %2d:%02d:%02d - mysqld got " SIGNAL_FMT " ;\n\ This could be because you hit a bug. It is also possible that this binary\n\ or one of the libraries it was linked against is corrupt, improperly built,\n\ or misconfigured. This error can also be caused by malfunctioning hardware.\n", @@ -2165,6 +2315,10 @@ the thread stack. Please read http://dev.mysql.com/doc/mysql/en/linux.html\n\n", if (!(test_flags & TEST_NO_STACKTRACE)) { fprintf(stderr,"thd=%p\n",thd); + fprintf(stderr,"\ +Attempting backtrace. You can use the following information to find out\n\ +where mysqld died. If you see no messages after this, something went\n\ +terribly wrong...\n"); print_stacktrace(thd ? (gptr) thd->thread_stack : (gptr) 0, thread_stack); } @@ -2213,15 +2367,22 @@ of those buggy OS calls. You should consider whether you really need the\n\ bugs.\n"); } +#ifdef HAVE_WRITE_CORE if (test_flags & TEST_CORE_ON_SIGNAL) { fprintf(stderr, "Writing a core file\n"); fflush(stderr); write_core(sig); } +#endif + +#ifndef __WIN__ + /* On Windows, do not terminate, but pass control to exception filter */ exit(1); +#endif } +#if !defined(__WIN__) && !defined(__NETWARE__) && !defined(__EMX__) #ifndef SA_RESETHAND #define SA_RESETHAND 0 #endif @@ -2564,19 +2725,6 @@ static void my_str_free_mysqld(void *ptr) #ifdef __WIN__ - -struct utsname -{ - char nodename[FN_REFLEN]; -}; - - -int uname(struct utsname *a) -{ - return -1; -} - - pthread_handler_t handle_shutdown(void *arg) { MSG msg; @@ -2590,18 +2738,6 @@ pthread_handler_t handle_shutdown(void *arg) kill_server(MYSQL_KILL_SIGNAL); return 0; } - - -int STDCALL handle_kill(ulong ctrl_type) -{ - if (ctrl_type == CTRL_CLOSE_EVENT || - ctrl_type == CTRL_SHUTDOWN_EVENT) - { - kill_server(MYSQL_KILL_SIGNAL); - return TRUE; - } - return FALSE; -} #endif @@ -3630,11 +3766,6 @@ we force server id to 2, but this MySQL server will not act as a slave."); freopen(log_error_file,"a+",stderr); FreeConsole(); // Remove window } - else - { - /* Don't show error dialog box when on foreground: it stops the server */ - SetErrorMode(SEM_NOOPENFILEERRORBOX | SEM_FAILCRITICALERRORS); - } #endif /* |