I have a daemon that forks multiple child processes.
#!/opt/perl-5.6.1/bin/perl
######################################################################
+##########
############
#Initial Phase: Make a working daemon.
#Second Phase: Fork child processes.
#Third phase: Build a basic framework wherein the individual pieces of
+ functionalities can be just plugged in.
#Fourth Phase: Build the individual pieces of checks / other functiona
+lities like debug option, logging other checks etc.
#Fifth Phase: Bind the different functionalities with the basic framew
+ork.
#Sixth Phase: Test the compelete script.
#Seventh Phase: Performance improvement.
######################################################################
+##########
############
use POSIX;
use FileHandle;
use File::Basename;
use IO::Handle;
#$PGM=basename($0);
$DEF_TIMEOUT=60;
$CHILD_TIMEOUT=10;
$NUM_OF_KIDS=4;
$shutitdown=0; #Please do not change this value.
my $pid;
my $file='/home/hkitmond/test.txt';
my $file2='/home/hkitmond/pid.txt';
my $logfile='/home/hkitmond/log';
STDOUT->autoflush(1);
STDERR->autoflush(1);
@jobs = ();
%job = ();
###############Install signal handler############
$SIG{'TERM'}=$SIG{'INT'}=$SIG{'HUP'}=$SIG{'QUIT'}='shutdown';
#################################################
if ($pid=fork()){
print "\nI am the parent and just forked a child that has this PID:$pi
+d";
#####Log this PID somewhere so that it can be used while issuing /bin/
+kill -s TERM <PID>##############
open(PIDFILE, '>/home/hkitmond/pid.txt');
print PIDFILE "$pid";
close(PIDFILE);
######################################################################
+################################
print "\nExiting..";
exit 0;
}
elsif(!defined $pid){
print "\nCouldn't fork child. Probably process table is filled. Get in
+ touch with sysadm!!";
}
else{
#This is the thread that is actually the daemon and it will keep runni
+ng forever.
setpgrp(0, 0);
chdir('/');
print STDOUT "\nI am the child $$ and have just been forked by my pare
+nt. Now I have become a daemon.";
open(LOGFILE,'>/home/hkitmond/log');
LOGFILE->autoflush(1);
while(1){
open(INPUT, $file)||die ("\nCannot open $file");
chomp (@args=<INPUT>);
close(INPUT);
$i=1;
#if ($shutitdown==0){
#foreach $node (@args){
while ($node = shift(@args)){
if ($shutitdown==0){
$READER = "READER$i";
$WRITER = "WRITER$i";
pipe($READER, $WRITER);
$WRITER->autoflush(1);
if ($pid = fork()){
close($WRITER);
$job{$pid}{'pipe'}= $READER;
}
elsif(!defined $pid){
print "\nCouldn't fork child";
}
else{
###This is the thread invoked per server - it will contain calls to wr
+apper scripts for every check. Agent scripts reside on agent.
###This thread will exit after it runs checks and other tasks.
######################################
#Include timeout functionality here to make sure a thread doesn't ling
+er too long.
#Install the appropriate signal handler for timeout
$SIG{'ALRM'}='thread_hung';
alarm $CHILD_TIMEOUT;
print STDOUT "\nI am the child $$ corresponding to $node";
setpgrp(0, 0);
close($READER);
chdir('/');
##################################
#Write code here to call scripts to invoke various checks#
#Use timeout functionality
#while(1){
#}
@RES = system("/usr/sbin/ping $node 3 > /dev/null");
##################################
$m="$$:$node:x_START_x";
print $WRITER "$m\n";
foreach $m (@RES){
print $WRITER "$m\n";
}
close($WRITER);
###Exit this thread###
exit 0;
}
######################################################################
+###########
#Need to implement logic to allow no more than defined number of threa
+ds to run parallely
#while(scalar(keys %job) >= $NUM_OF_KIDS || (%job && (scalar @args < $
+NUM_OF_KIDS))){
while(scalar(keys %job) >= $NUM_OF_KIDS || ((scalar(keys %job) >= 1) &
+& (scalar @args == 0))){
print STDOUT "\n".scalar(keys %job).",".scalar @args;
print STDOUT "\nWaiting for some child...";
$kpid= wait; #waiting for any child process to finish. This is essenti
+al for proper termination of child.
print STDOUT "\nJust waited for $kpid child";
#$a = @args; #not sure why this is added.
next unless $job{$kpid}; #Not required actually.
@kid_stdout = ();
$PIPE=$job{$kpid}{'pipe'};
chomp(@kid_stdout=<$PIPE>);
close($PIPE);
foreach $l (@kid_stdout){
print STDOUT "\n$l";
print LOGFILE "\n$l";
}
delete($job{$kpid}); #removing the element from job corresponding to
+this process
}
##Logic to restrict number of parallel threads less than the predefine
+d value ends
######################################################################
+##############
print STDOUT "\nGoing to next run of loop";
$i++;
} #If block corresponding to $shutitdown=0 ends
######################################################################
+##
#Need to include logic such that if a daemon needs to be killed, it ca
+tches this signal, does the required cleanup and then exits.
#If its req. to stop the daemon, use /bin/kill -9 <PID> command which
+will be caught by signal handler and the required cleanup will be don
+e.
######################################################################
+##
else{
##############################################################
#This block contains logic such that on reception of SIGTERM, the alre
+ady forked processes are waited upon by the parent.
#We need to consider the situation where some child has already been k
+illed as a result of timeout.
##############################################################
print STDOUT "\nInside the cleanup section...";
print STDOUT "\nNumber of outstanding processes:".scalar(keys %job)."
+..";
while(scalar(keys %job) != 0){
$pid=wait;
delete($job{$pid});
print STDOUT "\nJust received exit status of $pid. Waiting for ".scala
+r(keys %job)." others before stopping the daemon..";
}
print "\nDaemon exiting...";
close(LOGFILE);
exit 0;
} #Else block corresponding to cleanup i.e. $shutitdown=1 ends
} #for loop corresponding to every node from i/p file ends.
=piyush
######################################################################
+##
#Need to include logic such that if a daemon needs to be killed, it ca
+tches this signal, does the required cleanup and then exits.
#If its req. to stop the daemon, use /bin/kill -9 <PID> command which
+will be caught by signal handler and the required cleanup will be don
+e.
######################################################################
+##
else{
##############################################################
#This block contains logic such that on reception of SIGTERM, the alre
+ady forked processes are waited upon by the parent.
#We need to consider the situation where some child has already been k
+illed as a result of timeout.
##############################################################
print STDOUT "\nInside the cleanup section...";
print STDOUT "\nNumber of outstanding processes:".scalar(keys %job)."
+..";
while(scalar(keys %job) != 0){
$pid=wait;
delete($job{$pid});
print STDOUT "\nJust received exit status of $pid. Waiting for ".scala
+r(keys %job)." others before stopping the daemon..";
}
print "\nDaemon exiting...";
exit 0;
} #Else block corresponding to cleanup i.e. $shutitdown=1 ends
=cut
} #End of infinite while loop
} #end of daemon code.
##############Subroutines Section#####################################
+########
sub shutdown{
print STDOUT "\nReceived stop signal. Stopping the daemon...";
$shutitdown=1;
}
sub thread_hung{
print STDOUT "\nThread $$ is hung. Aborting..";
$id=$$;
$pipe=$job{$id}{'pipe'};
delete($job{$id});
kill -9, $id;
close($pipe);
}
Here is a sample output:
I am the parent and just forked a child that has this PID:2040
I am the child 2040 and have just been forked by my parent. Now I have
+ become a daemon.
Exiting..hkgisdev02%
Going to next run of loop
I am the child 2041 corresponding to abcd.pi.com
I am the child 2042 corresponding to lonovoprod5.lehman.com
Going to next run of loop
I am the child 2046 corresponding to lonovoprod6.lehman.com/usr/sbin/p
+ing: unknown host abcd.pi.com
Going to next run of loop
I am the child 2050 corresponding to lonlxvmopsw01.lehman.com
4,587
Waiting for some child...
Just waited for 2041 child
2041:abcd.pi.com:x_START_x
256
Going to next run of loop
I am the child 2052 corresponding to faicmc01-usrs07.lehman.com
4,586
Waiting for some child...
Just waited for 2042 child
2042:lonovoprod5.lehman.com:x_START_x
0
Going to next run of loop
4,585
Waiting for some child...
Just waited for 2046 child
2046:lonovoprod6.lehman.com:x_START_x
0
Going to next run of loop
I am the child 2056 corresponding to lonintrelay2.lehman.com
I am the child 2057 corresponding to losin11pudb4-m.lehman.com
4,584
Waiting for some child...
Just waited for 2050 child
2050:lonlxvmopsw01.lehman.com:x_START_x
0
Going to next run of loop
4,583
Waiting for some child...
I am the child 2062 corresponding to lonfwmgmt2.lehman.com
Just waited for 2052 child
2052:faicmc01-usrs07.lehman.com:x_START_x
0
As can be seen in the above output, the PIDs that get generated are: 2041, 2042,
and so on .... which is not in a sequence...