source: signal.c

release-1.9
Last change on this file was a7fac14, checked in by David Benjamin <davidben@mit.edu>, 6 years ago
Assign all watched signals to a dummy no-op disposition Otherwise some (namely SIGWINCH) may have SIG_DFL = SIG_IGN. This means that the signal is ignored if the signal thread is in the middle of processing another signal (a race condition), and on Solaris it's not delivered at all. Also more consistently consider errors in setup here fatal. And rename CHECK_RESULT to OR_DIE. Reported-by: Benjamin Kaduk <kaduk@mit.edu> Reviewed-by: Adam Glasgall <adam@crossproduct.net>
  • Property mode set to 100644
File size: 2.5 KB
Line 
1#include <errno.h>
2#include <glib.h>
3#include <pthread.h>
4#include <signal.h>
5#include <stdio.h>
6#include <stdlib.h>
7
8static pthread_t signal_thread;
9static sigset_t signal_set;
10
11static void (*signal_cb)(const siginfo_t*, void*);
12static void *signal_cbdata;
13
14static void *signal_thread_func(void *data);
15
16static void dummy_handler(int signum)
17{
18  /* Do nothing. This should never get called. It'd be nice to report the error
19   * or something, but you can't have nice things in a signal handler. */
20}
21
22#define OR_DIE(s, syscall)       \
23  G_STMT_START {                 \
24    if ((syscall) == -1) {       \
25      perror((s));               \
26      exit(1);                   \
27    }                            \
28  } G_STMT_END
29
30/* Initializes the signal thread to listen for 'signals' on a dedicated
31 * thread. 'callback' is called *on the signal thread* when a signal
32 * is received.
33 *
34 * This function /must/ be called before any other threads are
35 * created. (Otherwise the signals will not get blocked correctly.) */
36void owl_signal_init(const int *signals, int num_signals, void (*callback)(const siginfo_t*, void*), void *data) {
37  struct sigaction sig_dummy = { .sa_handler = dummy_handler };
38  int ret;
39  int i;
40
41  signal_cb = callback;
42  signal_cbdata = data;
43
44  /* Stuff the signals into our sigset_t. Also assign all of them to a dummy
45   * handler. Otherwise, if their default is SIG_IGN, they will get dropped if
46   * delivered while processing. On Solaris, they will not get delivered at
47   * all. */
48  OR_DIE("sigemptyset", sigemptyset(&signal_set));
49  for (i = 0; i < num_signals; i++) {
50    OR_DIE("sigaddset", sigaddset(&signal_set, signals[i]));
51    OR_DIE("sigaction", sigaction(signals[i], &sig_dummy, NULL));
52  }
53
54  /* Block these signals in all threads, so we can get them. */
55  if ((ret = pthread_sigmask(SIG_BLOCK, &signal_set, NULL)) != 0) {
56    errno = ret;
57    perror("pthread_sigmask");
58    exit(1);
59  }
60  /* Spawn a dedicated thread to sigwait. */
61  if ((ret = pthread_create(&signal_thread, NULL,
62                            signal_thread_func, NULL)) != 0) {
63    errno = ret;
64    perror("pthread_create");
65    exit(1);
66  }
67}
68
69static void *signal_thread_func(void *data) {
70  while (1) {
71    siginfo_t siginfo;
72    int ret;
73
74    ret = sigwaitinfo(&signal_set, &siginfo);
75    /* TODO: Print an error? */
76    if (ret < 0)
77      continue;
78
79    signal_cb(&siginfo, signal_cbdata);
80    /* Die on SIGTERM. */
81    if (siginfo.si_signo == SIGTERM)
82      break;
83  }
84  return NULL;
85}
86
87void owl_signal_shutdown(void) {
88  pthread_kill(signal_thread, SIGTERM);
89  pthread_join(signal_thread, NULL);
90}
Note: See TracBrowser for help on using the repository browser.