318 lines
5.6 KiB
C
318 lines
5.6 KiB
C
/* go-signal.c -- signal handling for Go.
|
|
|
|
Copyright 2009 The Go Authors. All rights reserved.
|
|
Use of this source code is governed by a BSD-style
|
|
license that can be found in the LICENSE file. */
|
|
|
|
#include <signal.h>
|
|
#include <stdlib.h>
|
|
#include <unistd.h>
|
|
#include <sys/time.h>
|
|
|
|
#include "runtime.h"
|
|
#include "go-assert.h"
|
|
#include "go-panic.h"
|
|
|
|
#ifndef SA_RESTART
|
|
#define SA_RESTART 0
|
|
#endif
|
|
|
|
/* What to do for a signal. */
|
|
|
|
struct sigtab
|
|
{
|
|
/* Signal number. */
|
|
int sig;
|
|
/* Nonzero if the signal should be caught. */
|
|
_Bool catch;
|
|
/* Nonzero if the signal should be queued. */
|
|
_Bool queue;
|
|
/* Nonzero if the signal should be ignored. */
|
|
_Bool ignore;
|
|
/* Nonzero if we should restart system calls. */
|
|
_Bool restart;
|
|
};
|
|
|
|
/* What to do for signals. */
|
|
|
|
static struct sigtab signals[] =
|
|
{
|
|
{ SIGHUP, 0, 1, 0, 1 },
|
|
{ SIGINT, 0, 1, 0, 1 },
|
|
{ SIGQUIT, 0, 1, 0, 1 },
|
|
{ SIGALRM, 0, 1, 1, 1 },
|
|
{ SIGTERM, 0, 1, 0, 1 },
|
|
#ifdef SIGILL
|
|
{ SIGILL, 1, 0, 0, 0 },
|
|
#endif
|
|
#ifdef SIGTRAP
|
|
{ SIGTRAP, 1, 0, 0, 0 },
|
|
#endif
|
|
#ifdef SIGABRT
|
|
{ SIGABRT, 1, 0, 0, 0 },
|
|
#endif
|
|
#ifdef SIGBUS
|
|
{ SIGBUS, 1, 0, 0, 0 },
|
|
#endif
|
|
#ifdef SIGFPE
|
|
{ SIGFPE, 1, 0, 0, 0 },
|
|
#endif
|
|
#ifdef SIGUSR1
|
|
{ SIGUSR1, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGSEGV
|
|
{ SIGSEGV, 1, 0, 0, 0 },
|
|
#endif
|
|
#ifdef SIGUSR2
|
|
{ SIGUSR2, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGPIPE
|
|
{ SIGPIPE, 0, 0, 1, 0 },
|
|
#endif
|
|
#ifdef SIGSTKFLT
|
|
{ SIGSTKFLT, 1, 0, 0, 0 },
|
|
#endif
|
|
#ifdef SIGCHLD
|
|
{ SIGCHLD, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGTSTP
|
|
{ SIGTSTP, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGTTIN
|
|
{ SIGTTIN, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGTTOU
|
|
{ SIGTTOU, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGURG
|
|
{ SIGURG, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGXCPU
|
|
{ SIGXCPU, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGXFSZ
|
|
{ SIGXFSZ, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGVTARLM
|
|
{ SIGVTALRM, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGPROF
|
|
{ SIGPROF, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGWINCH
|
|
{ SIGWINCH, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGIO
|
|
{ SIGIO, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGPWR
|
|
{ SIGPWR, 0, 1, 1, 1 },
|
|
#endif
|
|
#ifdef SIGSYS
|
|
{ SIGSYS, 1, 0, 0, 0 },
|
|
#endif
|
|
{ -1, 0, 0, 0, 0 }
|
|
};
|
|
|
|
/* The Go signal handler. */
|
|
|
|
static void
|
|
sighandler (int sig)
|
|
{
|
|
const char *msg;
|
|
int i;
|
|
|
|
if (sig == SIGPROF)
|
|
{
|
|
/* FIXME. */
|
|
runtime_sigprof (0, 0, nil, nil);
|
|
return;
|
|
}
|
|
|
|
/* FIXME: Should check siginfo for more information when
|
|
available. */
|
|
msg = NULL;
|
|
switch (sig)
|
|
{
|
|
#ifdef SIGILL
|
|
case SIGILL:
|
|
msg = "illegal instruction";
|
|
break;
|
|
#endif
|
|
|
|
#ifdef SIGBUS
|
|
case SIGBUS:
|
|
msg = "invalid memory address or nil pointer dereference";
|
|
break;
|
|
#endif
|
|
|
|
#ifdef SIGFPE
|
|
case SIGFPE:
|
|
msg = "integer divide by zero or floating point error";
|
|
break;
|
|
#endif
|
|
|
|
#ifdef SIGSEGV
|
|
case SIGSEGV:
|
|
msg = "invalid memory address or nil pointer dereference";
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (msg != NULL)
|
|
{
|
|
sigset_t clear;
|
|
|
|
if (runtime_m()->mallocing)
|
|
{
|
|
fprintf (stderr, "caught signal while mallocing: %s\n", msg);
|
|
__go_assert (0);
|
|
}
|
|
|
|
/* The signal handler blocked signals; unblock them. */
|
|
i = sigfillset (&clear);
|
|
__go_assert (i == 0);
|
|
i = sigprocmask (SIG_UNBLOCK, &clear, NULL);
|
|
__go_assert (i == 0);
|
|
|
|
runtime_panicstring (msg);
|
|
}
|
|
|
|
for (i = 0; signals[i].sig != -1; ++i)
|
|
{
|
|
if (signals[i].sig == sig)
|
|
{
|
|
struct sigaction sa;
|
|
|
|
if (signals[i].queue)
|
|
{
|
|
if (__go_sigsend (sig) || signals[i].ignore)
|
|
return;
|
|
runtime_exit (2); // SIGINT, SIGTERM, etc
|
|
}
|
|
|
|
if (runtime_panicking)
|
|
runtime_exit (2);
|
|
runtime_panicking = 1;
|
|
|
|
memset (&sa, 0, sizeof sa);
|
|
|
|
sa.sa_handler = SIG_DFL;
|
|
|
|
i = sigemptyset (&sa.sa_mask);
|
|
__go_assert (i == 0);
|
|
|
|
if (sigaction (sig, &sa, NULL) != 0)
|
|
abort ();
|
|
|
|
raise (sig);
|
|
exit (2);
|
|
}
|
|
}
|
|
abort ();
|
|
}
|
|
|
|
/* Ignore a signal. */
|
|
|
|
static void
|
|
sig_ignore (int sig __attribute__ ((unused)))
|
|
{
|
|
}
|
|
|
|
/* Initialize signal handling for Go. This is called when the program
|
|
starts. */
|
|
|
|
void
|
|
runtime_initsig (int32 queue)
|
|
{
|
|
struct sigaction sa;
|
|
int i;
|
|
|
|
siginit ();
|
|
|
|
memset (&sa, 0, sizeof sa);
|
|
|
|
sa.sa_handler = sighandler;
|
|
|
|
i = sigfillset (&sa.sa_mask);
|
|
__go_assert (i == 0);
|
|
|
|
for (i = 0; signals[i].sig != -1; ++i)
|
|
{
|
|
if (signals[i].queue != (queue ? 1 : 0))
|
|
continue;
|
|
if (signals[i].catch || signals[i].queue)
|
|
sa.sa_handler = sighandler;
|
|
else
|
|
sa.sa_handler = sig_ignore;
|
|
sa.sa_flags = signals[i].restart ? SA_RESTART : 0;
|
|
if (sigaction (signals[i].sig, &sa, NULL) != 0)
|
|
__go_assert (0);
|
|
}
|
|
}
|
|
|
|
void
|
|
runtime_resetcpuprofiler(int32 hz)
|
|
{
|
|
struct itimerval it;
|
|
struct sigaction sa;
|
|
int i;
|
|
|
|
memset (&it, 0, sizeof it);
|
|
|
|
memset (&sa, 0, sizeof sa);
|
|
i = sigfillset (&sa.sa_mask);
|
|
__go_assert (i == 0);
|
|
|
|
if (hz == 0)
|
|
{
|
|
i = setitimer (ITIMER_PROF, &it, NULL);
|
|
__go_assert (i == 0);
|
|
|
|
sa.sa_handler = SIG_IGN;
|
|
i = sigaction (SIGPROF, &sa, NULL);
|
|
__go_assert (i == 0);
|
|
}
|
|
else
|
|
{
|
|
sa.sa_handler = sighandler;
|
|
sa.sa_flags = SA_RESTART;
|
|
i = sigaction (SIGPROF, &sa, NULL);
|
|
__go_assert (i == 0);
|
|
|
|
it.it_interval.tv_sec = 0;
|
|
it.it_interval.tv_usec = 1000000 / hz;
|
|
it.it_value = it.it_interval;
|
|
i = setitimer (ITIMER_PROF, &it, NULL);
|
|
__go_assert (i == 0);
|
|
}
|
|
|
|
runtime_m()->profilehz = hz;
|
|
}
|
|
|
|
/* Used by the os package to raise SIGPIPE. */
|
|
|
|
void os_sigpipe (void) __asm__ ("libgo_os.os.sigpipe");
|
|
|
|
void
|
|
os_sigpipe (void)
|
|
{
|
|
struct sigaction sa;
|
|
int i;
|
|
|
|
memset (&sa, 0, sizeof sa);
|
|
|
|
sa.sa_handler = SIG_DFL;
|
|
|
|
i = sigemptyset (&sa.sa_mask);
|
|
__go_assert (i == 0);
|
|
|
|
if (sigaction (SIGPIPE, &sa, NULL) != 0)
|
|
abort ();
|
|
|
|
raise (SIGPIPE);
|
|
}
|