--- loncom/lonmaxima 2006/03/08 12:57:30 1.13 +++ 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.13 2006/03/08 12:57:30 www Exp $ +# $Id: lonmaxima,v 1.15 2006/03/08 15:58:03 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -37,8 +37,6 @@ use IO::Socket; use IO::File; use Symbol; use POSIX; -use Fcntl; -use Socket; use lib '/home/httpd/lib/perl/'; use LONCAPA::Configuration; @@ -65,6 +63,7 @@ sub REAPER { # ta $SIG{CHLD} = \&REAPER; my $pid = wait; $children--; + &logthis("Child $pid for port or process $children{$pid} died"); delete($usedmaximaports{$children{$pid}}); delete($children{$pid}); } @@ -130,18 +129,6 @@ sub catchexception { die("Signal abend"); } -# -------------------------------------------------- make a socket non-blocking -sub nonblock { - my $socket = shift; - my $flags; - if (ref($socket)) { - $flags = fcntl($socket, F_GETFL, 0) - or die "Can't get flags for socket: $!\n"; - fcntl($socket, F_SETFL, $flags | O_NONBLOCK) - or die "Can't make socket nonblocking: $!\n"; - } -} - # ---------------------------------------------------------------- Main program # -------------------------------- Set signal handlers to record abnormal exits @@ -232,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 } } @@ -255,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 @@ -271,23 +263,25 @@ sub make_new_child { Reuse => 1, Listen => 10 ) or die "making socket: $@\n"; - &nonblock($maximaserver); 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"); my $maximaclient=$maximaserver->accept(); + $maximaclient->blocking(0); $maximaselect->add($maximaclient); - &nonblock($maximaclient); &status("$maximapid on $maximaport connected."); &logthis("Maxima $maximapid on port $maximaport connected."); + sleep(2); + &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++) { @@ -295,7 +289,7 @@ sub make_new_child { my $client = $server->accept() or last; while (my $cmd=<$client>) { &status('Processing command by '.$maximapid.' on '.$maximaport); - print $maximaclient &unescape($cmd).";\n"; + &maximawrite($maximaselect,&unescape($cmd).";\n"); print $client &escape(&maximareply($maximaselect))."\n"; } } @@ -316,6 +310,7 @@ sub make_new_child { sub maximareply { my ($maximaselect)=@_; my $output=''; + foreach my $ready ($maximaselect->can_read(1)) { my $data = ''; my $rv = $ready->recv($data, POSIX::BUFSIZ, 0); @@ -324,3 +319,14 @@ sub maximareply { 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)); + } +} + +