Diff for /loncom/loncnew between versions 1.59 and 1.65

version 1.59, 2004/09/22 10:46:06 version 1.65, 2004/10/05 11:16:57
Line 75  my %perlvar    = %{$perlvarref}; Line 75  my %perlvar    = %{$perlvarref};
 my %ChildHash; # by pid -> host.  my %ChildHash; # by pid -> host.
 my %HostToPid; # By host -> pid.  my %HostToPid; # By host -> pid.
 my %HostHash; # by loncapaname -> IP.  my %HostHash; # by loncapaname -> IP.
   my %listening_to; # Socket->host table for who the parent
                                   # is listening to.
   my %parent_dispatchers;         # host-> listener watcher events. 
   
   my %parent_handlers; # Parent signal handlers...
   
 my $MaxConnectionCount = 10; # Will get from config later.  my $MaxConnectionCount = 10; # Will get from config later.
 my $ClientConnection = 0; # Uniquifier for client events.  my $ClientConnection = 0; # Uniquifier for client events.
Line 85  my $NextDebugLevel= 2;  # So Sigint can Line 89  my $NextDebugLevel= 2;  # So Sigint can
 my $IdleTimeout= 600; # Wait 10 minutes before pruning connections.  my $IdleTimeout= 600; # Wait 10 minutes before pruning connections.
   
 my $LogTransactions = 0; # When True, all transactions/replies get logged.  my $LogTransactions = 0; # When True, all transactions/replies get logged.
   my $executable      = $0; # Get the full path to me.
   
 #  #
 #  The variables below are only used by the child processes.  #  The variables below are only used by the child processes.
Line 106  my $LondVersion     = "unknown"; # Versi Line 111  my $LondVersion     = "unknown"; # Versi
 my $KeyMode         = "";       # e.g. ssl, local, insecure from last connect.  my $KeyMode         = "";       # e.g. ssl, local, insecure from last connect.
 my $LondConnecting  = 0;       # True when a connection is being built.  my $LondConnecting  = 0;       # True when a connection is being built.
   
 my $DieWhenIdle     = 0; # When true children die when trimmed -> 0.  
   
   my $DieWhenIdle     = 1; # When true children die when trimmed -> 0.
   my $I_am_child      = 0; # True if this is the child process.
   
 #  #
 #   The hash below gives the HTML format for log messages  #   The hash below gives the HTML format for log messages
Line 296  sub SocketTimeout { Line 304  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.
   # Parameters:
   #     exit_code           - Exit status value, however see the next parameter.
   #     message             - If this optional parameter is supplied, the exit
   #                           is via a die with this message.
   #
   sub child_exit {
       my ($exit_code, $message) = @_;
   
       # 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:
   
       if($message) {
    die $message;
       } else {
    exit($exit_code);
       }
   }
 #----------------------------- Timer management ------------------------  #----------------------------- Timer management ------------------------
   
 =pod  =pod
Line 326  sub Tick { Line 372  sub Tick {
     $IdleSeconds = 0; # Otherwise all connections get trimmed to fast.      $IdleSeconds = 0; # Otherwise all connections get trimmed to fast.
     UpdateStatus();      UpdateStatus();
     if(($ConnectionCount == 0) && $DieWhenIdle) {      if(($ConnectionCount == 0) && $DieWhenIdle) {
  #   &child_exit(0);
  #  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);  
     }      }
  }   }
     } else {      } else {
Line 1171  sub MakeLondConnection { Line 1207  sub MakeLondConnection {
  #   #
  my $Socket = $Connection->GetSocket();   my $Socket = $Connection->GetSocket();
  if($Socket eq undef) {   if($Socket eq undef) {
     die "did not get a socket from the connection";      &child_exit(-1, "did not get a socket from the connection");
  } else {   } else {
     &Debug(9,"MakeLondConnection got socket: ".$Socket);      &Debug(9,"MakeLondConnection got socket: ".$Socket);
  }   }
Line 1353  sub ClientRequest { Line 1389  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.
   # Parameters:
   #    $socket       - The listener socket.
   # Returns:
   #   NONE
   # Side Effects:
   #    An event is made to watch the accepted connection.
   #    Active clients hash is updated to reflect the new connection.
   #    The client connection count is incremented.
   #
   sub accept_client {
       my ($socket) = @_;
   
       Debug(8, "Entering accept for lonc UNIX socket\n");
       my $connection = $socket->accept(); # Accept the client connection.
       Debug(8,"Connection request accepted from "
     .GetPeername($connection, AF_UNIX));
   
   
       my $description = sprintf("Connection to lonc client %d",
         $ClientConnection);
       Debug(9, "Creating event named: ".$description);
       Event->io(cb      => \&ClientRequest,
         poll    => 'r',
         desc    => $description,
         data    => "",
         fd      => $connection);
       $ActiveClients{$connection} = $ClientConnection;
       $ClientConnection++;
   }
   
 =pod  =pod
   
Line 1371  sub NewClient { Line 1441  sub NewClient {
     my $event      = shift; # Get the event parameters.      my $event      = shift; # Get the event parameters.
     my $watcher    = $event->w;       my $watcher    = $event->w; 
     my $socket     = $watcher->fd; # Get the event' socket.      my $socket     = $watcher->fd; # Get the event' socket.
     my $connection = $socket->accept(); # Accept the client connection.  
     Debug(8,"Connection request accepted from "  
   .GetPeername($connection, AF_UNIX));  
   
   
     my $description = sprintf("Connection to lonc client %d",      &accept_client($socket);
       $ClientConnection);  
     Debug(9, "Creating event named: ".$description);  
     Event->io(cb      => \&ClientRequest,  
       poll    => 'r',  
       desc    => $description,  
       data    => "",  
       fd      => $connection);  
     $ActiveClients{$connection} = $ClientConnection;  
     $ClientConnection++;  
 }  }
   
 =pod  =pod
Line 1464  sub SetupLoncListener { Line 1521  sub SetupLoncListener {
     unless ($socket =IO::Socket::UNIX->new(Local  => $SocketName,      unless ($socket =IO::Socket::UNIX->new(Local  => $SocketName,
     Listen => 250,       Listen => 250, 
     Type   => SOCK_STREAM)) {      Type   => SOCK_STREAM)) {
  die "Failed to create a lonc listner socket";   if($I_am_child) {
       &child_exit(-1, "Failed to create a lonc listener socket");
    } else {
       die "Failed to create a lonc listner socket";
    }
     }      }
     return $socket;      return $socket;
 }  }
Line 1568  sub ToggleDebug { Line 1629  sub ToggleDebug {
 =head2 ChildProcess  =head2 ChildProcess
   
 This sub implements a child process for a single lonc daemon.  This sub implements a child process for a single lonc daemon.
   Optional parameter:
      $socket  - if provided, this is a socket already open for listen
                 on the client socket. Otherwise, a new listen is set up.
   
 =cut  =cut
   
 sub ChildProcess {  sub ChildProcess {
       #  If we are in DieWhenIdle mode, 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.
   
       my $host = GetServerHost();
       foreach my $listener (keys %parent_dispatchers) {
    my $watcher = $parent_dispatchers{$listener};
    my $s       = $watcher->fd;
    if ($listener ne $host) { # Close everyone but me.
       Debug(5, "Closing listen socket for $listener");
       $s->close();
    }
    Debug(5, "Killing watcher for $listener");
   
    $watcher->cancel();
    delete($parent_dispatchers{$listener});
   
       }
   
       #  kill off the parent's signal handlers too!  
       #
   
       for my $handler (keys %parent_handlers) {
    my $watcher = $parent_handlers{$handler};
    $watcher->cancel();
    delete($parent_handlers{$handler});
       }
   
       $I_am_child    = 1; # Seems like in spite of it all I may still getting
                                   # parent event dispatches.. flag I'm a child.
   
   
     #      #
     #  Signals must be handled by the Event framework...      #  Signals must be handled by the Event framework...
 #      #
   
     Event->signal(signal   => "QUIT",      Event->signal(signal   => "QUIT",
   cb       => \&SignalledToDeath,    cb       => \&SignalledToDeath,
Line 1593  sub ChildProcess { Line 1688  sub ChildProcess {
   cb       => \&ToggleDebug,    cb       => \&ToggleDebug,
   data     => "INT");    data     => "INT");
   
           #  Figure out if we got passed a socket or need to open one to listen for
     my $socket =  SetupLoncListener();      #  client requests.
   
       my ($socket) = @_;
       if (!$socket) {
   
    $socket =  SetupLoncListener();
       }
       #  Establish an event to listen for client connection requests.
   
   
     Event->io(cb   => \&NewClient,      Event->io(cb   => \&NewClient,
       poll => 'r',        poll => 'r',
       desc => 'Lonc Listener Unix Socket',        desc => 'Lonc Listener Unix Socket',
Line 1606  sub ChildProcess { Line 1710  sub ChildProcess {
   
 # Setup the initial server connection:  # Setup the initial server connection:
           
      # &MakeLondConnection(); // let first work requirest do it.       # &MakeLondConnection(); // let first work request do it.
   
       #  If We are in diwhenidle, need to accept the connection since the
       #  event may  not fire.
   
       if ($DieWhenIdle) {
    &accept_client($socket);
       }
   
     Debug(9,"Entering event loop");      Debug(9,"Entering event loop");
     my $ret = Event::loop(); #  Start the main event loop.      my $ret = Event::loop(); #  Start the main event loop.
           
           
     die "Main event loop exited!!!";      &child_exit (-1,"Main event loop exited!!!");
 }  }
   
 #  Create a new child for host passed in:  #  Create a new child for host passed in:
   
 sub CreateChild {  sub CreateChild {
     my $host = shift;      my ($host, $socket) = @_;
   
     my $sigset = POSIX::SigSet->new(SIGINT);      my $sigset = POSIX::SigSet->new(SIGINT);
     sigprocmask(SIG_BLOCK, $sigset);      sigprocmask(SIG_BLOCK, $sigset);
Line 1636  sub CreateChild { Line 1746  sub CreateChild {
  ShowStatus("Connected to ".$RemoteHost);   ShowStatus("Connected to ".$RemoteHost);
  $SIG{INT} = 'DEFAULT';   $SIG{INT} = 'DEFAULT';
  sigprocmask(SIG_UNBLOCK, $sigset);   sigprocmask(SIG_UNBLOCK, $sigset);
  ChildProcess; # Does not return.   if(defined $socket) {
       &ChildProcess($socket);
    } else {
       ChildProcess; # Does not return.
    }
       }
   }
   
   # parent_client_connection:
   #    Event handler that processes client connections for the parent process.
   #    This sub is called when the parent is listening on a socket and
   #    a connection request arrives.  We must:
   #     Start a child process to accept the connection request.
   #     Kill our listen on the socket.
   # Parameter:
   #    event       - The event object that was created to monitor this socket.
   #                  event->w->fd is the socket.
   # Returns:
   #    NONE
   #
   sub parent_client_connection {
       if ($I_am_child) {
    #  Should not get here, but seem to anyway:
    &Debug(5," Child caught parent client connection event!!");
    my ($event) = @_;
    my $watcher = $event->w;
    $watcher->cancel(); # Try to kill it off again!!
       } else {
    &Debug(9, "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();
       }
   }
   
   # parent_listen:
   #    Opens a socket and starts a listen for the parent process on a client UNIX
   #    domain socket.
   #
   #    This involves:
   #       Creating a socket for listen.
   #       Removing any socket lock file
   #       Adding an event handler for this socket becoming readable
   #         To the parent's event dispatcher.
   # Parameters:
   #    loncapa_host    - LonCAPA cluster name of the host represented by the client
   #                      socket.
   # Returns:
   #    NONE
   #
   sub parent_listen {
       my ($loncapa_host) = @_;
       Debug(5, "parent_listen: $loncapa_host");
   
       my $socket    = &SetupLoncListener($loncapa_host);
       $listening_to{$socket} = $loncapa_host;
       if (!$socket) {
    die "Unable to create a listen socket for $loncapa_host";
     }      }
       
       my $lock_file = &GetLoncSocketPath($loncapa_host).".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);
       $parent_dispatchers{$loncapa_host} = $watcher;
   
   }
   
   
   # 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.
   #
   #  Parameters:
   #      NONE
   #  Implicit Inputs:
   #    The configuration file that has been read in by LondConnection.
   #  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();
       }
 }  }
   
   #   server_died is called whenever a child process exits.
   #   Since this is dispatched via a signal, we must process all
   #   dead children until there are no more left.  The action
   #   is to:
   #      - Remove the child from the bookeeping hashes
   #      - Re-establish a listen on the unix domain socket associated
   #        with that host.
   # Parameters:
   #    The event, but we don't actually care about it.
   sub server_died {
       &Debug(9, "server_died called...");
       
       while(1) { # Loop until waitpid nowait fails.
    my $pid = waitpid(-1, WNOHANG);
    if($pid <= 0) {
       return; # Nothing left to wait for.
    }
    # need the host to restart:
   
    my $host = $ChildHash{$pid};
    if($host) { # It's for real...
       &Debug(9, "Caught sigchild for $host");
       delete($ChildHash{$pid});
       delete($HostToPid{$host});
       &parent_listen($host);
   
    } else {
       &Debug(5, "Caught sigchild for pid not in hosts hash: $pid");
    }
       }
   
   }
   
 #  #
 #  Parent process logic pass 1:  #  Parent process logic pass 1:
 #   For each entry in the hosts table, we will  #   For each entry in the hosts table, we will
Line 1689  Log("CRITICAL", "--------------- Startin Line 1946  Log("CRITICAL", "--------------- Startin
   
 LondConnection::ReadConfig;               # Read standard config files.  LondConnection::ReadConfig;               # Read standard config files.
 my $HostIterator = LondConnection::GetHostIterator;  my $HostIterator = LondConnection::GetHostIterator;
 while (! $HostIterator->end()) {  
   
     my $hostentryref = $HostIterator->get();  if ($DieWhenIdle) {
     CreateChild($hostentryref->[0]);      $RemoteHost = "[parent]";
     $HostHash{$hostentryref->[0]} = $hostentryref->[4];      &listen_on_all_unix_sockets();
     $HostIterator->next();  } else {
       
       while (! $HostIterator->end()) {
   
    my $hostentryref = $HostIterator->get();
    CreateChild($hostentryref->[0]);
    $HostHash{$hostentryref->[0]} = $hostentryref->[4];
    $HostIterator->next();
       }
 }  }
   
 $RemoteHost = "Parent Server";  $RemoteHost = "Parent Server";
   
 # Maintain the population:  # Maintain the population:
   
 ShowStatus("Parent keeping the flock");  ShowStatus("Parent keeping the flock");
   
 #  
 #   Set up parent signals:  
 #  
   
 $SIG{INT}  = \&Terminate;  if ($DieWhenIdle) {
 $SIG{TERM} = \&Terminate;       # We need to setup a SIGChild event to handle the exit (natural or otherwise)
 $SIG{HUP}  = \&Restart;      # of the children.
 $SIG{USR1} = \&CheckKids;   
 $SIG{USR2} = \&UpdateKids; # LonManage update request.      Event->signal(cb       => \&server_died,
      desc     => "Child exit handler",
 while(1) {     signal   => "CHLD");
     my $deadchild = wait();  
     if(exists $ChildHash{$deadchild}) { # need to restart.  
  my $deadhost = $ChildHash{$deadchild};      # Set up all the other signals we set up.  We'll vector them off to the
  delete($HostToPid{$deadhost});      # same subs as we would for DieWhenIdle false and, if necessary, conditionalize
  delete($ChildHash{$deadchild});      # the code there.
  Log("WARNING","Lost child pid= ".$deadchild.  
       "Connected to host ".$deadhost);      $parent_handlers{INT} = Event->signal(cb       => \&Terminate,
  Log("INFO", "Restarting child procesing ".$deadhost);    desc     => "Parent INT handler",
  CreateChild($deadhost);    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);
    }
     }      }
 }  }
   
   
   
 =pod  =pod
   
 =head1 CheckKids  =head1 CheckKids
Line 1746  sub CheckKids { Line 2050  sub CheckKids {
     my $now=time;      my $now=time;
     my $local=localtime($now);      my $local=localtime($now);
     print $fh "LONC status $local - parent $$ \n\n";      print $fh "LONC status $local - parent $$ \n\n";
       foreach my $host (keys %parent_dispatchers) {
    print $fh "LONC Parent process listening for $host\n";
       }
     foreach my $pid (keys %ChildHash) {      foreach my $pid (keys %ChildHash) {
  Debug(2, "Sending USR1 -> $pid");   Debug(2, "Sending USR1 -> $pid");
  kill 'USR1' => $pid; # Tell Child to report status.   kill 'USR1' => $pid; # Tell Child to report status.
  sleep 1; # Wait so file doesn't intermix.   sleep 1; # Wait so file doesn't intermix.
     }      }
   
 }  }
   
 =pod  =pod
Line 1783  sub UpdateKids { Line 2091  sub UpdateKids {
   
     Log("INFO", "Updating connections via SIGUSR2");      Log("INFO", "Updating connections via SIGUSR2");
   
     #  Just in case we need to kill our own lonc, we wait a few seconds to      #  I'm not sure what I was thinking in the first implementation.
     #  give it a chance to receive and relay lond's response to the       # someone will have to work hard to convince me the effect is any
     #  re-init command.      # different than Restart, especially now that we don't start up 
     #      # per host servers automatically, may as well just restart.
       # The down side is transactions that are in flight will get timed out
       # (lost unless they are critical).
   
     sleep(2); # Wait a couple of seconds.      &Restart();
   
     my %hosts;                   # Indexed by loncapa hostname, value=ip.  
       
     # Need to re-read  the host table:  
       
       
     LondConnection::ReadConfig();  
     my $I = LondConnection::GetHostIterator;  
     while (! $I->end()) {  
  my $item = $I->get();  
  $hosts{$item->[0]} = $item->[4];  
  $I->next();  
     }  
   
     #  The logic below is written for clarity not for efficiency.  
     #  Since I anticipate that this function is only rarely called, that's  
     #  appropriate.  There are certainly ways to combine the loops below,  
     #  and anyone wishing to obscure the logic is welcome to go for it.  
     #  Note that we don't re-direct sigchild.  Instead we do what's needed  
     #  to the data structures that keep track of children to ensure that  
     #  when sigchild is honored, no new child is born.  
     #  
   
     #  For each existing child; if it's host doesn't exist, kill the child.  
   
     foreach my $child (keys %ChildHash) {  
  my $oldhost = $ChildHash{$child};  
  if (!(exists $hosts{$oldhost})) {  
     Log("CRITICAL", "Killing child for $oldhost  host no longer exists");  
     delete $ChildHash{$child};  
     delete $HostToPid{$oldhost};  
     kill 'QUIT' => $child;  
  }  
     }  
     # For each remaining existing child; if it's host's ip has changed,  
     # Restart the child on the new IP.  
   
     foreach my $child (keys %ChildHash) {  
  my $oldhost = $ChildHash{$child};  
  my $oldip   = $HostHash{$oldhost};  
  if ($hosts{$oldhost} ne $oldip) {  
   
     # kill the old child.  
   
     Log("CRITICAL", "Killing child for $oldhost host ip has changed...");  
     delete $ChildHash{$child};  
     delete $HostToPid{$oldhost};  
     kill 'QUIT' => $child;  
   
     # Do the book-keeping needed to start a new child on the  
     # new ip.  
   
     $HostHash{$oldhost} = $hosts{$oldhost};  
     CreateChild($oldhost);  
  }  
     }  
     # Finally, for each new host, not in the host hash, create a  
     # enter the host and create a new child.  
     # Force a status display of any existing process.  
   
     foreach my $host (keys %hosts) {  
  if(!(exists $HostHash{$host})) {  
     Log("INFO", "New host $host discovered in hosts.tab...");  
     $HostHash{$host} = $hosts{$host};  
     CreateChild($host);  
  } else {  
     kill 'HUP' => $HostToPid{$host};    # status display.  
  }  
     }  
 }  }
   
   
Line 1876  sub Restart { Line 2118  sub Restart {
     Log("CRITICAL", "Restarting");      Log("CRITICAL", "Restarting");
     my $execdir = $perlvar{'lonDaemons'};      my $execdir = $perlvar{'lonDaemons'};
     unlink("$execdir/logs/lonc.pid");      unlink("$execdir/logs/lonc.pid");
     exec("$execdir/loncnew");      exec("$executable");
 }  }
   
 =pod  =pod

Removed from v.1.59  
changed lines
  Added in v.1.65


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>