--- loncom/lonmaxima 2006/03/08 03:18:42 1.12 +++ loncom/lonmaxima 2006/03/08 15:58:03 1.15 @@ -3,7 +3,7 @@ # The LearningOnline Network with CAPA # Connect to MAXIMA CAS # -# $Id: lonmaxima,v 1.12 2006/03/08 03:18:42 www Exp $ +# $Id: lonmaxima,v 1.15 2006/03/08 15:58:03 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -57,28 +57,13 @@ my $lastlog; # use vars qw($PREFORK $MAX_CLIENTS_PER_CHILD %children $children %usedmaximaports $status $pidfile $port %perlvar $lastlog); -sub maximareply { - my ($cmd,$maximaclient,$maximapid) = @_; - my $reply=''; - while (my $line=<$maximaclient>) { - $reply.=$line; - } - unless ($cmd=~/\;\n$/) { $cmd.=";\n"; } - print $maximaclient $cmd; - &status("Command sent to $maximapid"); - while (my $line=<$maximaclient>) { - $reply.=$line; - } - &status("Command processed by $maximapid"); - return $reply; -} - # ------------------------------------------------------------ Service routines sub REAPER { # takes care of dead children # and MAXIMA processes $SIG{CHLD} = \&REAPER; my $pid = wait; $children--; + &logthis("Child $pid for port or process $children{$pid} died"); delete($usedmaximaports{$children{$pid}}); delete($children{$pid}); } @@ -144,8 +129,6 @@ sub catchexception { die("Signal abend"); } - - # ---------------------------------------------------------------- Main program # -------------------------------- Set signal handlers to record abnormal exits @@ -236,10 +219,13 @@ while (1) { for (my $i = $children; $i < $PREFORK; $i++) { &status('Parent process, starting child'); my $newport; - foreach $newport ($STARTPORT .. $STARTPORT+$PREFORK-1) { - if (!defined($usedmaximaports{$newport})) { last; } + &logthis("Current pool: ".join(', ',keys %usedmaximaports)); + foreach my $testport ($STARTPORT .. $STARTPORT+$PREFORK-1) { + if (!$usedmaximaports{$testport}) { $newport=$testport; } + } + if ($newport) { + &make_new_child($server,$newport); # top up the child pool } - &make_new_child($server,$newport); # top up the child pool } } @@ -259,8 +245,10 @@ sub make_new_child { or die("Can't unblock SIGINT for fork: $!\n"); $children{$pid} = $maximaport; $children++; + $usedmaximaports{$maximaport}=1; return; } else { + &logthis("Starting child on port $maximaport"); # Child can *not* return from this subroutine. $SIG{INT} = 'DEFAULT'; # make SIGINT kill us as it did before @@ -275,27 +263,36 @@ sub make_new_child { Reuse => 1, Listen => 10 ) or die "making socket: $@\n"; + my $maximaselect=IO::Select->new($maximaserver); + sleep(1); # open MAXIMA to talk to that port my ($cmd_in, $cmd_out, $cmd_err); my $maximapid = open3($cmd_in, $cmd_out, $cmd_err, "maxima -s $maximaport"); - $children{$maximapid} = 1; - + $children{$maximapid} = "Maxima $maximapid port $maximaport"; my $prompt=<$cmd_out>; &logthis("Maxima $maximapid: $prompt"); + # hopefully, MAXIMA calls us back &status("Waiting $maximapid on $maximaport"); - # Hopefully, MAXIMA calls us back my $maximaclient=$maximaserver->accept(); + $maximaclient->blocking(0); + $maximaselect->add($maximaclient); &status("$maximapid on $maximaport connected."); &logthis("Maxima $maximapid on port $maximaport connected."); + sleep(2); - # Absorb initial prompts - &logthis(&maximareply("0;\n",$maximaclient,$maximapid)); - - # Ready for action - - &process_requests($server,$maximaclient,$maximapid); + &logthis('Initial reply: '.&maximareply($maximaselect)); + # handle connections until we've reached $MAX_CLIENTS_PER_CHILD + for (my $i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) { + &status('Accepting connections for '.$maximapid.' on '.$maximaport); + my $client = $server->accept() or last; + while (my $cmd=<$client>) { + &status('Processing command by '.$maximapid.' on '.$maximaport); + &maximawrite($maximaselect,&unescape($cmd).";\n"); + print $client &escape(&maximareply($maximaselect))."\n"; + } + } # tidy up gracefully and finish @@ -310,15 +307,26 @@ sub make_new_child { } } -sub process_requests { - my ($server,$maximaclient,$maximapid) = @_; - # handle connections until we've reached $MAX_CLIENTS_PER_CHILD - for (my $i=0; $i < $MAX_CLIENTS_PER_CHILD; $i++) { - &status('Accepting connections for '.$maximapid.' on '.$maximaport); - my $client = $server->accept() or last; - while (my $cmd=<$client>) { - &status('Processing command by '.$maximapid.' on '.$maximaport); - print $client &escape((&maximareply(&unescape($cmd),$maximaclient,$maximapid))[0])."\n"; - } - } +sub maximareply { + my ($maximaselect)=@_; + my $output=''; + + foreach my $ready ($maximaselect->can_read(1)) { + my $data = ''; + my $rv = $ready->recv($data, POSIX::BUFSIZ, 0); + $output.=$data; + } + return $output; +} + +sub maximawrite { + my ($maximaselect,$cmd)=@_; + my $ready=($maximaselect->can_write(1)); + if (ref($ready)) { + print $ready $cmd; + } else { + &logthis("Cannot write: ".&maximareply($maximaselect)); + } } + +