diff options
author | Malcolm Beattie <mbeattie@sable.ox.ac.uk> | 1998-03-18 11:03:11 +0000 |
---|---|---|
committer | Malcolm Beattie <mbeattie@sable.ox.ac.uk> | 1998-03-18 11:03:11 +0000 |
commit | 3aeed370afcacdc526e9f8575b34e519df1ffe51 (patch) | |
tree | 5864e71f855b4dc0b422c4e4a2806bef9bc6edf5 /ext/Thread | |
parent | 63c303421ae8994f77ab63c42697d3066f2fd98a (diff) | |
download | perl-3aeed370afcacdc526e9f8575b34e519df1ffe51.tar.gz |
Add Thread::Signal to run signal handlers reliably in a new thread
p4raw-id: //depot/perl@835
Diffstat (limited to 'ext/Thread')
-rw-r--r-- | ext/Thread/Thread.xs | 29 | ||||
-rw-r--r-- | ext/Thread/Thread/Signal.pm | 50 |
2 files changed, 68 insertions, 11 deletions
diff --git a/ext/Thread/Thread.xs b/ext/Thread/Thread.xs index aea72f4a46..b867fec72b 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 0000000000..f5f03db8a8 --- /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<Thread::Signal> 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<die> 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; |