summaryrefslogtreecommitdiff
path: root/sql/mysqld.cc
diff options
context:
space:
mode:
Diffstat (limited to 'sql/mysqld.cc')
-rw-r--r--sql/mysqld.cc225
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
/*