--- loncom/loncnew 2005/01/17 20:35:14 1.66 +++ loncom/loncnew 2007/06/18 22:49:52 1.87 @@ -2,7 +2,7 @@ # The LearningOnline Network with CAPA # lonc maintains the connections to remote computers # -# $Id: loncnew,v 1.66 2005/01/17 20:35:14 albertel Exp $ +# $Id: loncnew,v 1.87 2007/06/18 22:49:52 albertel Exp $ # # Copyright Michigan State University Board of Trustees # @@ -60,7 +60,7 @@ use LONCAPA::Stack; use LONCAPA::LondConnection; use LONCAPA::LondTransaction; use LONCAPA::Configuration; -use LONCAPA::HashIterator; +use Fcntl qw(:flock); # Read the httpd configuration file to get perl variables @@ -72,9 +72,8 @@ my %perlvar = %{$perlvarref}; # # parent and shared variables. -my %ChildHash; # by pid -> host. -my %HostToPid; # By host -> pid. -my %HostHash; # by loncapaname -> IP. +my %ChildPid; # by pid -> host. +my %ChildHost; # by host. my %listening_to; # Socket->host table for who the parent # is listening to. my %parent_dispatchers; # host-> listener watcher events. @@ -95,6 +94,8 @@ my $executable = $0; # Get the full # The variables below are only used by the child processes. # my $RemoteHost; # Name of host child is talking to. +my $RemoteHostId; # default lonid of host child is talking to. +my @all_host_ids; my $UnixSocketDir= $perlvar{'lonSockDir'}; my $IdleConnections = Stack->new(); # Set of idle connections my %ActiveConnections; # Connections to the remote lond. @@ -105,15 +106,14 @@ my $ConnectionCount = 0; my $IdleSeconds = 0; # Number of seconds idle. my $Status = ""; # Current status string. my $RecentLogEntry = ""; -my $ConnectionRetries=2; # Number of connection retries allowed. -my $ConnectionRetriesLeft=2; # Number of connection retries remaining. +my $ConnectionRetries=5; # Number of connection retries allowed. +my $ConnectionRetriesLeft=5; # Number of connection retries remaining. my $LondVersion = "unknown"; # Version of lond we talk with. my $KeyMode = ""; # e.g. ssl, local, insecure from last connect. my $LondConnecting = 0; # True when a connection is being built. -my $DieWhenIdle = 1; # When true children die when trimmed -> 0. my $I_am_child = 0; # True if this is the child process. # @@ -151,12 +151,14 @@ sub UpdateStatus { Makes an entry into the permanent log file. =cut + sub LogPerm { my $message=shift; my $execdir=$perlvar{'lonDaemons'}; my $now=time; my $local=localtime($now); my $fh=IO::File->new(">>$execdir/logs/lonnet.perm.log"); + chomp($message); print $fh "$now:$message:$local\n"; } @@ -196,7 +198,7 @@ sub Log { my $now = time; my $local = localtime($now); my $finalformat = "$local ($$) [$RemoteHost] [$Status] "; - my $finalformat = $finalformat.$format."\n"; + $finalformat = $finalformat.$format."\n"; # open the file and put the result. @@ -270,6 +272,7 @@ sub SocketDump { and as what we return in a SIGUSR1 =cut + sub ShowStatus { my $state = shift; my $now = time; @@ -280,13 +283,14 @@ sub ShowStatus { =pod -=head 2 SocketTimeout +=head2 SocketTimeout Called when an action on the socket times out. The socket is destroyed and any active transaction is failed. =cut + sub SocketTimeout { my $Socket = shift; Log("WARNING", "A socket timeout was detected"); @@ -304,12 +308,13 @@ sub SocketTimeout { } } + # # This function should be called by the child in all cases where it must -# exit. If the child process is running with the DieWhenIdle turned on -# it must create a lock file for the AF_UNIX socket in order to prevent -# connection requests from lonnet in the time between process exit -# and the parent picking up the listen again. +# exit. The child process must create a lock file for the AF_UNIX socket +# in order to prevent connection requests from lonnet in the time between +# process exit and the parent picking up the listen again. +# # Parameters: # exit_code - Exit status value, however see the next parameter. # message - If this optional parameter is supplied, the exit @@ -320,24 +325,20 @@ sub child_exit { # Regardless of how we exit, we may need to do the lock thing: - if($DieWhenIdle) { - # - # Create a lock file since there will be a time window - # between our exit and the parent's picking up the listen - # during which no listens will be done on the - # lonnet client socket. - # - my $lock_file = GetLoncSocketPath().".lock"; - open(LOCK,">$lock_file"); - print LOCK "Contents not important"; - close(LOCK); - - exit(0); - } - # Now figure out how we exit: + # + # Create a lock file since there will be a time window + # between our exit and the parent's picking up the listen + # during which no listens will be done on the + # lonnet client socket. + # + my $lock_file = &GetLoncSocketPath().".lock"; + open(LOCK,">$lock_file"); + print LOCK "Contents not important"; + close(LOCK); + unlink(&GetLoncSocketPath()); - if($message) { - die $message; + if ($message) { + die($message); } else { exit($exit_code); } @@ -371,7 +372,7 @@ sub Tick { KillSocket($Socket); $IdleSeconds = 0; # Otherwise all connections get trimmed to fast. UpdateStatus(); - if(($ConnectionCount == 0) && $DieWhenIdle) { + if(($ConnectionCount == 0)) { &child_exit(0); } @@ -502,6 +503,9 @@ the data and Event->w->fd is the socket sub ClientWritable { my $Event = shift; my $Watcher = $Event->w; + if (!defined($Watcher)) { + &child_exit(-1,'No watcher for event in ClientWritable'); + } my $Data = $Watcher->data; my $Socket = $Watcher->fd; @@ -565,6 +569,7 @@ sub ClientWritable { } } else { $Watcher->cancel(); # A delayed request...just cancel. + return; } } @@ -604,8 +609,8 @@ sub CompleteTransaction { StartClientReply($Transaction, $data); } else { # Delete deferred transaction file. Log("SUCCESS", "A delayed transaction was completed"); - LogPerm("S:$Transaction->getClient() :".$Transaction->getRequest()); - unlink $Transaction->getFile(); + LogPerm("S:".$Transaction->getClient().":".$Transaction->getRequest()); + unlink($Transaction->getFile()); } } @@ -673,9 +678,9 @@ sub FailTransaction { if ($ConnectionRetriesLeft > 0) { Log("WARNING", "Failing transaction " - .$transaction->getRequest()); + .$transaction->getLoggableRequest()); } - Debug(1, "Failing transaction: ".$transaction->getRequest()); + Debug(1, "Failing transaction: ".$transaction->getLoggableRequest()); if (!$transaction->isDeferred()) { # If the transaction is deferred we'll get to it. my $client = $transaction->getClient(); Debug(1," Replying con_lost to ".$transaction->getRequest()); @@ -685,12 +690,14 @@ sub FailTransaction { } =pod + =head1 EmptyQueue Fails all items in the work queue with con_lost. Note that each item in the work queue is a transaction. =cut + sub EmptyQueue { $ConnectionRetriesLeft--; # Counts as connection failure too. while($WorkQueue->Count()) { @@ -706,6 +713,7 @@ sub EmptyQueue { Close all connections open on lond prior to exit e.g. =cut + sub CloseAllLondConnections { foreach my $Socket (keys %ActiveConnections) { if(exists($ActiveTransactions{$Socket})) { @@ -714,7 +722,6 @@ sub CloseAllLondConnections { KillSocket($Socket); } } -=cut =pod @@ -736,8 +743,8 @@ Parameters: nonzero if we are allowed to create a new connection. - =cut + sub KillSocket { my $Socket = shift; @@ -949,7 +956,7 @@ sub LondReadable { # We need to be writable for this and probably don't belong # here inthe first place. - Deubg(6, "SendingRequest state encountered in readable"); + Debug(6, "SendingRequest state encountered in readable"); $Watcher->poll("w"); $Watcher->cb(\&LondWritable); @@ -1147,9 +1154,12 @@ sub LondWritable { } } + =pod =cut + + sub QueueDelayed { Debug(3,"QueueDelayed called"); @@ -1157,19 +1167,19 @@ sub QueueDelayed { Debug(4, "Delayed path: ".$path); opendir(DIRHANDLE, $path); - - my @alldelayed = grep /\.$RemoteHost$/, readdir DIRHANDLE; + + my $host_id_re = '(?:'.join('|',map {quotemeta($_)} (@all_host_ids)).')'; + my @alldelayed = grep(/\.$host_id_re$/, readdir(DIRHANDLE)); closedir(DIRHANDLE); - my $dfname; - my $reqfile; - foreach $dfname (sort @alldelayed) { - $reqfile = "$path/$dfname"; - Debug(4, "queueing ".$reqfile); + foreach my $dfname (sort(@alldelayed)) { + my $reqfile = "$path/$dfname"; + my ($host_id) = ($dfname =~ /\.([^.]*)$/); + Debug(4, "queueing ".$reqfile." for $host_id"); my $Handle = IO::File->new($reqfile); my $cmd = <$Handle>; chomp $cmd; # There may or may not be a newline... $cmd = $cmd."\n"; # now for sure there's exactly one newline. - my $Transaction = LondTransaction->new($cmd); + my $Transaction = LondTransaction->new("sethost:$host_id:$cmd"); $Transaction->SetDeferred($reqfile); QueueTransaction($Transaction); } @@ -1193,7 +1203,8 @@ sub MakeLondConnection { .GetServerPort()); my $Connection = LondConnection->new(&GetServerHost(), - &GetServerPort()); + &GetServerPort(), + &GetHostId()); if($Connection eq undef) { # Needs to be more robust later. Log("CRITICAL","Failed to make a connection with lond."); @@ -1201,6 +1212,7 @@ sub MakeLondConnection { return 0; # Failure. } else { + $LondConnecting = 1; # Connection in progress. # The connection needs to have writability # monitored in order to send the init sequence # that starts the whole authentication/key @@ -1231,7 +1243,6 @@ sub MakeLondConnection { } Log("SUCESS", "Created connection ".$ConnectionCount ." to host ".GetServerHost()); - $LondConnecting = 1; # Connection in progress. return 1; # Return success. } @@ -1372,14 +1383,23 @@ sub ClientRequest { $data = $data.$thisread; # Append new data. $watcher->data($data); if($data =~ /\n$/) { # Request entirely read. - if($data eq "close_connection_exit\n") { + if ($data eq "close_connection_exit\n") { Log("CRITICAL", "Request Close Connection ... exiting"); CloseAllLondConnections(); exit; + } elsif ($data eq "reset_retries\n") { + Log("INFO", "Resetting Connection Retries."); + $ConnectionRetriesLeft = $ConnectionRetries; + &UpdateStatus(); + my $Transaction = LondTransaction->new($data); + $Transaction->SetClient($socket); + StartClientReply($Transaction, "ok\n"); + $watcher->cancel(); + return; } Debug(8, "Complete transaction received: ".$data); - if($LogTransactions) { + if ($LogTransactions) { Log("SUCCESS", "Transaction: '$data'"); # Transaction has \n. } my $Transaction = LondTransaction->new($data); @@ -1394,7 +1414,7 @@ sub ClientRequest { # Accept a connection request for a client (lonc child) and # start up an event watcher to keep an eye on input from that # Event. This can be called both from NewClient and from -# ChildProcess if we are started in DieWhenIdle mode. +# ChildProcess. # Parameters: # $socket - The listener socket. # Returns: @@ -1483,6 +1503,18 @@ sub GetServerHost { =pod +=head2 GetServerId + +Returns the hostid whose lond we talk with. + +=cut + +sub GetHostId { + return $RemoteHostId; # Setup by the fork. +} + +=pod + =head2 GetServerPort Returns the lond port number. @@ -1510,15 +1542,14 @@ another event handler to subess requests =cut sub SetupLoncListener { + my ($host,$SocketName) = @_; + if (!$host) { $host = &GetServerHost(); } + if (!$SocketName) { $SocketName = &GetLoncSocketPath($host); } - my $host = GetServerHost(); # Default host. - if (@_) { - ($host) = @_ # Override host with parameter. - } - my $socket; - my $SocketName = GetLoncSocketPath($host); unlink($SocketName); + + my $socket; unless ($socket =IO::Socket::UNIX->new(Local => $SocketName, Listen => 250, Type => SOCK_STREAM)) { @@ -1558,6 +1589,7 @@ into the status file. We also use this to reset the retries count in order to allow the client to retry connections with a previously dead server. + =cut sub ChildStatus { @@ -1566,26 +1598,31 @@ sub ChildStatus { Debug(2, "Reporting child status because : ".$watcher->data); my $docdir = $perlvar{'lonDocRoot'}; - my $fh = IO::File->new(">>$docdir/lon-status/loncstatus.txt"); - print $fh $$."\t".$RemoteHost."\t".$Status."\t". + + open(LOG,">>$docdir/lon-status/loncstatus.txt"); + flock(LOG,LOCK_EX); + print LOG $$."\t".$RemoteHost."\t".$Status."\t". $RecentLogEntry."\n"; # # Write out information about each of the connections: # if ($DebugLevel > 2) { - print $fh "Active connection statuses: \n"; + print LOG "Active connection statuses: \n"; my $i = 1; print STDERR "================================= Socket Status Dump:\n"; foreach my $item (keys %ActiveConnections) { my $Socket = $ActiveConnections{$item}->data; my $state = $Socket->GetState(); - print $fh "Connection $i State: $state\n"; + print LOG "Connection $i State: $state\n"; print STDERR "---------------------- Connection $i \n"; $Socket->Dump(-1); # Ensure it gets dumped.. $i++; } } + flock(LOG,LOCK_UN); + close(LOG); $ConnectionRetriesLeft = $ConnectionRetries; + UpdateStatus(); } =pod @@ -1606,12 +1643,14 @@ sub SignalledToDeath { chomp($signal); Log("CRITICAL", "Abnormal exit. Child $$ for $RemoteHost " ."died through "."\"$signal\""); - LogPerm("F:lonc: $$ on $RemoteHost signalled to death: " - ."\"$signal\""); + #LogPerm("F:lonc: $$ on $RemoteHost signalled to death: " +# ."\"$signal\""); exit 0; } +=pod + =head2 ToggleDebug This sub toggles trace debugging on and off. @@ -1627,6 +1666,8 @@ sub ToggleDebug { } +=pod + =head2 ChildProcess This sub implements a child process for a single lonc daemon. @@ -1637,7 +1678,7 @@ Optional parameter: =cut sub ChildProcess { - # If we are in DieWhenIdle mode, we've inherited all the + # We've inherited all the # events of our parent and those have to be cancelled or else # all holy bloody chaos will result.. trust me, I already made # >that< mistake. @@ -1705,7 +1746,7 @@ sub ChildProcess { desc => 'Lonc Listener Unix Socket', fd => $socket); - $Event::Debuglevel = $DebugLevel; + $Event::DebugLevel = $DebugLevel; Debug(9, "Making initial lond connection for ".$RemoteHost); @@ -1713,12 +1754,9 @@ sub ChildProcess { # &MakeLondConnection(); // let first work request do it. - # If We are in diwhenidle, need to accept the connection since the - # event may not fire. + # need to accept the connection since the event may not fire. - if ($DieWhenIdle) { - &accept_client($socket); - } + &accept_client($socket); Debug(9,"Entering event loop"); my $ret = Event::loop(); # Start the main event loop. @@ -1730,7 +1768,7 @@ sub ChildProcess { # Create a new child for host passed in: sub CreateChild { - my ($host, $socket) = @_; + my ($host, $hostid) = @_; my $sigset = POSIX::SigSet->new(SIGINT); sigprocmask(SIG_BLOCK, $sigset); @@ -1739,19 +1777,15 @@ sub CreateChild { my $pid = fork; if($pid) { # Parent $RemoteHost = "Parent"; - $ChildHash{$pid} = $host; - $HostToPid{$host}= $pid; + $ChildPid{$pid} = $host; sigprocmask(SIG_UNBLOCK, $sigset); - + undef(@all_host_ids); } else { # child. + $RemoteHostId = $hostid; ShowStatus("Connected to ".$RemoteHost); $SIG{INT} = 'DEFAULT'; sigprocmask(SIG_UNBLOCK, $sigset); - if(defined $socket) { - &ChildProcess($socket); - } else { - ChildProcess; # Does not return. - } + &ChildProcess(); # Does not return. } } @@ -1779,25 +1813,50 @@ sub parent_client_connection { my ($event) = @_; my $watcher = $event->w; my $socket = $watcher->fd; - - # Lookup the host associated with this socket: - - my $host = $listening_to{$socket}; - - # Start the child: - - - - &Debug(9,"Creating child for $host (parent_client_connection)"); - &CreateChild($host, $socket); - - # Clean up the listen since now the child takes over until it exits. - - $watcher->cancel(); # Nolonger listening to this event - delete($listening_to{$socket}); - delete($parent_dispatchers{$host}); - $socket->close(); + my $connection = $socket->accept(); # Accept the client connection. + Event->io(cb => \&get_remote_hostname, + poll => 'r', + data => "", + fd => $connection); + } +} + +sub get_remote_hostname { + my ($event) = @_; + my $watcher = $event->w; + my $socket = $watcher->fd; + + my $thisread; + my $rv = $socket->recv($thisread, POSIX::BUFSIZ, 0); + Debug(8, "rcv: data length = ".length($thisread)." read =".$thisread); + if (!defined($rv) || length($thisread) == 0) { + # Likely eof on socket. + Debug(5,"Client Socket closed on lonc for p_c_c"); + close($socket); + $watcher->cancel(); + return; } + + my $data = $watcher->data().$thisread; + $watcher->data($data); + if($data =~ /\n$/) { # Request entirely read. + chomp($data); + } else { + return; + } + + &Debug(5,"Creating child for $data (parent_client_connection)"); + (my $hostname,my $lonid,@all_host_ids) = split(':',$data); + $ChildHost{$hostname}++; + if ($ChildHost{$hostname} == 1) { + &CreateChild($hostname,$lonid); + } else { + &Log('WARNING',"Request for a second child on $hostname"); + } + # Clean up the listen since now the child takes over until it exits. + $watcher->cancel(); # Nolonger listening to this event + $socket->send("done\n"); + $socket->close(); } # parent_listen: @@ -1819,32 +1878,50 @@ sub parent_listen { my ($loncapa_host) = @_; Debug(5, "parent_listen: $loncapa_host"); - my $socket = &SetupLoncListener($loncapa_host); + my ($socket,$file); + if (!$loncapa_host) { + $loncapa_host = 'common_parent'; + $file = $perlvar{'lonSockCreate'}; + } else { + $file = &GetLoncSocketPath($loncapa_host); + } + $socket = &SetupLoncListener($loncapa_host,$file); + $listening_to{$socket} = $loncapa_host; if (!$socket) { die "Unable to create a listen socket for $loncapa_host"; } - my $lock_file = &GetLoncSocketPath($loncapa_host).".lock"; + my $lock_file = $file.".lock"; unlink($lock_file); # No problem if it doesn't exist yet [startup e.g.] - my $watcher = Event->io(cb => \&parent_client_connection, - poll => 'r', - desc => "Parent listener unix socket ($loncapa_host)", - fd => $socket); + my $watcher = + Event->io(cb => \&parent_client_connection, + poll => 'r', + desc => "Parent listener unix socket ($loncapa_host)", + data => "", + fd => $socket); $parent_dispatchers{$loncapa_host} = $watcher; } +sub parent_clean_up { + my ($loncapa_host) = @_; + Debug(1, "parent_clean_up: $loncapa_host"); + + my $socket_file = &GetLoncSocketPath($loncapa_host); + unlink($socket_file); # No problem if it doesn't exist yet [startup e.g.] + my $lock_file = $socket_file.".lock"; + unlink($lock_file); # No problem if it doesn't exist yet [startup e.g.] +} + + -# listen_on_all_unix_sockets: -# This sub initiates a listen on all unix domain lonc client sockets. -# This will be called in the case where we are trimming idle processes. -# When idle processes are trimmed, loncnew starts up with no children, -# and only spawns off children when a connection request occurs on the -# client unix socket. The spawned child continues to run until it has -# been idle a while at which point it eventually exits and once more -# the parent picks up the listen. +# This sub initiates a listen on the common unix domain lonc client socket. +# loncnew starts up with no children, and only spawns off children when a +# connection request occurs on the common client unix socket. The spawned +# child continues to run until it has been idle a while at which point it +# eventually exits and once more the parent picks up the listen. # # Parameters: # NONE @@ -1853,16 +1930,9 @@ sub parent_listen { # Returns: # NONE # -sub listen_on_all_unix_sockets { - Debug(5, "listen_on_all_unix_sockets"); - my $host_iterator = &LondConnection::GetHostIterator(); - while (!$host_iterator->end()) { - my $host_entry_ref = $host_iterator->get(); - my $host_name = $host_entry_ref->[0]; - Debug(9, "Listen for $host_name"); - &parent_listen($host_name); - $host_iterator->next(); - } +sub listen_on_common_socket { + Debug(5, "listen_on_common_socket"); + &parent_listen(); } # server_died is called whenever a child process exits. @@ -1884,12 +1954,12 @@ sub server_died { } # need the host to restart: - my $host = $ChildHash{$pid}; + my $host = $ChildPid{$pid}; if($host) { # It's for real... &Debug(9, "Caught sigchild for $host"); - delete($ChildHash{$pid}); - delete($HostToPid{$host}); - &parent_listen($host); + delete($ChildPid{$pid}); + delete($ChildHost{$host}); + &parent_clean_up($host); } else { &Debug(5, "Caught sigchild for pid not in hosts hash: $pid"); @@ -1946,21 +2016,9 @@ ShowStatus("Forking node servers"); Log("CRITICAL", "--------------- Starting children ---------------"); LondConnection::ReadConfig; # Read standard config files. -my $HostIterator = LondConnection::GetHostIterator; -if ($DieWhenIdle) { - $RemoteHost = "[parent]"; - &listen_on_all_unix_sockets(); -} else { - - while (! $HostIterator->end()) { - - my $hostentryref = $HostIterator->get(); - CreateChild($hostentryref->[0]); - $HostHash{$hostentryref->[0]} = $hostentryref->[4]; - $HostIterator->next(); - } -} +$RemoteHost = "[parent]"; +&listen_on_common_socket(); $RemoteHost = "Parent Server"; @@ -1969,68 +2027,38 @@ $RemoteHost = "Parent Server"; ShowStatus("Parent keeping the flock"); -if ($DieWhenIdle) { - # We need to setup a SIGChild event to handle the exit (natural or otherwise) - # of the children. - - Event->signal(cb => \&server_died, - desc => "Child exit handler", - signal => "CHLD"); - - - # Set up all the other signals we set up. We'll vector them off to the - # same subs as we would for DieWhenIdle false and, if necessary, conditionalize - # the code there. - - $parent_handlers{INT} = Event->signal(cb => \&Terminate, - desc => "Parent INT handler", - signal => "INT"); - $parent_handlers{TERM} = Event->signal(cb => \&Terminate, - desc => "Parent TERM handler", - signal => "TERM"); - $parent_handlers{HUP} = Event->signal(cb => \&Restart, - desc => "Parent HUP handler.", - signal => "HUP"); - $parent_handlers{USR1} = Event->signal(cb => \&CheckKids, - desc => "Parent USR1 handler", - signal => "USR1"); - $parent_handlers{USR2} = Event->signal(cb => \&UpdateKids, - desc => "Parent USR2 handler.", - signal => "USR2"); - - # Start procdesing events. - - $Event::DebugLevel = $DebugLevel; - Debug(9, "Parent entering event loop"); - my $ret = Event::loop(); - die "Main Event loop exited: $ret"; - - -} else { - # - # Set up parent signals: - # - - $SIG{INT} = \&Terminate; - $SIG{TERM} = \&Terminate; - $SIG{HUP} = \&Restart; - $SIG{USR1} = \&CheckKids; - $SIG{USR2} = \&UpdateKids; # LonManage update request. - - while(1) { - my $deadchild = wait(); - if(exists $ChildHash{$deadchild}) { # need to restart. - my $deadhost = $ChildHash{$deadchild}; - delete($HostToPid{$deadhost}); - delete($ChildHash{$deadchild}); - Log("WARNING","Lost child pid= ".$deadchild. - "Connected to host ".$deadhost); - Log("INFO", "Restarting child procesing ".$deadhost); - CreateChild($deadhost); - } - } -} +# We need to setup a SIGChild event to handle the exit (natural or otherwise) +# of the children. +Event->signal(cb => \&server_died, + desc => "Child exit handler", + signal => "CHLD"); + + +# Set up all the other signals we set up. + +$parent_handlers{INT} = Event->signal(cb => \&Terminate, + desc => "Parent INT handler", + signal => "INT"); +$parent_handlers{TERM} = Event->signal(cb => \&Terminate, + desc => "Parent TERM handler", + signal => "TERM"); +$parent_handlers{HUP} = Event->signal(cb => \&KillThemAll, + desc => "Parent HUP handler.", + signal => "HUP"); +$parent_handlers{USR1} = Event->signal(cb => \&CheckKids, + desc => "Parent USR1 handler", + signal => "USR1"); +$parent_handlers{USR2} = Event->signal(cb => \&UpdateKids, + desc => "Parent USR2 handler.", + signal => "USR2"); + +# Start procdesing events. + +$Event::DebugLevel = $DebugLevel; +Debug(9, "Parent entering event loop"); +my $ret = Event::loop(); +die "Main Event loop exited: $ret"; =pod @@ -2054,10 +2082,9 @@ sub CheckKids { foreach my $host (keys %parent_dispatchers) { print $fh "LONC Parent process listening for $host\n"; } - foreach my $pid (keys %ChildHash) { + foreach my $pid (keys %ChildPid) { Debug(2, "Sending USR1 -> $pid"); kill 'USR1' => $pid; # Tell Child to report status. - sleep 1; # Wait so file doesn't intermix. } } @@ -2099,8 +2126,7 @@ sub UpdateKids { # The down side is transactions that are in flight will get timed out # (lost unless they are critical). - &Restart(); - + &KillThemAll(); } @@ -2133,15 +2159,19 @@ SIGHUP. Responds to sigint and sigterm. sub KillThemAll { Debug(2, "Kill them all!!"); - local($SIG{CHLD}) = 'IGNORE'; # Our children >will< die. - foreach my $pid (keys %ChildHash) { - my $serving = $ChildHash{$pid}; + + #local($SIG{CHLD}) = 'IGNORE'; + # Our children >will< die. + # but we need to catch their death and cleanup after them in case this is + # a restart set of kills + my @allpids = keys(%ChildPid); + foreach my $pid (@allpids) { + my $serving = $ChildPid{$pid}; ShowStatus("Nicely Killing lonc for $serving pid = $pid"); Log("CRITICAL", "Nicely Killing lonc for $serving pid = $pid"); kill 'QUIT' => $pid; } - - + ShowStatus("Finished killing child processes off."); } @@ -2153,16 +2183,17 @@ sub really_kill_them_all_dammit { Debug(2, "Kill them all Dammit"); local($SIG{CHLD} = 'IGNORE'); # In case some purist reenabled them. - foreach my $pid (keys %ChildHash) { - my $serving = $ChildHash{$pid}; + foreach my $pid (keys %ChildPid) { + my $serving = $ChildPid{$pid}; &ShowStatus("Nastily killing lonc for $serving pid = $pid"); Log("CRITICAL", "Nastily killing lonc for $serving pid = $pid"); kill 'KILL' => $pid; - delete($ChildHash{$pid}); + delete($ChildPid{$pid}); my $execdir = $perlvar{'lonDaemons'}; unlink("$execdir/logs/lonc.pid"); } } + =pod =head1 Terminate @@ -2185,6 +2216,14 @@ sub Terminate { exit 0; } + +sub my_hostname { + use Sys::Hostname; + my $name = &hostname(); + &Debug(9,"Name is $name"); + return $name; +} + =pod =head1 Theory 500 Internal Server Error

Internal Server Error

The server encountered an internal error or misconfiguration and was unable to complete your request.

Please contact the server administrator at root@localhost to inform them of the time this error occurred, and the actions you performed just before this error.

More information about this error may be available in the server error log.