--- loncom/lonmaxima 2006/03/08 03:18:42 1.12 +++ loncom/lonmaxima 2006/03/08 12:57:30 1.13 @@ -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.13 2006/03/08 12:57:30 www Exp $ # # Copyright Michigan State University Board of Trustees # @@ -37,6 +37,8 @@ use IO::Socket; use IO::File; use Symbol; use POSIX; +use Fcntl; +use Socket; use lib '/home/httpd/lib/perl/'; use LONCAPA::Configuration; @@ -57,22 +59,6 @@ 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 @@ -144,7 +130,17 @@ 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 @@ -275,27 +271,34 @@ sub make_new_child { Reuse => 1, Listen => 10 ) or die "making socket: $@\n"; + &nonblock($maximaserver); + my $maximaselect=IO::Select->new($maximaserver); # 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; - 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(); + $maximaselect->add($maximaclient); + &nonblock($maximaclient); &status("$maximapid on $maximaport connected."); &logthis("Maxima $maximapid on port $maximaport connected."); - - # 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); + print $maximaclient &unescape($cmd).";\n"; + print $client &escape(&maximareply($maximaselect))."\n"; + } + } # tidy up gracefully and finish @@ -310,15 +313,14 @@ 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; } +