Hardy has asked for the wisdom of the Perl Monks concerning the following question:

Hello Perl Monks,

I crashed my host provider's server last time I ran my daemon/web server script and I would not like to repeat the process. they said it was a loop of some sort concerning the signals I was catching in the parent daemon and the child processes simultaneously. as a result, they only allow me to test the script during business hours.

the problem seemed to be that the child processes were also using the restart sigterm handler used in the parent process (or daemon process).

I gathered from Clinton and others that I could turn off the daemon handlers for the child processes and let the term signal use its normal routine by placing this command after each child fork:

#turn off the posix sigterm handler $SIG{TERM} = 'DEFAULT';

now, when the parent receives the term signal, the parent (or daemon) will enter the sigterm handler and restart its process by reloading the code into its process, but when a child gets a term signal, it would simply terminate its process.

this would give me this result: the script stays alive continuously while hundreds of clients log on and off playing various games.

if after looking at the code below you decide this will not happen, please let me know before I try running the script in real time.

#!/usr/bin/perl -w -t #!/usr/local/bin/perl -w -t #this is the script that is loaded first #load support for strict variables use strict; #load support for printing to the screen - testing only use CGI; use CGI::Carp qw(fatalsToBrowser); my $q = CGI->new; print $q->header; print "<p>start: $$<p>"; #load support for sockets use IO::Socket; #load posix support for named pipes use POSIX qw(mkfifo); #load support for finding the path to the process folder use FindBin(); use File::Basename(); use File::Spec::Functions; #load posix support for trapping signals use POSIX(); #determine the current script path and name my $script = File::Basename::basename($0); my $SELF = catfile $FindBin::Bin, $script; #create a new signal set my $sigset = POSIX::SigSet->new(); #create the action you want performed on terminate signals my $termAction = POSIX::SigAction->new('sigTERM_handler', $sigset, &POSIX::SA_NODEFER); #attach the signal to the action you want performed POSIX::sigaction(&POSIX::SIGTERM, $termAction); #start of the sub to run when the terminate signal arrives sub sigTERM_handler { #store the signal sent by the system my $HTPad_signalCaught = shift; #run the handler for all exit signals &HTPad_exitSignalHandler("Terminate", $HTPad_signalCaught); } #end of the sub to run when the terminate signal arrives #start of the handler for all exit signals sub HTPad_exitSignalHandler { #reinstate the passed variables my $HTPad_exitType = shift; my $HTPad_signalCaught = shift; unless (exec($SELF, @ARGV)) { Die "Could not restart the script after a $HTPad_signalCaught si +gnal was received: $!"; } } #end of the handler for all exit signals #turn on auto flush $|=1; #load required files require './HTPadProcess_subs.pl'; #ignore child signals in order to do automatic child reaping $SIG{CHLD} = 'IGNORE'; #enter the web server &HTPad_webSserver(); #start of the web server sub HTPad_webSserver { my %HTPad = (); my ($HTPad_server , $HTPad_client); #define the in out port $HTPad{port} = 5814; #define the server pipe names $HTPad{serverReadPipeName} = '.serverReadPipe.txt'; $HTPad{serverWritePipeName} = '.serverWritePipe.txt'; #open the TCP connection $HTPad_server = IO::Socket::INET->new( LocalPort => $HTPad{port}, Type => SOCK_STREAM, Reuse => 1, Listen => SOMAXCONN) or die "There is no tcp server on port $HTPad{port}: $!\n"; #start of the parent server accepting clients while ($HTPad_client = $HTPad_server->accept()) { #auto flush the client $HTPad_client->autoflush(1); #start of forking a write child for the client unless ($HTPad{clientWritePID} = fork()) { #write child #turn off the posix sigterm handler $SIG{TERM} = 'DEFAULT'; #turn off the posix sigint handler $SIG{INT} = 'DEFAULT'; #turn off the posix sighup handler $SIG{HUP} = 'DEFAULT'; #turn off the posix sigpipe handler $SIG{PIPE} = 'DEFAULT'; #the read childcloses the unused server handle close ($HTPad_server); #get the pipe name from the parent server $HTPad{pipeName} = &HTPad_readFromPipe($HTPad{serverWriteP +ipeName}); #start of continuously wait for data from the read child while (1) { #get data from the read child $HTPad{ringData} = &HTPad_readFromPipe($HTPad{pipeName +}); #add test text #$HTPad{ringData} = $HTPad{ringData}; #start of process test data if ($HTPad{ringData} =~ m/are you there/i) { #send the data to the client print $HTPad_client "The web server confirms your +write test:" . $HTPad{ringData} . "\015\12"; #end of process test data #start of process normal web server data } else { #send the data to the client print $HTPad_client "This is the server and you wr +ote: " . $HTPad{ringData} . "\015\12"; } #end of process normal web server data } #end of continuously wait for data from the read child #close the write child connection close($HTPad_client); #exit the write child to keep it from accepting new client +s exit(1); } #end of forking a write child for the client #start of checking the success of the forked write child if ($HTPad{clientWritePID} > 0) { #start of forking a read child for the client unless ($HTPad{clientReadPID} = fork()) { #read child #turn off the posix sigterm handler $SIG{TERM} = 'DEFAULT'; #turn off the posix sigint handler $SIG{INT} = 'DEFAULT'; #turn off the posix sighup handler $SIG{HUP} = 'DEFAULT'; #turn off the posix sigpipe handler $SIG{PIPE} = 'DEFAULT'; #the read childcloses the unused server handle close ($HTPad_server); #get the pipe name from the parent server $HTPad{pipeName} = &HTPad_readFromPipe($HTPad{serverRe +adPipeName}); #start of listen for data untill client connection clo +ses while (defined ($HTPad{ringData} = <$HTPad_client>)) { #start of send the new data to the write child if ($HTPad{ringData} ne '') { #add test data to the data $HTPad{ringData} = $HTPad{pipeName} . " " . $H +TPad{ringData}; #send the data to the write child &HTPad_writeToPipe($HTPad{pipeName}, $HTPad{ri +ngData}); } #end of send the new data to the write child } #end of listen for data untill client connection clo +ses #send sig term to write child when client closes conne +ction kill ("TERM", $HTPad{clientWritePID}); #close the read child connection close($HTPad_client); #exit the read child to keep it from accepting new cli +ents exit(1); } #end of forking a read child for the client } #end of checking the success of the forked write child #start of checking the success of the forked write and read ch +ild if ($HTPad{clientWritePID} > 0 and $HTPad{clientReadPID} > 0) +{ #parent server #the server closes the unused read child handle close ($HTPad_client ); #define the new clients pipe name $HTPad{pipeNameFromServer} = '.puppy_' . $HTPad{clientRead +PID} . '.txt'; #send the pipe name to the read child &HTPad_writeToPipe($HTPad{serverReadPipeName}, $HTPad{pipe +NameFromServer}); #send the pipe name to the write child &HTPad_writeToPipe($HTPad{serverWritePipeName}, $HTPad{pip +eNameFromServer}); #close the TCP connection after x connections - only when +not waiting for more clients. if (++$HTPad{clientCount} >= 2) { close($HTPad_server); } } #end of checking the success of the forked write and read ch +ild #initialize the read and write pids $HTPad{clientWritePID} = 0; $HTPad{clientReadPID} = 0; } #end of the parent server accepting clients #close the parent server close($HTPad_server); } #end of the web server __END__

Skype: hardManHardy
...waiting for the world to change...

Replies are listed 'Best First'.
Re: I crashed my web host with sig handlers - please help
by Corion (Patriarch) on Aug 08, 2007 at 11:33 UTC

    Your ISP should set up ulimits for all CGI processes and kill them after (say) 2 minutes to prevent such stuff. You should develop and test not on your production webserver but on a local machine, for example by using VMWare Player or installing and running Apache on your development machine. If you're developing under Windows, you might prefer to go the VMWare route because fork() is broken on Windows and signals don't exist as a mechanism of IPC.

    Looking at your code I find it very hard to make out what's going on because you don't use indentation.

      I find it very hard to make out what's going on because you don't use indentation.

      Or subroutines....
    A reply falls below the community's threshold of quality. You may see it by logging in.