Changeset a7fac14


Ignore:
Timestamp:
Jul 23, 2011, 7:30:51 PM (6 years ago)
Author:
David Benjamin <davidben@mit.edu>
Branches:
master, release-1.9
Children:
4ebbfbc, 85bb19b, d933c3ca
Parents:
f661cee
git-author:
David Benjamin <davidben@mit.edu> (07/20/11 02:03:42)
git-committer:
David Benjamin <davidben@mit.edu> (07/23/11 19:30:51)
Message:
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>
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • owl.c

    rb8a3e00 ra7fac14  
    389389}
    390390
    391 #define CHECK_RESULT(s, syscall) \
     391#define OR_DIE(s, syscall)      \
    392392  G_STMT_START {                 \
    393     if ((syscall) != 0) {        \
     393    if ((syscall) == -1) {       \
    394394      perror((s));               \
    395395      exit(1);                   \
     
    402402  sigset_t sigset;
    403403  int ret, i;
    404   const int signals[] = { SIGABRT, SIGBUS, SIGCHLD, SIGFPE, SIGHUP, SIGILL,
    405                           SIGINT, SIGQUIT, SIGSEGV, SIGTERM, SIGWINCH };
     404  const int reset_signals[] = { SIGABRT, SIGBUS, SIGCHLD, SIGFPE, SIGILL,
     405                                SIGQUIT, SIGSEGV, };
     406  /* Don't bother resetting watched ones because owl_signal_init will. */
     407  const int watch_signals[] = { SIGWINCH, SIGTERM, SIGHUP, SIGINT, };
    406408
    407409  /* Sanitize our signals; the mask and dispositions from our parent
    408410   * aren't really useful. Signal list taken from equivalent code in
    409411   * Chromium. */
    410   CHECK_RESULT("sigemptyset", sigemptyset(&sigset));
     412  OR_DIE("sigemptyset", sigemptyset(&sigset));
    411413  if ((ret = pthread_sigmask(SIG_SETMASK, &sigset, NULL)) != 0) {
    412414    errno = ret;
    413415    perror("pthread_sigmask");
    414   }
    415   for (i = 0; i < G_N_ELEMENTS(signals); i++) {
    416     CHECK_RESULT("sigaction", sigaction(signals[i], &sig_default, NULL));
     416    exit(1);
     417  }
     418  for (i = 0; i < G_N_ELEMENTS(reset_signals); i++) {
     419    OR_DIE("sigaction", sigaction(reset_signals[i], &sig_default, NULL));
    417420  }
    418421
    419422  /* Turn off SIGPIPE; we check the return value of write. */
    420   CHECK_RESULT("sigaction", sigaction(SIGPIPE, &sig_ignore, NULL));
     423  OR_DIE("sigaction", sigaction(SIGPIPE, &sig_ignore, NULL));
    421424
    422425  /* Register some signals with the signal thread. */
    423   CHECK_RESULT("sigaddset", sigaddset(&sigset, SIGWINCH));
    424   CHECK_RESULT("sigaddset", sigaddset(&sigset, SIGTERM));
    425   CHECK_RESULT("sigaddset", sigaddset(&sigset, SIGHUP));
    426   CHECK_RESULT("sigaddset", sigaddset(&sigset, SIGINT));
    427   owl_signal_init(&sigset, sig_handler, NULL);
     426  owl_signal_init(watch_signals, G_N_ELEMENTS(watch_signals),
     427                  sig_handler, NULL);
    428428}
    429429
  • signal.c

    r1d21d9f ra7fac14  
    11#include <errno.h>
     2#include <glib.h>
    23#include <pthread.h>
    34#include <signal.h>
     
    1314static void *signal_thread_func(void *data);
    1415
    15 /* Initializes the signal thread to listen for 'set' on a dedicated
     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
    1631 * thread. 'callback' is called *on the signal thread* when a signal
    1732 * is received.
     
    1934 * This function /must/ be called before any other threads are
    2035 * created. (Otherwise the signals will not get blocked correctly.) */
    21 void owl_signal_init(const sigset_t *set, void (*callback)(const siginfo_t*, void*), void *data) {
     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 };
    2238  int ret;
     39  int i;
    2340
    24   signal_set = *set;
    2541  signal_cb = callback;
    2642  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
    2754  /* Block these signals in all threads, so we can get them. */
    28   if ((ret = pthread_sigmask(SIG_BLOCK, set, NULL)) != 0) {
     55  if ((ret = pthread_sigmask(SIG_BLOCK, &signal_set, NULL)) != 0) {
    2956    errno = ret;
    3057    perror("pthread_sigmask");
     58    exit(1);
    3159  }
    3260  /* Spawn a dedicated thread to sigwait. */
Note: See TracChangeset for help on using the changeset viewer.