# Copyright (c) 1997-2005
# Ewgenij Gawrilow, Michael Joswig (Technische Universitaet Berlin, Germany)
# http://www.math.tu-berlin.de/polymake, mailto:polymake@math.tu-berlin.de
#
# This program is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
# Free Software Foundation; either version 2, or (at your option) any
# later version: http://www.gnu.org/licenses/gpl.txt.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#-----------------------------------------------------------------------------
# $Project: polymake $$Id: ProgramPipe.pm 6640 2005-12-21 16:19:26Z gawrilow $
use strict;
use namespaces;
package Poly::Pipe::Process;
use Struct (
[ new => '$$' ],
[ '$pid' => '#1' ],
[ '$program' => '#2' ],
);
use POSIX qw(:sys_wait_h);
sub DESTROY {
my $self=shift;
waitpid $self->pid, 0;
if (!$@ && $? && $program) {
my $rc=$?>>8;
my ($prog)= $self->program =~ m'([^/\s]+)(?:\s|$)';
die $rc > 128 ? ("$prog exited with code ", $rc>>8)
: ("$prog killed by signal ", $rc&127),
"\n";
}
}
package Poly::ProgramPipe;
use IPC::Open3;
use POSIX qw(:signal_h);
use Fcntl;
use Poly::Pipe;
#####################################################################################
#
# Constructor: new Poly::ProgramPipe('command', 'arg', ... );
#
# Supports only one special, although very common communication "protocol":
# send the source data to the program, then switch into the input mode,
# and read all the results it has produced.
#
use Struct (
[ '@ISA' => 'Poly::CollaborativePipe' ],
[ '$proc' => 'undef' ],
[ '$in' => 'undef' ],
);
sub construct {
my $self=&_new;
dbg_print( "running '@_'" ) if $Switches::d;
my $out;
my $pid=eval { open3($out, $self->in, ">&STDERR", @_) };
if ($@) {
$@ =~ s/^.*?://;
$@ =~ s/ at \(eval.*$/\n/;
if ($$ != getpgrp) { # we are in the fork!!!
print STDERR $@;
exec "false"; # avoid executing global destructors
}
die $@;
}
$self->init($out);
$self->proc=new Poly::Pipe::Process($pid, $_[0]);
my $rfd=fileno($self->in);
$channels[$rfd]=$self;
vec($rmask,$rfd,1)=1;
$out;
}
sub new {
my $out=&construct;
fcntl($out, F_SETFL, O_NONBLOCK);
$out;
}
sub shared {
my $out=&construct;
fcntl($out, F_SETFD, 0); # by default the pipe is closed in child processes (due to the implementation of Open3.)
$out;
}
#####################################################################################
#
# The source data (output for us) are complete, start receiving the results
#
sub switch_to_input {
my $self=shift;
# flush the output buffer
$self->WRITE while length($self->wbuffer);
vec($wmask,$self->fd,1)=0;
POSIX::close($self->fd);
undef $channels[$self->fd];
$self->fd=fileno($self->in);
bless $self, keys(%active) ? "Poly::Pipe" : "Poly::CollaborativePipe";
}
sub alone { }
sub READ {
(shift)->switch_to_input->READ(@_);
}
sub READLINE {
(shift)->switch_to_input->READLINE;
}
# seems to die before started to consume input: shoot the program down
sub CLOSE {
my $self=shift;
$self->SUPER::CLOSE;
kill SIGINT, $self->proc->pid;
undef $self->proc->program;
close($self->in);
}
1
# Local Variables:
# c-basic-offset:3
# End:
syntax highlighted by Code2HTML, v. 0.9.1