CGI/Perl Guide | Learning Center | Forums | Advertise | Login
Site Search: in

  Main Index MAIN
INDEX
Search Posts SEARCH
POSTS
Who's Online WHO'S
ONLINE
Log in LOG
IN

Home: Perl Programming Help: Intermediate:
Signals

 



Batman
New User

Jan 14, 2010, 8:26 PM

Post #1 of 4 (1026 views)
Signals Can't Post

This is my program:


Code
my $parentpid = $PID; 
my $pid;

$SIG{'USR1'} = sub {
print "Received signal\n";
exit;
};

$pid = fork();
if ($pid == 0) {
print "Sent signal\n";
kill('USR1', $parentpid);
exit;
} else {
while(1) {
}
}


when I run it I get this output:
Sent signal
Received signal
Received signal

Why does it receive the signal twice but only send it once?


shawnhcorey
Enthusiast


Jan 15, 2010, 7:04 AM

Post #2 of 4 (1019 views)
Re: [Batman] Signals [In reply to] Can't Post

It works as expected on my machine. What OS are you using?

__END__

I love Perl; it's the only language where you can bless your thingy.

Perl documentation is available at perldoc.perl.org. The list of standard modules and pragmatics is available in perlmodlib.

Get Markup Help. Please note the markup tag of "code".


Batman
New User

Jan 18, 2010, 3:20 PM

Post #3 of 4 (966 views)
Re: [shawnhcorey] Signals [In reply to] Can't Post

My OS is windows XP but I'm using cygwin to run the program.


7stud
Enthusiast

Jan 23, 2010, 4:45 PM

Post #4 of 4 (930 views)
Re: [Batman] Signals [In reply to] Can't Post

I get the same results as the op on mac osx. Here is a problem: where is the signal being sent?


Code
$parentpid = $PID;  
print "-->$parentpid<--\n";

if (!defined $parentpid) {
print 'undef\n';
}

--output:--
--><--
undef

The signal isn't being sent to the parent--it's being sent to the child: when undef is used as a number it is interpreted as 0. However, it still seems like there is only one signal being sent. I think the parent process should hang indefinitely when it enters the infinite while loop. It's as if the signal is filtering from the child up to the parent.

It also looks like there are three processes:


Code
my $parentid = $PID; 
my $pid;

print "$$\n";

$SIG{'USR1'} = sub {
print "$$: Received signal\n";
exit;
};


$pid = fork();

print "\$pid after fork(): $pid\n";

if ($pid == 0) {
print "Sent signal\n";
kill('USR1', $parentpid);
exit;
} else {
while(1) {
}
}

--output:--
459
$pid after fork(): 460
$pid after fork(): 0
Sent signal
460: Received signal
459: Received signal

The receive message does not appear to be printed by the child since there is no process id of 0 in the message.

Well, I guess there aren't 3 processes based on this output:

Code
my $parentid = $PID; 
my $pid;

print "$$\n";

$SIG{'USR1'} = sub {
print "$$: Received signal\n";
exit;
};

$pid = fork();

print "\$pid after fork(): $pid\n";

if ($pid == 0) {
print "child: $$\n";

print "Sent signal\n";
kill('USR1', $parentpid);
exit;
} else {
print "parent: $$\n";
while(1) {
}
}

--output:--
465
$pid after fork(): 466
parent: 465
$pid after fork(): 0
child: 466
Sent signal
465: Received signal
466: Received signal

The child does not appear to really have a process id of 0, rather fork() just returns 0 in the child. So calling the variable $pid seems to be a misnomer, even though I've never seen it called anything else.

After thinking about your problem some more, I decided that killing a pid of 0 must be some special command--similar to the way a signal of 0 is special; and after searching around on google, I found this in an IEEE standards paper on kill():


Quote
If pid is 0, sig shall be sent to all processes (excluding an unspecified set of system processes) whose process group ID is equal to the process group ID of the sender, and for which the process has permission to send a signal.


That seems to be what is happening with your program. I couldn't find anything in the perl docs about what a pid of 0 means, and the manpages for my system's kill() command don't mention that either.

Here is some output that traces what's happening:

Code
my $parentid = $PID; 
my $pid;

$SIG{'USR1'} = sub {
print "$$: Received signal\n";
exit;
};

$pid = fork();

print "\$pid after fork(): $pid\n";

if ($pid == 0) {
print "child: $$, group: " . getpgrp($$) . "\n";

print "Sent signal\n";
kill('USR1', $parentpid);

exit;
}
else {
print "parent: $$, group: " . getpgrp($$) . "\n";

while(1) {
}
}

--output:--
$pid after fork(): 524 #parent gets child's pid
parent: 523, group: 523 #parent's pid and the parent's group id
$pid after fork(): 0 #fork() returns 0 in the child(but that's not a pid!)
child: 524, group: 523 #here is the child's pid and group id
Sent signal
523: Received signal #parent received signal
524: Received signal #child received signal


Basically, a process and all its child processes, as well as any processes started by the children, all share the same group id, and calling kill() on a process id of 0 will send the specified signal to them all.

By the way, if you had the following at the top of your program:


Code
use strict; 
use warnings;


you would have never ran into this problem. You need to 'use English;' to be able to use the sensical names for perl's global vars.


(This post was edited by 7stud on Jan 24, 2010, 9:06 PM)

 
 


Search for (options) Powered by Gossamer Forum v.1.2.0

Web Applications & Managed Hosting Powered by Gossamer Threads
Visit our Mailing List Archives