I've got a moderately complex program which I'm switching to an event-loop
architecture, using the Event module.  I'm doing something slightly
naughty with signal handlers, and I'd like advice on how best to do it
with Event.

Before I started using Event, I had a couple of signal handlers that,
as part of their work, locally modified the handling of their signal.
The interesting case is with SIGTSTP: after doing some application
cleanup, it would temporarily reset SIGTSTP to default handling and
unblock it and then deliver itself a SIGTSTP.  The point of this is
that the behaviour looks, from the user's point of view, just like an
ordinary ^Z suspension, but the application cleanup gets done along
the way.  After the program is restarted, the signal handler restores
the catching of SIGTSTP and does more bookkeeping before returning.

With Event, I'd like the signal handler to operate synchronously as part
of the event loop.  (The issue of the signal handler possibly being
called at an inopportune moment is one of the reasons for moving to
an event-loop architecture.)  If I do it in the obvious way, replacing
"$SIG{TSTP} =" with "Event->signal signal =>", then my signal handler
gets called fine, but it fails to restore proper signal handling after
temporarily switching it to default handling.

I realise that in that I'm breaking one of the documented rules: "A given
signal can be handled by %SIG or Event, but not both.".  I understand
why it doesn't work: %SIG doesn't reflect the actual signal handler, so
my "local $SIG{TSTP}" ends up `restoring' undef to $SIG{TSTP} instead
of restoring the actual SIGTSTP handler.  I want to make it work, in
some form.

I see four main possible ways for me to achieve the effect I want:

0. Have my own stub signal handler in %SIG, instead of Event handling it.
   The stub signal handler would do nothing more than trigger an event,
   the callback for which is the real signal handler that mucks about
   with %SIG.  Result: I get synchronous signal handling, while still
   retaining control over %SIG.  This is inelegant; I'd rather have
   Event handle the signal directly when I don't need to usurp it.

1. Rewrite my invoke-default-handler function in C, so that it can save
   and restore the real struct sigaction rather than being limited to
   what is visible in %SIG.  This is cleaner, but means I'd lose some
   portability.  The invoke-default-handler function is actually of wider
   utility than just this program, so I might implement this anyway so
   that it can cope with other situations where %SIG isn't the whole
   story, but I'm concerned about the portability loss for this program.

2. Arrange for Event to be able to cede and retake control of signal
   handlers.  It's a simple enough thing to negotiate.  At minimum, Event
   would need to provide just two new functions: "do you [Event] currently
   handle signal FOO?" and "rehook signal FOO".  This would allow for
   a much wider range of cases where it is desired to temporarily take
   over control of a signal from Event.

3. Arrange for %SIG to show *something* for a non-Perl signal handler,
   so that such handlers can be manipulated by Perl code in the expected
   manner.  (This would actually make my non-working code work without
   modification.)  I'm not sure whether it could be done safely in the
   general case -- one has to ensure that the non-Perl signal handler
   can actually be safely used when Perl code tries to install it via
   %SIG.  Even if it's not possible in general, it might be possible
   for cooperating code to do it, so Event could use that mechanism to
   achieve option 2 with the means of negotiation being %SIG.

Being an engineer, I'm leaning towards attempting 1, 2, and 3
simultaneously.  Each of them would be useful even with the others
being available, and of course TMTOWTDI.  Not knowing Event's internals,
though, I'd like commentary from the list.

-zefram

Reply via email to