Async signals and GMainLoop
- From: muppet <scott asofyet org>
- To: sameervk eudoramail com
- Cc: gtk-perl list <gtk-perl-list gnome org>
- Subject: Async signals and GMainLoop
- Date: Fri, 20 Feb 2004 01:00:36 -0500
back on-list, as this is good info for everyone and will probably
deserve to be in the FAQ. now that i've looked into the problem, i see
that this question has been asked a time or two before on the list, but
we couldn't reproduce it.
we have a long explanation, and three options at the end. everyone's
input is invited.
On Thursday, February 19, 2004, at 08:02 PM, Sameer VK wrote:
When I tried setting a signal handler in Perl:
$SIG{INT} = \&app_cleanup, the script did not respond, probably
because the handler in the perl-Glib library cannot be overridden?
well, there's no handler, so it's not that. if you stopped the
mainloop in your handler, that would explain why the gui stopped
responding. beyond that, i need more info. again, if you can't
divulge details publicly, just email me offlist, i'd be happy to help.
the perl script I tried is:
$SIG{INT} = sub{ warn "inside sighandler"; };
use Glib;
my $mainloop = Glib::MainLoop->new();
$mainloop->run;
async signal handlers can get called at any point in a program's
execution, and therefore there are *very* few things you can safely do
in them. basically, anything that calls malloc() is not safe, because
malloc() may already be in the middle of something when your signal
handler gets called --- so you typically do nothing beyond setting a
new value to an existing integer variable.
because these handlers are so limited, perl >= 5.7.3 introduced
deferred signal handlers. When you install something in %SIG, perl
actually installs a dummy handler that sets a flag and exits; then at
"strategic 'safe' points" in later execution, perl sees that flag is
set and then runs the handler. this is documented in the section
"Deferred Signals" of perlipc(1).
if you don't set a handler for a signal, perl just lets your os's
normal signal handler run and everything is fine.
the key thing to note here, however is the "at strategic 'safe' points"
*later* in the script's execution. that means control must return to
the interpreter for your handler to run. in your test case, the SIGINT
comes when the interpreter is blocking on the call to
g_main_loop_run()... the interpreter never reaches the point where it
sees that it needs to run the handler!
you can prove this:
$SIG{INT} = sub{ warn "inside sighandler"; };
use Glib;
my $mainloop = Glib::MainLoop->new();
Glib::Timeout->add (100, sub {1});
$mainloop->run;
^C will then stop the program.
of course, it will stop the program up to 100ms *after* the signal was
received. an idle may give you better granularity, however, recurring
idles are a great way to increase your system load for no good reason;
a timeout at about 100ms is less of a strain on your system, but even
then it's wasted work.
you were using perl 5.8.0 (which is what was standard on redhat 8.0),
and that version provides the deferred signals as a compile-time
default. some later version, i think 5.8.1 but definitely by 5.8.3,
allows you to disable the safe signals at runtime by setting
PERL_SIGNALS=unsafe in the environment. with that, your script works
unaltered.
after a fair bit of discussion in #gtk+, there are a few options:
a) if you are going to install a handler in %SIG and you need it to run
during a main loop, ensure that you have a new enough version of perl
and set PERL_SIGNALS=unsafe in the env before running.
b) install a no-op timeout that causes perl to check for signals every
so often, say 100ms. pygtk does this. it's simple and it works, but
it's a little ugly and wasteful.
c) yosh proposed an elegant but difficult-to-get-right solution
involves using a tie to mask and override %SIG to allow us to catch
modifications to the signal set, so we can override the signal handler
to call a springboard, which queues up an event for the main loop to
process, which will trigger perl to run its signal handlers. we will
have to monitor %SIG because it may change over the course of the app,
and we don't want to mask the os signals for no reason, nor do we want
to categorically disable the deferred signal handling in all gtk2-perl
apps, because the deferred signals are A Good Thing.
option c) is the most elegant and imposes no runtime penalty, but will
be the hardest to get right. option b) is a fair, if dirty, stopgap.
option a) is what we have at the moment.
what say you, peanut gallery?
--
elysse (in labor): is the head the biggest part?
midwife: yes.
elysse: oh, good.
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]