summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMathias Stearn <mathias@10gen.com>2014-04-01 18:11:43 -0400
committerMathias Stearn <mathias@10gen.com>2014-04-01 19:44:05 -0400
commit261233b6c11a8282b1f626d496a1743a0b48821d (patch)
tree3ad229e0cdc69e16368ef62496031fb3ecb22d2a
parent019f0ccc9efbdb3a76e8e50259dd2921b939d39a (diff)
downloadmongo-261233b6c11a8282b1f626d496a1743a0b48821d.tar.gz
SERVER-13429 unify signal handling between mongos and mongod
(cherry picked from commit ad91eb0f75f39c1bb71b5e0ca4279b883cb9fe8d)
-rw-r--r--jstests/noPassthrough/exit_logging.js16
-rw-r--r--src/mongo/SConscript2
-rw-r--r--src/mongo/db/db.cpp273
-rw-r--r--src/mongo/db/initialize_server_global_state.cpp9
-rw-r--r--src/mongo/db/initialize_server_global_state.h2
-rw-r--r--src/mongo/db/instance.cpp5
-rw-r--r--src/mongo/s/server.cpp119
-rw-r--r--src/mongo/util/signal_handlers.cpp252
-rw-r--r--src/mongo/util/signal_handlers.h15
9 files changed, 302 insertions, 391 deletions
diff --git a/jstests/noPassthrough/exit_logging.js b/jstests/noPassthrough/exit_logging.js
index 89615b34e8c..32e3dd2d3de 100644
--- a/jstests/noPassthrough/exit_logging.js
+++ b/jstests/noPassthrough/exit_logging.js
@@ -18,8 +18,10 @@
function makeRegExMatchFn(pattern) {
return function (text) {
- assert(pattern.test(text),
- "Log contents did not match " + pattern);
+ if (!pattern.test(text)) {
+ print(text);
+ doassert("Log contents did not match " + pattern);
+ }
}
}
@@ -42,16 +44,16 @@
return;
}
- // testShutdownLogging(
- // function (conn) { conn.getDB('admin').shutdownServer() },
- // makeRegExMatchFn(/shutdown command received[\s\S]*dbexit: really exiting now/));
+ testShutdownLogging(
+ function (conn) { conn.getDB('admin').shutdownServer() },
+ makeRegExMatchFn(/shutdown command received[\s\S]*dbexit: really exiting now/));
testShutdownLogging(
makeShutdownByCrashFn('fault'),
- makeRegExMatchFn(/Invalid access at address[\s\S]*abruptQuitWithAddrSignal/));
+ makeRegExMatchFn(/Invalid access at address[\s\S]*printStackTrace/));
testShutdownLogging(
makeShutdownByCrashFn('abort'),
- makeRegExMatchFn(/Got signal[\s\S]*abruptQuit[^W]/));
+ makeRegExMatchFn(/Got signal[\s\S]*printStackTrace/));
}());
diff --git a/src/mongo/SConscript b/src/mongo/SConscript
index daaa322c05d..58f8406a89b 100644
--- a/src/mongo/SConscript
+++ b/src/mongo/SConscript
@@ -46,7 +46,6 @@ env.Library('foundation',
'util/file.cpp',
'util/log.cpp',
'util/platform_init.cpp',
- 'util/signal_handlers.cpp',
'util/text.cpp',
'util/time_support.cpp',
'util/timer.cpp',
@@ -901,6 +900,7 @@ mongodAndMongosFiles = [
"db/initialize_server_global_state.cpp",
"db/server_extra_log_context.cpp",
"db/dbwebserver.cpp",
+ "util/signal_handlers.cpp",
]
env.Library("mongodandmongos", mongodAndMongosFiles,
LIBDEPS=["message_server_port"])
diff --git a/src/mongo/db/db.cpp b/src/mongo/db/db.cpp
index 4f19610d1b6..2a5562d08bf 100644
--- a/src/mongo/db/db.cpp
+++ b/src/mongo/db/db.cpp
@@ -88,7 +88,7 @@
#include "mongo/util/options_parser/startup_options.h"
#include "mongo/util/ramlog.h"
#include "mongo/util/scopeguard.h"
-#include "mongo/util/signal_win32.h"
+#include "mongo/util/signal_handlers.h"
#include "mongo/util/stacktrace.h"
#include "mongo/util/startup_test.h"
#include "mongo/util/text.h"
@@ -108,8 +108,6 @@ namespace mongo {
extern int diagLogging;
extern int lockFile;
- static void setupSignalHandlers();
- static void startSignalProcessingThread();
void exitCleanly( ExitCode code );
#ifdef _WIN32
@@ -934,9 +932,35 @@ MONGO_INITIALIZER_GENERAL(setSSLManagerType,
}
#endif
+#if defined(_WIN32)
+namespace mongo {
+ // the hook for mongoAbort
+ extern void (*reportEventToSystem)(const char *msg);
+ static void reportEventToSystemImpl(const char *msg) {
+ static ::HANDLE hEventLog = RegisterEventSource( NULL, TEXT("mongod") );
+ if( hEventLog ) {
+ std::wstring s = toNativeString(msg);
+ LPCTSTR txt = s.c_str();
+ BOOL ok = ReportEvent(
+ hEventLog, EVENTLOG_ERROR_TYPE,
+ 0, 0, NULL,
+ 1,
+ 0,
+ &txt,
+ 0);
+ wassert(ok);
+ }
+ }
+} // namespace mongo
+#endif // if defined(_WIN32)
+
static int mongoDbMain(int argc, char* argv[], char **envp) {
static StaticObserver staticObserver;
+#if defined(_WIN32)
+ mongo::reportEventToSystem = &mongo::reportEventToSystemImpl;
+#endif
+
getcurns = ourgetns;
setupSignalHandlers();
@@ -987,246 +1011,3 @@ static int mongoDbMain(int argc, char* argv[], char **envp) {
dbexit(EXIT_CLEAN);
return 0;
}
-
-namespace mongo {
-
- string getDbContext();
-
-#undef out
-
-
-#if !defined(_WIN32)
-
-} // namespace mongo
-
-#include <signal.h>
-#include <string.h>
-
-namespace mongo {
-
- void abruptQuit(int signalNum) {
- {
- logger::LogstreamBuilder logBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Severe());
- logBuilder.stream() <<
- "Got signal: " << signalNum << " (" << strsignal(signalNum) << ").\nBacktrace:";
- printStackTrace(logBuilder.stream());
- }
-
- // Don't go through normal shutdown procedure. It may make things worse.
- ::_exit(EXIT_ABRUPT);
- }
-
- void abruptQuitWithAddrSignal( int signalNum, siginfo_t *siginfo, void * ) {
- {
- logger::LogstreamBuilder logBuilder(logger::globalLogDomain(),
- getThreadName(),
- logger::LogSeverity::Severe());
-
- std::ostream& oss = logBuilder.stream();
- oss << "Invalid";
- if ( signalNum == SIGSEGV || signalNum == SIGBUS ) {
- oss << " access";
- } else {
- oss << " operation";
- }
- oss << " at address: " << siginfo->si_addr;
- }
- abruptQuit( signalNum );
- }
-
- sigset_t asyncSignals;
- // The signals in asyncSignals will be processed by this thread only, in order to
- // ensure the db and log mutexes aren't held.
- void signalProcessingThread() {
- while (true) {
- int actualSignal = 0;
- int status = sigwait( &asyncSignals, &actualSignal );
- fassert(16781, status == 0);
- switch (actualSignal) {
- case SIGUSR1:
- // log rotate signal
- fassert(16782, rotateLogs());
- logProcessDetailsForLogRotate();
- break;
- case SIGQUIT:
- log() << "Received SIGQUIT; terminating.";
- _exit(EXIT_ABRUPT);
- default:
- // interrupt/terminate signal
- Client::initThread( "signalProcessingThread" );
- log() << "got signal " << actualSignal << " (" << strsignal( actualSignal )
- << "), will terminate after current cmd ends" << endl;
- exitCleanly( EXIT_CLEAN );
- break;
- }
- }
- }
-
- // this will be called in certain c++ error cases, for example if there are two active
- // exceptions
- void myterminate() {
- printStackTrace(severe().stream()
- << "terminate() called, printing stack (if implemented for platform):\n");
- ::abort();
- }
-
- // this gets called when new fails to allocate memory
- void my_new_handler() {
- printStackTrace(severe().stream() << "out of memory, printing stack and exiting:\n");
- ::_exit(EXIT_ABRUPT);
- }
-
- void setupSignals_ignoreHelper( int signal ) {}
-
- void setupSignalHandlers() {
- setupCoreSignals();
-
- struct sigaction addrSignals;
- memset( &addrSignals, 0, sizeof( struct sigaction ) );
- addrSignals.sa_sigaction = abruptQuitWithAddrSignal;
- sigemptyset( &addrSignals.sa_mask );
- addrSignals.sa_flags = SA_SIGINFO;
-
- verify( sigaction(SIGSEGV, &addrSignals, 0) == 0 );
- verify( sigaction(SIGBUS, &addrSignals, 0) == 0 );
- verify( sigaction(SIGILL, &addrSignals, 0) == 0 );
- verify( sigaction(SIGFPE, &addrSignals, 0) == 0 );
-
- verify( signal(SIGABRT, abruptQuit) != SIG_ERR );
- verify( signal(SIGPIPE, SIG_IGN) != SIG_ERR );
-
- setupSIGTRAPforGDB();
-
- // asyncSignals is a global variable listing the signals that should be handled by the
- // interrupt thread, once it is started via startSignalProcessingThread().
- sigemptyset( &asyncSignals );
- sigaddset( &asyncSignals, SIGHUP );
- sigaddset( &asyncSignals, SIGINT );
- sigaddset( &asyncSignals, SIGTERM );
- sigaddset( &asyncSignals, SIGQUIT );
- sigaddset( &asyncSignals, SIGUSR1 );
- sigaddset( &asyncSignals, SIGXCPU );
-
- set_terminate( myterminate );
- set_new_handler( my_new_handler );
- }
-
- void startSignalProcessingThread() {
- verify( pthread_sigmask( SIG_SETMASK, &asyncSignals, 0 ) == 0 );
- boost::thread it( signalProcessingThread );
- }
-
-#else // WIN32
- void consoleTerminate( const char* controlCodeName ) {
- Client::initThread( "consoleTerminate" );
- log() << "got " << controlCodeName << ", will terminate after current cmd ends" << endl;
- exitCleanly( EXIT_KILL );
- }
-
- BOOL WINAPI CtrlHandler( DWORD fdwCtrlType ) {
-
- switch( fdwCtrlType ) {
-
- case CTRL_C_EVENT:
- log() << "Ctrl-C signal";
- consoleTerminate( "CTRL_C_EVENT" );
- return TRUE ;
-
- case CTRL_CLOSE_EVENT:
- log() << "CTRL_CLOSE_EVENT signal";
- consoleTerminate( "CTRL_CLOSE_EVENT" );
- return TRUE ;
-
- case CTRL_BREAK_EVENT:
- log() << "CTRL_BREAK_EVENT signal";
- consoleTerminate( "CTRL_BREAK_EVENT" );
- return TRUE;
-
- case CTRL_LOGOFF_EVENT:
- // only sent to services, and only in pre-Vista Windows; FALSE means ignore
- return FALSE;
-
- case CTRL_SHUTDOWN_EVENT:
- log() << "CTRL_SHUTDOWN_EVENT signal";
- consoleTerminate( "CTRL_SHUTDOWN_EVENT" );
- return TRUE;
-
- default:
- return FALSE;
- }
- }
-
- // called by mongoAbort()
- extern void (*reportEventToSystem)(const char *msg);
- void reportEventToSystemImpl(const char *msg) {
- static ::HANDLE hEventLog = RegisterEventSource( NULL, TEXT("mongod") );
- if( hEventLog ) {
- std::wstring s = toNativeString(msg);
- LPCTSTR txt = s.c_str();
- BOOL ok = ReportEvent(
- hEventLog, EVENTLOG_ERROR_TYPE,
- 0, 0, NULL,
- 1,
- 0,
- &txt,
- 0);
- wassert(ok);
- }
- }
-
- void myPurecallHandler() {
- printStackTrace();
- mongoAbort("pure virtual");
- }
-
- void setupSignalHandlers() {
- reportEventToSystem = reportEventToSystemImpl;
- setWindowsUnhandledExceptionFilter();
- massert(10297,
- "Couldn't register Windows Ctrl-C handler",
- SetConsoleCtrlHandler(static_cast<PHANDLER_ROUTINE>(CtrlHandler), TRUE));
- _set_purecall_handler( myPurecallHandler );
- }
-
- void eventProcessingThread() {
- std::string eventName = getShutdownSignalName(ProcessId::getCurrent().asUInt32());
-
- HANDLE event = CreateEventA(NULL, TRUE, FALSE, eventName.c_str());
- if (event == NULL) {
- warning() << "eventProcessingThread CreateEvent failed: "
- << errnoWithDescription();
- return;
- }
-
- ON_BLOCK_EXIT(CloseHandle, event);
-
- int returnCode = WaitForSingleObject(event, INFINITE);
- if (returnCode != WAIT_OBJECT_0) {
- if (returnCode == WAIT_FAILED) {
- warning() << "eventProcessingThread WaitForSingleObject failed: "
- << errnoWithDescription();
- return;
- }
- else {
- warning() << "eventProcessingThread WaitForSingleObject failed: "
- << errnoWithDescription(returnCode);
- return;
- }
- }
-
- Client::initThread("eventTerminate");
- log() << "shutdown event signaled, will terminate after current cmd ends";
- exitCleanly(EXIT_CLEAN);
- }
-
- void startSignalProcessingThread() {
- if (Command::testCommandsEnabled) {
- boost::thread it(eventProcessingThread);
- }
- }
-
-#endif // if !defined(_WIN32)
-
-} // namespace mongo
diff --git a/src/mongo/db/initialize_server_global_state.cpp b/src/mongo/db/initialize_server_global_state.cpp
index f32250d6d4f..df9f77fdb2e 100644
--- a/src/mongo/db/initialize_server_global_state.cpp
+++ b/src/mongo/db/initialize_server_global_state.cpp
@@ -366,13 +366,4 @@ namespace mongo {
return true;
}
- static void ignoreSignal( int sig ) {}
-
- void setupCoreSignals() {
-#if !defined(_WIN32)
- verify( signal(SIGHUP , ignoreSignal ) != SIG_ERR );
- verify( signal(SIGUSR2, ignoreSignal ) != SIG_ERR );
-#endif
- }
-
} // namespace mongo
diff --git a/src/mongo/db/initialize_server_global_state.h b/src/mongo/db/initialize_server_global_state.h
index 68f25f77cf2..7085274d7af 100644
--- a/src/mongo/db/initialize_server_global_state.h
+++ b/src/mongo/db/initialize_server_global_state.h
@@ -51,6 +51,4 @@ namespace mongo {
*/
void signalForkSuccess();
- void setupCoreSignals();
-
} // namespace mongo
diff --git a/src/mongo/db/instance.cpp b/src/mongo/db/instance.cpp
index caa27969c7d..a7451fd95a8 100644
--- a/src/mongo/db/instance.cpp
+++ b/src/mongo/db/instance.cpp
@@ -331,10 +331,11 @@ namespace mongo {
return ok;
}
+ // Mongod on win32 defines a value for this function. In all other executables it is NULL.
void (*reportEventToSystem)(const char *msg) = 0;
- void mongoAbort(const char *msg) {
- if( reportEventToSystem )
+ void mongoAbort(const char *msg) {
+ if( reportEventToSystem )
reportEventToSystem(msg);
severe() << msg;
::abort();
diff --git a/src/mongo/s/server.cpp b/src/mongo/s/server.cpp
index f8ba539807a..37311eb1dcb 100644
--- a/src/mongo/s/server.cpp
+++ b/src/mongo/s/server.cpp
@@ -79,7 +79,6 @@
#include "mongo/util/ramlog.h"
#include "mongo/util/scopeguard.h"
#include "mongo/util/signal_handlers.h"
-#include "mongo/util/signal_win32.h"
#include "mongo/util/stacktrace.h"
#include "mongo/util/stringutils.h"
#include "mongo/util/text.h"
@@ -180,119 +179,6 @@ namespace mongo {
}
};
- void sighandler(int sig) {
- dbexit(EXIT_CLEAN, (string("received signal ") + BSONObjBuilder::numStr(sig)).c_str());
- }
-
- void abruptQuit(int x) {
- severe() << "Got signal: " << x << " (" << strsignal( x ) << ").";
- printStackTrace(severe().stream() << "Backtrace: \n");
- ::_exit(EXIT_ABRUPT);
- }
-
- // this gets called when new fails to allocate memory
- void my_new_handler() {
- printStackTrace(severe().stream() << "out of memory, printing stack and exiting:\n");
- ::_exit(EXIT_ABRUPT);
- }
-
-#ifndef _WIN32
- sigset_t asyncSignals;
-
- void signalProcessingThread() {
- while (true) {
- int actualSignal = 0;
- int status = sigwait( &asyncSignals, &actualSignal );
- fassert(16779, status == 0);
- switch (actualSignal) {
- case SIGUSR1:
- // log rotate signal
- fassert(16780, rotateLogs());
- logProcessDetailsForLogRotate();
- break;
- default:
- // no one else should be here
- fassertFailed(16778);
- break;
- }
- }
- }
-
- void startSignalProcessingThread() {
- verify( pthread_sigmask( SIG_SETMASK, &asyncSignals, 0 ) == 0 );
- boost::thread it( signalProcessingThread );
- }
-#else
-
- void eventProcessingThread() {
- std::string eventName = getShutdownSignalName(ProcessId::getCurrent().asUInt32());
-
- HANDLE event = CreateEventA(NULL, TRUE, FALSE, eventName.c_str());
- if (event == NULL) {
- warning() << "eventProcessingThread CreateEvent failed: "
- << errnoWithDescription();
- return;
- }
-
- ON_BLOCK_EXIT(CloseHandle, event);
-
- int returnCode = WaitForSingleObject(event, INFINITE);
- if (returnCode != WAIT_OBJECT_0) {
- if (returnCode == WAIT_FAILED) {
- warning() << "eventProcessingThread WaitForSingleObject failed: "
- << errnoWithDescription();
- return;
- }
- else {
- warning() << "eventProcessingThread WaitForSingleObject failed: "
- << errnoWithDescription(returnCode);
- return;
- }
- }
-
- Client::initThread("eventTerminate");
- log() << "shutdown event signaled, will terminate after current cmd ends";
- exitCleanly(EXIT_CLEAN);
- }
-
- void startSignalProcessingThread() {
- boost::thread it(eventProcessingThread);
- }
-#endif // not _WIN32
-
- void setupSignalHandlers() {
- setupSIGTRAPforGDB();
- setupCoreSignals();
-
- signal(SIGTERM, sighandler);
- signal(SIGINT, sighandler);
-#if defined(SIGXCPU)
- signal(SIGXCPU, sighandler);
-#endif
-
-#if defined(SIGQUIT)
- signal( SIGQUIT , abruptQuit );
-#endif
- signal( SIGSEGV , abruptQuit );
- signal( SIGABRT , abruptQuit );
- signal( SIGFPE , abruptQuit );
-#if defined(SIGBUS)
- signal( SIGBUS , abruptQuit );
-#endif
-#if defined(SIGPIPE)
- signal( SIGPIPE , SIG_IGN );
-#endif
-
-#ifndef _WIN32
- sigemptyset( &asyncSignals );
- sigaddset( &asyncSignals, SIGUSR1 );
-#endif
-
- startSignalProcessingThread();
-
- setWindowsUnhandledExceptionFilter();
- set_new_handler( my_new_handler );
- }
void init() {
serverID.init();
@@ -323,7 +209,6 @@ namespace mongo {
using namespace mongo;
static bool runMongosServer( bool doUpgrade ) {
- setupSignalHandlers();
setThreadName( "mongosMain" );
printShardingVersionInfo( false );
@@ -432,6 +317,8 @@ static int _main() {
if (!initializeServerGlobalState())
return EXIT_FAILURE;
+ startSignalProcessingThread();
+
// we either have a setting where all processes are in localhost or none are
for (std::vector<std::string>::const_iterator it = mongosGlobalParams.configdbs.begin();
it != mongosGlobalParams.configdbs.end(); ++it) {
@@ -500,6 +387,8 @@ int mongoSMain(int argc, char* argv[], char** envp) {
if (argc < 1)
return EXIT_FAILURE;
+ setupSignalHandlers();
+
mongosCommand = argv[0];
Status status = mongo::runGlobalInitializers(argc, argv, envp);
diff --git a/src/mongo/util/signal_handlers.cpp b/src/mongo/util/signal_handlers.cpp
index dd2ad2b1a7f..9f543afa53d 100644
--- a/src/mongo/util/signal_handlers.cpp
+++ b/src/mongo/util/signal_handlers.cpp
@@ -28,19 +28,39 @@
* then also delete it in the license file.
*/
-#include "mongo/pch.h"
+#include "mongo/platform/basic.h"
-#include <cstdarg>
-#include <cstdio>
-#include <cstdlib>
+#include "mongo/util/signal_handlers.h"
-#if !defined(_WIN32) // TODO: windows support
-#include <unistd.h>
-#endif
+#include <boost/thread.hpp>
-#include "mongo/platform/backtrace.h"
+#include "mongo/db/client.h"
+#include "mongo/db/log_process_details.h"
+#include "mongo/util/assert_util.h"
+#include "mongo/util/exit_code.h"
#include "mongo/util/log.h"
-#include "mongo/util/signal_handlers.h"
+#include "mongo/util/scopeguard.h"
+#include "mongo/util/stacktrace.h"
+
+#if defined(_WIN32)
+# include "mongo/util/signal_win32.h"
+# include "mongo/util/exception_filter_win32.h"
+#else
+# include <signal.h>
+# include <unistd.h>
+#endif
+
+#if defined(_WIN32)
+namespace {
+ const char* strsignal(int signalNum) {
+ // should only see SIGABRT on windows
+ switch (signalNum) {
+ case SIGABRT: return "SIGABRT";
+ default: return "UNKNOWN";
+ }
+ }
+}
+#endif
namespace mongo {
@@ -50,6 +70,220 @@ namespace mongo {
* All code in this module must be signal-friendly. Before adding any system
* call or other dependency, please make sure that this still holds.
*
+ * All code in this file follows this pattern:
+ * Generic code
+ * #ifdef _WIN32
+ * Windows code
+ * #else
+ * Posix code
+ * #endif
+ *
*/
+ // everything provides this, but only header is instance.h
+ void exitCleanly(ExitCode exitCode);
+
+namespace {
+
+ // this will be called in certain c++ error cases, for example if there are two active
+ // exceptions
+ void myTerminate() {
+ printStackTrace(severe().stream()
+ << "terminate() called, printing stack (if implemented for platform):\n");
+ ::_exit(EXIT_ABRUPT);
+ }
+
+ // this gets called when new fails to allocate memory
+ void myNewHandler() {
+ printStackTrace(severe().stream() << "out of memory, printing stack and exiting:\n");
+ ::_exit(EXIT_ABRUPT);
+ }
+
+ void abruptQuit(int signalNum) {
+ {
+ LogstreamBuilder logBuilder = severe();
+ logBuilder <<
+ "Got signal: " << signalNum << " (" << strsignal(signalNum) << ").\nBacktrace:";
+ printStackTrace(logBuilder.stream());
+ }
+
+ // Don't go through normal shutdown procedure. It may make things worse.
+ ::_exit(EXIT_ABRUPT);
+ }
+
+#ifdef _WIN32
+
+ void consoleTerminate( const char* controlCodeName ) {
+ Client::initThread( "consoleTerminate" );
+ log() << "got " << controlCodeName << ", will terminate after current cmd ends" << endl;
+ exitCleanly( EXIT_KILL );
+ }
+
+ BOOL WINAPI CtrlHandler( DWORD fdwCtrlType ) {
+
+ switch( fdwCtrlType ) {
+
+ case CTRL_C_EVENT:
+ log() << "Ctrl-C signal";
+ consoleTerminate( "CTRL_C_EVENT" );
+ return TRUE ;
+
+ case CTRL_CLOSE_EVENT:
+ log() << "CTRL_CLOSE_EVENT signal";
+ consoleTerminate( "CTRL_CLOSE_EVENT" );
+ return TRUE ;
+
+ case CTRL_BREAK_EVENT:
+ log() << "CTRL_BREAK_EVENT signal";
+ consoleTerminate( "CTRL_BREAK_EVENT" );
+ return TRUE;
+
+ case CTRL_LOGOFF_EVENT:
+ // only sent to services, and only in pre-Vista Windows; FALSE means ignore
+ return FALSE;
+
+ case CTRL_SHUTDOWN_EVENT:
+ log() << "CTRL_SHUTDOWN_EVENT signal";
+ consoleTerminate( "CTRL_SHUTDOWN_EVENT" );
+ return TRUE;
+
+ default:
+ return FALSE;
+ }
+ }
+
+ void eventProcessingThread() {
+ std::string eventName = getShutdownSignalName(ProcessId::getCurrent().asUInt32());
+
+ HANDLE event = CreateEventA(NULL, TRUE, FALSE, eventName.c_str());
+ if (event == NULL) {
+ warning() << "eventProcessingThread CreateEvent failed: "
+ << errnoWithDescription();
+ return;
+ }
+
+ ON_BLOCK_EXIT(CloseHandle, event);
+
+ int returnCode = WaitForSingleObject(event, INFINITE);
+ if (returnCode != WAIT_OBJECT_0) {
+ if (returnCode == WAIT_FAILED) {
+ warning() << "eventProcessingThread WaitForSingleObject failed: "
+ << errnoWithDescription();
+ return;
+ }
+ else {
+ warning() << "eventProcessingThread WaitForSingleObject failed: "
+ << errnoWithDescription(returnCode);
+ return;
+ }
+ }
+
+ Client::initThread("eventTerminate");
+ log() << "shutdown event signaled, will terminate after current cmd ends";
+ exitCleanly(EXIT_CLEAN);
+ }
+
+#else
+
+ void abruptQuitWithAddrSignal( int signalNum, siginfo_t *siginfo, void * ) {
+ {
+ LogstreamBuilder logBuilder = severe();
+
+ logBuilder << "Invalid";
+ if ( signalNum == SIGSEGV || signalNum == SIGBUS ) {
+ logBuilder << " access";
+ } else {
+ logBuilder << " operation";
+ }
+ logBuilder << " at address: " << siginfo->si_addr;
+ }
+ abruptQuit( signalNum );
+ }
+
+ // The signals in asyncSignals will be processed by this thread only, in order to
+ // ensure the db and log mutexes aren't held.
+ sigset_t asyncSignals;
+ void signalProcessingThread() {
+ Client::initThread( "signalProcessingThread" );
+ while (true) {
+ int actualSignal = 0;
+ int status = sigwait( &asyncSignals, &actualSignal );
+ fassert(16781, status == 0);
+ switch (actualSignal) {
+ case SIGUSR1:
+ // log rotate signal
+ fassert(16782, rotateLogs());
+ logProcessDetailsForLogRotate();
+ break;
+ case SIGQUIT:
+ log() << "Received SIGQUIT; terminating.";
+ _exit(EXIT_ABRUPT);
+ default:
+ // interrupt/terminate signal
+ log() << "got signal " << actualSignal << " (" << strsignal( actualSignal )
+ << "), will terminate after current cmd ends" << endl;
+ exitCleanly( EXIT_CLEAN );
+ break;
+ }
+ }
+ }
+#endif
+} // namespace
+
+ void setupSignalHandlers() {
+ set_terminate( myTerminate );
+ set_new_handler( myNewHandler );
+
+ // SIGABRT is the only signal we want handled by signal handlers on both windows and posix.
+ invariant( signal(SIGABRT, abruptQuit) != SIG_ERR );
+
+#ifdef _WIN32
+ _set_purecall_handler( ::abort ); // TODO improve?
+ setWindowsUnhandledExceptionFilter();
+ massert(10297,
+ "Couldn't register Windows Ctrl-C handler",
+ SetConsoleCtrlHandler(static_cast<PHANDLER_ROUTINE>(CtrlHandler), TRUE));
+
+#else
+ invariant( signal(SIGHUP , SIG_IGN ) != SIG_ERR );
+ invariant( signal(SIGUSR2, SIG_IGN ) != SIG_ERR );
+ invariant( signal(SIGPIPE, SIG_IGN) != SIG_ERR );
+
+ struct sigaction addrSignals;
+ memset( &addrSignals, 0, sizeof( struct sigaction ) );
+ addrSignals.sa_sigaction = abruptQuitWithAddrSignal;
+ sigemptyset( &addrSignals.sa_mask );
+ addrSignals.sa_flags = SA_SIGINFO;
+
+ invariant( sigaction(SIGSEGV, &addrSignals, 0) == 0 );
+ invariant( sigaction(SIGBUS, &addrSignals, 0) == 0 );
+ invariant( sigaction(SIGILL, &addrSignals, 0) == 0 );
+ invariant( sigaction(SIGFPE, &addrSignals, 0) == 0 );
+
+
+ setupSIGTRAPforGDB();
+
+ // asyncSignals is a global variable listing the signals that should be handled by the
+ // interrupt thread, once it is started via startSignalProcessingThread().
+ sigemptyset( &asyncSignals );
+ sigaddset( &asyncSignals, SIGHUP );
+ sigaddset( &asyncSignals, SIGINT );
+ sigaddset( &asyncSignals, SIGTERM );
+ sigaddset( &asyncSignals, SIGQUIT );
+ sigaddset( &asyncSignals, SIGUSR1 );
+ sigaddset( &asyncSignals, SIGXCPU );
+#endif
+ }
+
+ void startSignalProcessingThread() {
+#ifdef _WIN32
+ boost::thread(eventProcessingThread).detach();
+#else
+ // Mask signals in the current (only) thread. All new threads will inherit this mask.
+ invariant( pthread_sigmask( SIG_SETMASK, &asyncSignals, 0 ) == 0 );
+ // Spawn a thread to capture the signals we just masked off.
+ boost::thread( signalProcessingThread ).detach();
+#endif
+ }
+
} // namespace mongo
diff --git a/src/mongo/util/signal_handlers.h b/src/mongo/util/signal_handlers.h
index 01f59728868..1813019930f 100644
--- a/src/mongo/util/signal_handlers.h
+++ b/src/mongo/util/signal_handlers.h
@@ -32,4 +32,19 @@
namespace mongo {
+ /**
+ * Sets up handlers for signals and other events like terminate and new_handler.
+ *
+ * This must be called very early in main, before runGlobalInitializers().
+ */
+ void setupSignalHandlers();
+
+ /**
+ * Starts the thread to handle asynchronous signals.
+ *
+ * This must be the first thread started from the main thread. Call this immediately after
+ * initializeServerGlobalState().
+ */
+ void startSignalProcessingThread();
+
} // namespace mongo