Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Perl > Perl Misc > SIGINT not blocked by system()?

Reply
Thread Tools

SIGINT not blocked by system()?

 
 
Tom
Guest
Posts: n/a
 
      04-27-2006
I've got a multithreaded script in which I'd like to have my "worker"
threads ignore SIGINT (i.e. the main thread traps it and calls a sub to
cleanup nicely after all workers are done). The workers do their thing
via system() calls, and my experience (using 5.8.8 at least) indicates
that SIGINT is being propogated to the worker threads' system() call
(even though it's locally ignored).

According to perlfaq8, system() is shielded from SIGINT:

-----------------------------------------------------------------------------
How do I make a system() exit on control-C?

You can't. You need to imitate the system() call (see perlipc for
sample code) and then have a signal handler for the INT signal that
passes the signal on to the subprocess.
-----------------------------------------------------------------------------

When CTRL-C is hit on the console, the following code will print
"Cleaning up..." and exits promptly. I would have expected it to exit
after all threads have returned.


#!/usr/bin/perl -w
use strict;

use threads;

$SIG{INT} = \&cleanup;

foreach my $id ( 1..10 ) {
threads->new( \&sleeper, $id );
}

sleep 60;

sub cleanup {
print "Cleaning up\n";
foreach my $thread ( threads->list() ) {
$thread->join();
}
exit();
}

sub sleeper {
my $id = shift;
my $time = int( rand(30) );
local $SIG{INT} = 'IGNORE';
print "Thread $id sleeping for $time...\n";
system( "sleep $time" );

return;
}

 
Reply With Quote
 
 
 
 
Ben Morrow
Guest
Posts: n/a
 
      04-27-2006

Quoth "Tom" <(E-Mail Removed)>:
> I've got a multithreaded script in which I'd like to have my "worker"
> threads ignore SIGINT (i.e. the main thread traps it and calls a sub to
> cleanup nicely after all workers are done).


In general which thread receives a signal is not well defined; and
Perl's signal handling can be a little... funny. You may have luck with
any or all of these:

1. Catch the signal in the worker threads as well, and have them signal
a condition variable (see threads::shared). The main thread should be
sitting in a cond_wait on that variable, and if it gets signalled it
does the cleanup and exits. You may need some playing around with
mutexes and/or sigprocmask to avoid a race between the child starting
and the parent going into the wait.

2. Mask the signal in the child threads with POSIX::sigprocmask. This
may well mask it in the parent as well, though...

3. Set the environment variable PERL_SIGNALS to 'unsafe'. This will go
back to the old immediate signal handling, which is less safe (there is
some chance of memory corruption). You will want to heed the old advice
about doing nothing in the signal handler beyond setting a flag you can
check in the main program.

4. Fake up a system() yourself, as the faq suggests, and ignore the
signal in the (forked) child before you exec.

I don't actually know how well Perl handles the interaction of fork and
threads: it's not something I would try, myself. If you really do just
need your children to run system() and return, you'd be much better off
just forking and waiting.

Ben

--
We do not stop playing because we grow old;
we grow old because we stop playing.
[George Bernard Shaw]
http://www.velocityreviews.com/forums/(E-Mail Removed)
 
Reply With Quote
 
 
 
 
xhoster@gmail.com
Guest
Posts: n/a
 
      04-28-2006
"Tom" <(E-Mail Removed)> wrote:
> I've got a multithreaded script in which I'd like to have my "worker"
> threads ignore SIGINT (i.e. the main thread traps it and calls a sub to
> cleanup nicely after all workers are done). The workers do their thing
> via system() calls, and my experience (using 5.8.8 at least) indicates
> that SIGINT is being propogated to the worker threads' system() call
> (even though it's locally ignored).


In your shell, when you hit ^C, the shell sends an interupt signal to
all the processes in its "process group" (or whatever they call it),
which includes the processes spawned by the system function.

If, instead of hitting ^C, you instead determined the script's pid and
use linux's "kill -2 <pid>", you will probabl see the behaviour you want.

I can also get the the behaviour you want on my system by using
POSIX::setsid.


>
> According to perlfaq8, system() is shielded from SIGINT:
>
> -------------------------------------------------------------------------
> ---- How do I make a system() exit on control-C?
>
> You can't. You need to imitate the system() call (see perlipc for
> sample code) and then have a signal handler for the INT signal that
> passes the signal on to the subprocess.
> -------------------------------------------------------------------------
> ----


Perl doesn't pass the INT into the system. But if your shell decided to
signal the spawned process on its own, Perl doesn't stop it from doing so.

>
> sub sleeper {

##prevent shell from clobbering system
POSIX::setsid();
> my $id = shift;
> my $time = int( rand(30) );
> local $SIG{INT} = 'IGNORE';
> print "Thread $id sleeping for $time...\n";
> system( "sleep $time" );
>
> return;
> }


Xho

--
-------------------- http://NewsReader.Com/ --------------------
Usenet Newsgroup Service $9.95/Month 30GB
 
Reply With Quote
 
Ben Morrow
Guest
Posts: n/a
 
      04-28-2006

Quoth (E-Mail Removed):
> Perl doesn't pass the INT into the system. But if your shell decided to
> signal the spawned process on its own, Perl doesn't stop it from doing so.


My system(3) says

| During execution of the command, SIGCHLD will be blocked, and SIGINT and
| SIGQUIT will be ignored.

Does Perl's system() not do this?

Ben

--
All persons, living or dead, are entirely coincidental.
(E-Mail Removed) Kurt Vonnegut
 
Reply With Quote
 
xhoster@gmail.com
Guest
Posts: n/a
 
      04-28-2006
Ben Morrow <(E-Mail Removed)> wrote:
> Quoth (E-Mail Removed):
> > Perl doesn't pass the INT into the system. But if your shell decided
> > to signal the spawned process on its own, Perl doesn't stop it from
> > doing so.

>
> My system(3) says
>
> | During execution of the command, SIGCHLD will be blocked, and SIGINT
> | and SIGQUIT will be ignored.


That seems to mean that the parent process itself process will ignore
SIGINT while the child is running, not that the child will be arranged to
ignore SIGINT. I'm not sure if that is how you were interpreting it or not.

>
> Does Perl's system() not do this?


It seems to depend on the threads used.

$ perl -wle 'use strict; use threads; $SIG{INT}=sub {die }; \
print system "sleep 6"; print "Done"'
2
Done

(Exits immediately upon ^c, but not because the parent itself got the
signal, rather because the child the parent was waiting on got the signal
and exited early.)

$ perl -wle 'use strict; use threads; $SIG{INT}=sub {die }; \
threads->create(sub{print system "sleep 6"}); \
threads->list->join(); print "Done"'
2
Died at -e line 1.

Here, the parent itself does apparently get the signal.

This is perl, v5.8.3 built for x86_64-linux-thread-multi

Xho

--
-------------------- http://NewsReader.Com/ --------------------
Usenet Newsgroup Service $9.95/Month 30GB
 
Reply With Quote
 
Ben Morrow
Guest
Posts: n/a
 
      04-28-2006

Quoth (E-Mail Removed):
> Ben Morrow <(E-Mail Removed)> wrote:
> > Quoth (E-Mail Removed):
> > > Perl doesn't pass the INT into the system. But if your shell decided
> > > to signal the spawned process on its own, Perl doesn't stop it from
> > > doing so.

> >
> > My system(3) says
> >
> > | During execution of the command, SIGCHLD will be blocked, and SIGINT
> > | and SIGQUIT will be ignored.

>
> That seems to mean that the parent process itself process will ignore
> SIGINT while the child is running, not that the child will be arranged to
> ignore SIGINT. I'm not sure if that is how you were interpreting it or not.


Ah, yes, I missed that ambiguity. I was reading it as

fork
if (parent) {
waitpid
}
else {
ignore SIGINT
exec
}

i.e. the parent sets up the child to ignore the signals.

So, the answer is, if you care do it all yourself and handle the signals
as you need .

--
Heracles: Vulture! Here's a titbit for you / A few dried molecules of the gall
From the liver of a friend of yours. / Excuse the arrow but I have no spoon.
(Ted Hughes, [ Heracles shoots Vulture with arrow. Vulture bursts into ]
'Alcestis') [ flame, and falls out of sight. ] (E-Mail Removed)
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
multiprocessing and SIGINT akineko Python 2 01-10-2009 07:15 AM
Cleanly exiting multi thread application on SIGINT jrpfinch Python 2 03-23-2007 01:32 PM
how to send a SIGINT to a Python process? Michele Simionato Python 2 10-03-2005 03:04 PM
using filedescriptors in SIGINT signal handler Bram Stolk Python 2 09-13-2005 02:01 PM
A Question About Handling SIGINT With Threads Keith Python 0 04-13-2005 03:12 PM



Advertisments