[LON-CAPA-cvs] cvs: modules /gerd/maxima lonmaxima
www
lon-capa-cvs@mail.lon-capa.org
Wed, 08 Mar 2006 22:30:13 -0000
www Wed Mar 8 17:30:13 2006 EDT
Modified files:
/modules/gerd/maxima lonmaxima
Log:
YES!
Index: modules/gerd/maxima/lonmaxima
diff -u modules/gerd/maxima/lonmaxima:1.15 modules/gerd/maxima/lonmaxima:1.16
--- modules/gerd/maxima/lonmaxima:1.15 Wed Mar 8 10:58:03 2006
+++ modules/gerd/maxima/lonmaxima Wed Mar 8 17:30:11 2006
@@ -3,7 +3,7 @@
# The LearningOnline Network with CAPA
# Connect to MAXIMA CAS
#
-# $Id: lonmaxima,v 1.15 2006/03/08 15:58:03 www Exp $
+# $Id: lonmaxima,v 1.16 2006/03/08 22:30:11 www Exp $
#
# Copyright Michigan State University Board of Trustees
#
@@ -30,7 +30,7 @@
# http://www.lon-capa.org/
#
-
+use Expect;
use IPC::Open3;
use IO::Select;
use IO::Socket;
@@ -43,18 +43,16 @@
use strict;
# global variables
-my $STARTPORT = 5664; # port for first child's server
my $PREFORK = 5; # number of children to maintain
my $MAX_CLIENTS_PER_CHILD = 5; # number of clients each child should process
my %children = (); # keys are current child process IDs
-my %usedmaximaports = (); # keys are the used maximaports
my $children = 0; # current number of children
my $status; # string for current status
my $pidfile; # file containg parent process pid
my $port; # path to UNIX socket file
my %perlvar; # configuration file info
my $lastlog; # last string that was logged
-use vars qw($PREFORK $MAX_CLIENTS_PER_CHILD %children $children %usedmaximaports $status
+use vars qw($PREFORK $MAX_CLIENTS_PER_CHILD %children $children $status
$pidfile $port %perlvar $lastlog);
# ------------------------------------------------------------ Service routines
@@ -63,8 +61,6 @@
$SIG{CHLD} = \&REAPER;
my $pid = wait;
$children--;
- &logthis("Child $pid for port or process $children{$pid} died");
- delete($usedmaximaports{$children{$pid}});
delete($children{$pid});
}
@@ -129,6 +125,8 @@
die("Signal abend");
}
+
+
# ---------------------------------------------------------------- Main program
# -------------------------------- Set signal handlers to record abnormal exits
@@ -204,12 +202,10 @@
# Install signal handlers.
$SIG{CHLD} = \&REAPER;
$SIG{INT} = $SIG{TERM} = \&HUNTSMAN;
-
-my $maximaport=$STARTPORT;
+
# Fork off our children.
for (1 .. $PREFORK) {
- &make_new_child($server,$maximaport);
- $maximaport++;
+ &make_new_child($server);
}
# And maintain the population.
@@ -218,19 +214,12 @@
sleep; # wait for a signal (i.e., child's death)
for (my $i = $children; $i < $PREFORK; $i++) {
&status('Parent process, starting child');
- my $newport;
- &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); # top up the child pool
}
}
sub make_new_child {
- my ($server,$maximaport) = @_;
+ my ($server) = @_;
# block signal for fork
my $sigset = POSIX::SigSet->new(SIGINT);
@@ -243,62 +232,35 @@
# Parent records the child's birth and returns.
sigprocmask(SIG_UNBLOCK, $sigset)
or die("Can't unblock SIGINT for fork: $!\n");
- $children{$pid} = $maximaport;
+ $children{$pid} = 1;
$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
# unblock signals
sigprocmask(SIG_UNBLOCK, $sigset)
or die("Can't unblock SIGINT for fork: $!\n");
-
- # open the MAXIMA port
- my $maximaserver = IO::Socket::INET->new(LocalPort => $maximaport,
- Type => SOCK_STREAM,
- Proto => 'tcp',
- 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} = "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);
- &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
+ my $command=Expect->spawn('maxima');
+ $command->log_stdout(0);
+
+ &getmaximaoutput($command);
+
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";
- }
+ &status('Accepting connections');
+ my $client = $server->accept() or last;
+ while (my $cmd=<$client>) {
+ &status('Processing command');
+ print $command &unescape($cmd).";\n";
+ print $client &escape(&getmaximaoutput($command))."\n";
+ }
}
# tidy up gracefully and finish
- if (ref($cmd_out)) { close($cmd_out); }
- if (ref($cmd_err)) { close($cmd_err); }
- if (ref($cmd_in)) { close($cmd_in); }
+ $command->soft_close();
# this exit is VERY important, otherwise the child will become
# a producer of more and more children, forking yourself into
@@ -307,26 +269,20 @@
}
}
-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));
- }
+sub getmaximaoutput {
+ my ($command)=@_;
+ my (undef,undef,undef,$output)=$command->expect(20, -re => '\(\%i\d+\)');
+ my $foundoutput=0;
+ my $realoutput='';
+ foreach my $line (split(/\n/,$output)) {
+ if ($line=~/\;/) { $foundoutput=1; next; }
+ if (!$foundoutput) { next; }
+ my ($label)=($line=~s/^(\(\%o\d+\))//);
+ if ($label) {
+ $label=~s/\S/ /g;
+ $line=$label.$line;
+ }
+ $realoutput.=$line."\n";
+ }
+ return $realoutput;
}
-
-