static void sigsegv_handler(int code, siginfo_t *siginfo, void *context);
static void sigtrap_handler(int code, siginfo_t *siginfo, void *context);
static void sigbus_handler(int code, siginfo_t *siginfo, void *context);
+static void sigint_handler(int code, siginfo_t *siginfo, void *context);
+static void sigquit_handler(int code, siginfo_t *siginfo, void *context);
#if USE_SIGNALS_FOR_THREAD_SUSPENSION
void CorUnix::suspend_handler(int code, siginfo_t *siginfo, void *context);
void CorUnix::resume_handler(int code, siginfo_t *siginfo, void *context);
struct sigaction g_previous_sigfpe;
struct sigaction g_previous_sigbus;
struct sigaction g_previous_sigsegv;
+struct sigaction g_previous_sigint;
+struct sigaction g_previous_sigquit;
#if USE_SIGNALS_FOR_THREAD_SUSPENSION
struct sigaction g_previous_sigusr1;
struct sigaction g_previous_sigusr2;
#endif // USE_SIGNALS_FOR_THREAD_SUSPENSION
+// Pipe used for sending SIGINT / SIGQUIT signals notifications to a helper thread
+// that invokes the actual handler.
+int g_signalPipe[2];
+
/* public function definitions ************************************************/
/*++
Parameters :
None
- (no return value)
+Return :
+ TRUE in case of a success, FALSE otherwise
--*/
-void SEHInitializeSignals()
+BOOL SEHInitializeSignals()
{
TRACE("Initializing signal handlers\n");
handle_signal(SIGFPE, sigfpe_handler, &g_previous_sigfpe);
handle_signal(SIGBUS, sigbus_handler, &g_previous_sigbus);
handle_signal(SIGSEGV, sigsegv_handler, &g_previous_sigsegv);
+ handle_signal(SIGINT, sigint_handler, &g_previous_sigint);
+ handle_signal(SIGQUIT, sigquit_handler, &g_previous_sigquit);
#if USE_SIGNALS_FOR_THREAD_SUSPENSION
handle_signal(SIGUSR1, suspend_handler, &g_previous_sigusr1);
handle_signal(SIGUSR2, resume_handler, &g_previous_sigusr2);
issued a SIGPIPE will, instead, report an error and set errno to EPIPE.
*/
signal(SIGPIPE, SIG_IGN);
+
+ int status = pipe(g_signalPipe);
+
+ return (status == 0);
}
/*++
restore_signal(SIGFPE, &g_previous_sigfpe);
restore_signal(SIGBUS, &g_previous_sigbus);
restore_signal(SIGSEGV, &g_previous_sigsegv);
+ restore_signal(SIGINT, &g_previous_sigint);
+ restore_signal(SIGQUIT, &g_previous_sigquit);
}
/* internal function definitions **********************************************/
/*++
Function :
+ HandleExternalSignal
+
+ Handle the SIGINT and SIGQUIT signals.
+
+
+Parameters :
+ signalCode - code of the external signal
+
+ (no return value)
+--*/
+static void HandleExternalSignal(int signalCode)
+{
+ BYTE signalCodeByte = (BYTE)signalCode;
+ ssize_t writtenBytes;
+ do
+ {
+ writtenBytes = write(g_signalPipe[1], &signalCodeByte, 1);
+ }
+ while ((writtenBytes == -1) && (errno == EINTR));
+
+ if (writtenBytes == -1)
+ {
+ // Fatal error
+ abort();
+ }
+}
+
+/*++
+Function :
+ sigint_handler
+
+ handle SIGINT signal
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigint_handler(int code, siginfo_t *siginfo, void *context)
+{
+ if (PALIsInitialized())
+ {
+ HandleExternalSignal(code);
+ }
+ else
+ {
+ TRACE("SIGINT signal was unhandled; chaining to previous sigaction\n");
+
+ if (g_previous_sigint.sa_sigaction != NULL)
+ {
+ g_previous_sigint.sa_sigaction(code, siginfo, context);
+ }
+ }
+}
+
+/*++
+Function :
+ sigquit_handler
+
+ handle SIGQUIT signal
+
+Parameters :
+ POSIX signal handler parameter list ("man sigaction" for details)
+
+ (no return value)
+--*/
+static void sigquit_handler(int code, siginfo_t *siginfo, void *context)
+{
+ if (PALIsInitialized())
+ {
+ HandleExternalSignal(code);
+ }
+ else
+ {
+ TRACE("SIGQUIT signal was unhandled; chaining to previous sigaction\n");
+
+ if (g_previous_sigquit.sa_sigaction != NULL)
+ {
+ g_previous_sigquit.sa_sigaction(code, siginfo, context);
+ }
+ }
+}
+
+/*++
+Function :
sigbus_handler
handle SIGBUS signal (EXCEPTION_ACCESS_VIOLATION?)
return palError;
}
-static const int c_iShutdownWaitTime = 5;
-
static
DWORD
PALAPI
DWORD dwThreadId;
bool fContinue = TRUE;
HANDLE hThread;
- int iError;
- int iSignal;
PAL_ERROR palError = NO_ERROR;
CPalThread *pthr = InternalGetCurrentThread();
- sigset_t sigsetAll;
- sigset_t sigsetWait;
-
- //
- // Setup our signal masks
- //
-
- //
- // SIGPROF is not masked by this thread, and thus not waited for
- // in sigwait since SIGPROF is used by the BSD thread scheduler.
- // Masking SIGPROF in this thread leads to a significant
- // reduction in performance.
- //
-
- (void)sigfillset(&sigsetAll);
- (void)sigdelset(&sigsetAll, SIGPROF);
-
- (void)sigemptyset(&sigsetWait);
- (void)sigaddset(&sigsetWait, SIGINT);
- (void)sigaddset(&sigsetWait, SIGQUIT);
-
- //
- // Mask off all signals for this thread
- //
-
- iError = pthread_sigmask(SIG_SETMASK, &sigsetAll, NULL);
- if (0 != iError)
- {
- ASSERT("pthread sigmask(sigsetAll) failed\n");
- fContinue = FALSE;
- }
//
// Wait for a signal to occur
while (fContinue)
{
- iError = sigwait(&sigsetWait, &iSignal);
- if (0 != iError)
+ BYTE signalCode;
+ ssize_t bytesRead;
+
+ do
{
- ASSERT("sigwait(sigsetWait, iSignal) failed\n");
- fContinue = FALSE;
- break;
+ bytesRead = read(g_signalPipe[0], &signalCode, 1);
}
+ while ((bytesRead == -1) && (errno == EINTR));
- //
- // If the PAL is shutting down we want to exit after waiting
- // a few seconds (in the hopes that the normal shutdown
- // finishes...)
- //
-
- if (PALIsShuttingDown())
+ if (bytesRead == -1)
{
- sleep(c_iShutdownWaitTime);
- fContinue = FALSE;
- break;
+ // Fatal error
+ abort();
}
- switch (iSignal)
+ switch (signalCode)
{
case SIGINT:
case SIGQUIT:
//
PVOID pvCtrlCode = UintToPtr(
- SIGINT == iSignal ? CTRL_C_EVENT : CTRL_BREAK_EVENT
+ SIGINT == signalCode ? CTRL_C_EVENT : CTRL_BREAK_EVENT
);
palError = InternalCreateThread(
if (NO_ERROR != palError)
{
+ if (!PALIsShuttingDown())
+ {
+ // If PAL is not shutting down, failure to create a thread is
+ // a fatal error.
+ abort();
+ }
fContinue = FALSE;
break;
}
}
default:
- ASSERT("Unexpect signal %d in signal thread\n", iSignal);
- fContinue = FALSE;
+ ASSERT("Unexpected signal %d in signal thread\n", signalCode);
+ abort();
break;
}
}