Diff for /loncom/lonmaxima between versions 1.17 and 1.39

version 1.17, 2006/03/09 21:38:26 version 1.39, 2008/08/19 10:59:10
Line 31 Line 31
 #  #
   
 use Expect;   use Expect; 
 use IPC::Open3;  
 use IO::Select;  use IO::Select;
 use IO::Socket;  use IO::Socket;
 use IO::File;  use IO::File;
Line 45  use strict; Line 44  use strict;
 # global variables  # global variables
 my $PREFORK                = 5;        # number of children to maintain  my $PREFORK                = 5;        # number of children to maintain
 my $MAX_CLIENTS_PER_CHILD  = 50;       # number of clients each child should process  my $MAX_CLIENTS_PER_CHILD  = 50;       # number of clients each child should process
   my $extra_children         = 0;
 my %children               = ();       # keys are current child process IDs  my %children               = ();       # keys are current child process IDs
 my $children               = 0;        # current number of children  my $children               = 0;        # current number of children
 my $status;                            # string for current status  my $status;                            # string for current status
Line 52  my $pidfile;                           # Line 52  my $pidfile;                           #
 my $port;                              # path to UNIX socket file  my $port;                              # path to UNIX socket file
 my %perlvar;                           # configuration file info  my %perlvar;                           # configuration file info
 my $lastlog;                           # last string that was logged  my $lastlog;                           # last string that was logged
   
 use vars qw($PREFORK $MAX_CLIENTS_PER_CHILD %children $children $status  use vars qw($PREFORK $MAX_CLIENTS_PER_CHILD %children $children $status
     $pidfile $port %perlvar $lastlog);      $pidfile $port %perlvar $lastlog);
     
Line 60  sub REAPER {                        # ta Line 61  sub REAPER {                        # ta
                                     # and MAXIMA processes                                      # and MAXIMA processes
     $SIG{CHLD} = \&REAPER;      $SIG{CHLD} = \&REAPER;
     my $pid = wait;      my $pid = wait;
     $children--;      if (exists($children{$pid})) {
     delete($children{$pid});   $children--;
    delete($children{$pid});
    if ($extra_children) {
       $extra_children--;
    }
       }    
 }  }
     
 sub HUNTSMAN {                      # signal handler for SIGINT  sub HUNTSMAN {                      # signal handler for SIGINT
Line 126  sub catchexception { Line 132  sub catchexception {
 }  }
   
   
   sub child_announce_death {
       $SIG{USR1} = \&child_announce_death;
       if ($extra_children < $PREFORK*10) {
    $extra_children++;
       }
   }
   
 # ---------------------------------------------------------------- Main program  # ---------------------------------------------------------------- Main program
 # -------------------------------- Set signal handlers to record abnormal exits  # -------------------------------- Set signal handlers to record abnormal exits
Line 133  sub catchexception { Line 145  sub catchexception {
     
 $SIG{'QUIT'}=\&catchexception;  $SIG{'QUIT'}=\&catchexception;
 $SIG{__DIE__}=\&catchexception;  $SIG{__DIE__}=\&catchexception;
   $SIG{USR1} = \&child_announce_death;
     
 # ---------------------------------- Read loncapa_apache.conf and loncapa.conf  # ---------------------------------- Read loncapa_apache.conf and loncapa.conf
 &status("Read loncapa.conf and loncapa_apache.conf");  &status("Read loncapa.conf and loncapa_apache.conf");
Line 212  for (1 .. $PREFORK) { Line 225  for (1 .. $PREFORK) {
 while (1) {  while (1) {
     &status('Parent process, sleeping');      &status('Parent process, sleeping');
     sleep;                          # wait for a signal (i.e., child's death)      sleep;                          # wait for a signal (i.e., child's death)
     for (my $i = $children; $i < $PREFORK; $i++) {      for (my $i = $children; $i < $PREFORK+$extra_children; $i++) {
         &status('Parent process, starting child');          &status('Parent process, starting child');
         &make_new_child($server);           # top up the child pool          &make_new_child($server);           # top up the child pool
     }      }
Line 237  sub make_new_child { Line 250  sub make_new_child {
         return;          return;
     } else {      } else {
         # Child can *not* return from this subroutine.          # Child can *not* return from this subroutine.
         $SIG{INT} = 'DEFAULT';      # make SIGINT kill us as it did before          
    my $ppid = getppid();
             
         # unblock signals          # unblock signals
         sigprocmask(SIG_UNBLOCK, $sigset)          sigprocmask(SIG_UNBLOCK, $sigset)
Line 246  sub make_new_child { Line 260  sub make_new_child {
         &logthis('New process started');          &logthis('New process started');
   
         my $command=Expect->spawn('maxima');          my $command=Expect->spawn('maxima');
         $command->log_stdout(0);   # soft/hard_close can take awhile and we really
           # don't care we just want it gone
    $SIG{INT} = sub {
       my $pid = $command->pid();
       kill('KILL'=>$pid);
       exit; 
    };
   
         &getmaximaoutput($command);   $command->log_stdout(0);
    #$command->log_file("$execdir/logs/lonmaxima.session.log");
   
         for (my $i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) {          for (my $i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) {
            &status('Accepting connections');              &status('Accepting connections');
            my $client = $server->accept()     or last;              my $client = $server->accept()     or last;
            print $command "kill(all);reset();\n";              &sync($command);
            &getmaximaoutput($command);              print $command ("display2d:false;simp:true;kill(all);\n");
            while (my $cmd=<$client>) {      &getmaximaoutput($command,2);
               &status('Processing command');              &sync($command);
               print $command &unescape($cmd);              my $syntaxerr = 0;
               my $reply=&getmaximaoutput($command);              while (my $cmd=<$client>) {
               print $client &escape($reply)."\n";                  &status('Processing command');
               if ($reply=~/^Error\:/) {                  print $command &unescape($cmd);
                  &logthis('Died through '.$reply);                  my ($reply,$syntaxerr) = &getmaximaoutput($command,1);
                  $client->close();                  print $client &escape($reply)."\n";
                  $command->hard_close();                       if ($syntaxerr) {
                  exit;                      last;
               }                  } elsif ($reply=~/^Error\:/) {
               &status('Waiting for commands');                      &logthis('Died through '.$reply);
            }      kill('USR1' => $ppid);
                       $client->close();
                       $command->hard_close();     
                       exit;
                   }
           &sync($command);
                   &status('Waiting for commands');
               }
         }          }
   
    kill('USR1' => $ppid);
    print $command ("quit();\n");
         # tidy up gracefully and finish          # tidy up gracefully and finish
    sleep(15);
         $command->soft_close();          $command->soft_close();
   
         # this exit is VERY important, otherwise the child will become          # this exit is VERY important, otherwise the child will become
Line 281  sub make_new_child { Line 311  sub make_new_child {
     }      }
 }  }
   
   {
       my $counter;
       sub sync {
    my ($command)=@_;
    $counter++;
    my $expect=$counter.time;
    print $command "$expect;\n";
    while (1) {
       my $output=&getmaximaoutput($command,1);
       if (($output=~/\Q$expect\E/) || ($output=~/^Error\:/)) {
    return;
       }
    }
       }
   }
   
 sub getmaximaoutput {  sub getmaximaoutput {
     my ($command)=@_;      my ($command,$numcheck)=@_;
     my (undef,$error,undef,$output)=$command->expect(20, -re => '\(\%i\d+\)');      my $regexp = '\(\%i\d+\)';
       my $syntaxerr=0;
       if ($numcheck) {
           if ($numcheck eq 2) {
       # command was the killall so should get a full reset on
       # command numbers
       $regexp = '(\(\%i(1)\)|Incorrect syntax\:)';
    } elsif ($command->match() =~ /\(\%i(\d+)\)/) {
               my $nextmatch = $1+1;
               $regexp = '(\(\%i'.$nextmatch.'\)|Incorrect syntax\:)';
           }
       }
       my $timeout = 20;
       my (undef,$error,$matched,$output) =
    $command->expect($timeout, -re => $regexp);
   
       if ($numcheck && $matched eq 'Incorrect syntax:') {
    $syntaxerr = 1;
    if (wantarray) {
       return ($matched,$syntaxerr);
    } else {
       return $matched;
    }
       }
     if ($error) {      if ($error) {
        return 'Error: '.$error;   return 'Error: '.$error;
     }      }
       $output =~ s/\r+//g; # Remove Windows-style linebreaks
     my $foundoutput=0;      my $foundoutput=0;
       my $found_label=0;
     my $realoutput='';      my $realoutput='';
     foreach my $line (split(/\n/,$output)) {      foreach my $line (split(/\n/,$output)) {
        if ($line=~/\;/) { $foundoutput=1; next; }         if ($line=~/\;/) { $foundoutput=1; next; }
        if (!$foundoutput) { next; }         if (!$foundoutput) { next; }
        my ($label)=($line=~s/^(\(\%o\d+\))//);         if ($line=~/^Incorrect syntax:/) { $syntaxerr = 1; next; }
        if ($label) {         if ($line=~ /^(\(\%o\d+\))(.+)$/){
           $label=~s/\S/ /g;             my $label = $1;
           $line=$label.$line;             $line = $2;
              $label =~s/\S/ /g;
              $line=$label.$line;
      $found_label=1;
        }         }
        $realoutput.=$line."\n";         if ($found_label) {
      $realoutput.=$line."\n";
          }
       }
       if (wantarray) {
           return ($realoutput,$syntaxerr);
       } else {
           return $realoutput;
     }      }
     return $realoutput;  
 }  }

Removed from v.1.17  
changed lines
  Added in v.1.39


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>
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.