[Author Prev][Author Next][Thread Prev][Thread Next][Author Index][Thread Index]

signal handling and posix threads



hi guys, someone mentioned a problem with SIGPIPE causing aborts with
posix threads.[0]  typically this is handled a few ways:

- with a dedicated signal handling thread (linux messes this up when
threads get distinct process ids [1]) that sigwait's for events.  all
other threads block signals.

- masking and trapping/checking signals within each thread; usually
more complicated than it's worth and may lead to odd behavior with
sigaction.

i'm not familiar enough with the internals of Tor to know the
trade-off's involved in such a decision.  the process based signal
handling in do_main_loop/handle_signals would work fine in a dedicated
sighandler thread, but somehow this would need to be distinguished
from the others and yet utilize the same event loop.  (perhaps
something as simple as a new thread doing nothing but sigwait/sleeping
without signals masked, but it would have to dispatch long sig
handlers to a worker lest processing block any new incoming signals)

there are some libevent considerations as well, particularly
evsignal_*, although i'm also not very familiar with how libevent
handles signals in a threaded context.

in any case, the naive and untested approach is to simply mask signals
in worker threads, like:

---cut---
diff -Naur orig/src/common/compat.c mod/src/common/compat.c
--- orig/src/common/compat.c	2007-02-03 02:42:43.000000000 +0000
+++ mod/src/common/compat.c	2007-02-20 01:16:05.648185312 +0000
@@ -81,6 +81,7 @@
#include <assert.h>
 #ifdef HAVE_PTHREAD_H
 #include <pthread.h>
+#include <signal.h>
 #endif
 #ifdef HAVE_UTIME_H
#include <utime.h>
@@ -978,6 +979,11 @@
  tor_pthread_data_t *data = _data;
  void (*func)(void*);
  void *arg;
+  /* mask signals to worker threads to avoid SIGPIPE, etc */
+  sigset_t  sigs;
+  const int how = SIG_SETMASK;
+  sigfillset (&sigs);
+  pthread_sigmask (how, &sigs, 0);
  func = data->func;
  arg = data->data;
  tor_free(_data);
---end-cut---

however, at least one thread would need to be the sole handler for
incoming signals via unmasked state or sigwait.

has this been discussed before in the context of the Tor event loop
when using pthread?  is anyone more familiar with libevent aware of
the usual idioms for handling signals within worker pthreads?  (it
appears at first glance that most signal mgmt in libevent is at a
process level)

best regards,


0. from <frozen> in irc: Feb 19 23:00:07.602 [notice] Self-testing indicates your DirPort is reachable from the outside. Excellent. [New Thread 0x80f4200 (LWP 100068)] Program received signal SIGPIPE, Broken pipe. [Switching to Thread 0x80f4200 (LWP 100068)] 0x2827f5b7 in pthread_testcancel () from /lib/libpthread.so.2


1. pthread_signal(3) "Signal handling in LinuxThreads departs significantly from the POSIX standard. According to the standard, ''asynchronous'' (external) signals are addressed to the whole process (the collection of all threads), which then delivers them to one particular thread. The thread that actually receives the signal is any thread that does not currently block the signal.

In  LinuxThreads,  each thread is actually a kernel process with its
own PID, so external signals are always directed to one particular
thread.  If, for instance, another thread is blocked in sigwait on
that signal, it will not be restarted.

The LinuxThreads implementation of sigwait installs dummy signal
handlers for the signals in set for  the  duration  of  the wait.
Since signal handlers are shared between all threads, other threads
must not attach their own signal handlers to these signals, or
alternatively they should all block these signals (which is
recommended anyway -- see the Notes section."