Skip Menu |

This queue is for tickets about the NetServer-Generic CPAN distribution.

Report information
The Basics
Id: 27223
Status: new
Priority: 0/
Queue: NetServer-Generic

People
Owner: Nobody in particular
Requestors: nick.cpan [...] xlmt.com
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 1.03
Fixed in: (no value)



Subject: Forking server exits after reaping children [PATCH SUPPLIED]
-- Demonstration -- I used to following script to test the module: use NetServer::Generic; my $server = NetServer::Generic->new; $server->port(9000); $server->run(); # Server should now run until $server->quit is called print "Server has stopped running :(\n"; Use a telnet client to access the server on port 9000. You will see the default echo server. Type 'bye'. The connection should close, but the server should remain running waiting for other connections. Instead you will see that the server exits. -- Explanation -- Mostly SIGCHLD is received while that main server process is waiting on $main_sock->accept() for a new connection. When a child process exits, SIGCHLD is received and that wait is interrupted. Once the signal is handled by &reap_child and control returns, Perl does not restart the relevant system call for $main_sock->accept, which instead returns undef. This is interpreted as an error and the server ends. -- Proposed Fix - Patch Attached -- Set a flag whenever &reap_child is called. If $main_sock->accept() fails, test this flag and restart the $main_sock->accept() call if we were interrupted. A patch is attached. I've tried as far as possible to keep to the same style conventions - and I hope the wide scope of the $NetServer::Signal_Flag variable I've introduced doesn't offend you too much :) I hope this proves useful. I've found this module a great help - thanks. FYI I'm running NetServer-Generic-1.03, perl v5.8.8 on Linux 2.6.18-gentoo-r5 #8 SMP PREEMPT
Subject: exit_after_reap.diff
--- /home/nick/Perl-NetServer-Test/NetServer-Generic-1.03/Generic.pm 2000-12-12 19:20:54.000000000 +0000 +++ /usr/lib/perl5/vendor_perl/5.8.8/NetServer/Generic.pm 2007-05-21 16:08:11.000000000 +0000 @@ -564,6 +564,11 @@ $NetServer::Debug = 0; +# $NetServer::Signal_Flag; if non-zero, we were interrupted to service a signal +# Perhaps we want to reset this flag and resume what we were doing before +$NetServer::Signal_Flag = 0; + + # here is a default callback routine. It basically echoes back anything # you sent to the server, unless the line begins with quit, bye, or # exit -- in which case it kills the server (rather than simply exiting). @@ -675,6 +680,8 @@ } sub reap_child { + # This sub is called when we receive a SIGCHLD + $NetServer::Signal_Flag = 1; do {} while waitpid(-1, WNOHANG) > 0; } @@ -1067,7 +1074,24 @@ # now loop, forking whenever a new connection arrives on the listener $self->root_pid($$); # set server root PID - while (my ($new_sock) = $main_sock->accept()) { + while (1) { + + # $NetServer::Signal_Flag is set by the SIGCHLD handler which + # can interrupt us while waiting on $main_sock->accept() + # For some reason this call is not restarted by Perl + # when the signal handling function returns, so we need to + # check and restart ourselves if need be. + $NetServer::Signal_Flag = 0; + my ($new_sock) = $main_sock->accept(); + if (!$new_sock && $NetServer::Signal_Flag) { + # We were interrupted + redo; + } elsif (!$new_sock) { + # Some other error occurred - give up + last; + } + + # If we get here, then we have a valid socket connection &$ante_fork_callback($self) if ( defined $ante_fork_callback ); my $x_time = [ gettimeofday ]; # millisecond timer to track duration my $pid = fork();