From: Malcolm Beattie Date: Wed, 18 Mar 1998 11:03:11 +0000 (+0000) Subject: Add Thread::Signal to run signal handlers reliably in a new thread X-Git-Url: http://git.shadowcat.co.uk/gitweb/gitweb.cgi?a=commitdiff_plain;h=3aeed370afcacdc526e9f8575b34e519df1ffe51;p=p5sagit%2Fp5-mst-13.2.git Add Thread::Signal to run signal handlers reliably in a new thread p4raw-id: //depot/perl@835 --- diff --git a/MANIFEST b/MANIFEST index 004e350..92f4001 100644 --- a/MANIFEST +++ b/MANIFEST @@ -267,6 +267,7 @@ ext/Thread/Thread.pm Thread extension Perl module ext/Thread/Thread.xs Thread extension external subroutines ext/Thread/Thread/Queue.pm Thread synchronised queue objects ext/Thread/Thread/Semaphore.pm Thread semaphore objects +ext/Thread/Thread/Signal.pm Start a thread to run signal handlers ext/Thread/Thread/Specific.pm Thread specific data access ext/Thread/create.t Test thread creation ext/Thread/die.t Test thread die() diff --git a/ext/Thread/Thread.xs b/ext/Thread/Thread.xs index aea72f4..b867fec 100644 --- a/ext/Thread/Thread.xs +++ b/ext/Thread/Thread.xs @@ -280,8 +280,15 @@ static Signal_t handle_thread_signal _((int sig)); static Signal_t handle_thread_signal(int sig) { - char c = (char) sig; - write(sig_pipe[0], &c, 1); + unsigned char c = (unsigned char) sig; + /* + * We're not really allowed to call fprintf in a signal handler + * so don't be surprised if this isn't robust while debugging + * with -DL. + */ + DEBUG_L(PerlIO_printf(PerlIO_stderr(), + "handle_thread_signal: got signal %d\n", sig);); + write(sig_pipe[1], &c, 1); } MODULE = Thread PACKAGE = Thread @@ -555,7 +562,7 @@ MODULE = Thread PACKAGE = Thread::Signal void kill_sighandler_thread() PPCODE: - write(sig_pipe[0], "\0", 1); + write(sig_pipe[1], "\0", 1); PUSHs(&sv_yes); void @@ -566,22 +573,22 @@ init_thread_signals() XSRETURN_UNDEF; PUSHs(&sv_yes); -SV * +void await_signal() PREINIT: - char c; + unsigned char c; SSize_t ret; CODE: do { - ret = read(sig_pipe[1], &c, 1); + ret = read(sig_pipe[0], &c, 1); } while (ret == -1 && errno == EINTR); if (ret == -1) croak("panic: await_signal"); - if (ret == 0) - XSRETURN_UNDEF; - RETVAL = c ? psig_ptr[c] : &sv_no; - OUTPUT: - RETVAL + ST(0) = sv_newmortal(); + if (ret) + sv_setsv(ST(0), c ? psig_ptr[c] : &sv_no); + DEBUG_L(PerlIO_printf(PerlIO_stderr(), + "await_signal returning %s\n", SvPEEK(ST(0)));); MODULE = Thread PACKAGE = Thread::Specific diff --git a/ext/Thread/Thread/Signal.pm b/ext/Thread/Thread/Signal.pm new file mode 100644 index 0000000..f5f03db --- /dev/null +++ b/ext/Thread/Thread/Signal.pm @@ -0,0 +1,50 @@ +package Thread::Signal; +use Thread qw(async); + +=head1 NAME + +Thread::Signal - Start a thread which runs signal handlers reliably + +=head1 SYNOPSIS + + use Thread::Signal; + + $SIG{HUP} = \&some_handler; + +=head1 DESCRIPTION + +The C module starts up a special signal handler thread. +All signals to the process are delivered to it and it runs the +associated C<$SIG{FOO}> handlers for them. Without this module, +signals arriving at inopportune moments (such as when perl's internals +are in the middle of updating critical structures) cause the perl +code of the handler to be run unsafely which can cause memory corruption +or worse. + +=head1 BUGS + +This module changes the semantics of signal handling slightly in that +the signal handler is run separately from the main thread (and in +parallel with it). This means that tricks such as calling C from +a signal handler behave differently (and, in particular, can't be +used to exit directly from a system call). + +=cut + +if (!init_thread_signals()) { + require Carp; + Carp::croak("init_thread_signals failed: $!"); +} + +async { + my $sig; + while ($sig = await_signal()) { + &$sig(); + } +}; + +END { + kill_sighandler_thread(); +} + +1;