# Copyright (c) 1997-2004
# 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: Pipe.pm 5537 2004-12-10 15:46:40Z gawrilow $
use strict;
use namespaces;
package Poly::Pipe;
use Fcntl;
use POSIX;
#####################################################################################
#
# Constructor: new Pipe(FileHandle);
#
use Struct (
'$fd',
'$rbuffer',
'$wbuffer',
);
declare %active;
declare @channels;
declare $rmask="";
declare $wmask="";
sub init {
my $self=shift;
$self->fd=fileno($_[0]);
$active{$self}=0;
$channels[$self->fd]=$self;
tie *{$_[0]}, $self;
}
sub new {
my $self=&_new;
if (keys(%active)==1) {
$self->not_alone;
(each %active)->not_alone;
}
init($self,$_[0]);
vec($rmask, $self->fd, 1)=1;
shift;
}
sub TIEHANDLE { shift }
sub CLOSE {
my $self=shift;
vec($rmask, $self->fd, 1)=0;
vec($wmask, $self->fd, 1)=0;
POSIX::close($self->fd);
delete $active{$self};
undef $channels[$self->fd];
if (keys(%active)==1) {
(each %active)->alone;
}
bless $self, "Poly::ClosedPipe" unless @_;
}
sub DESTROY {
my $self=shift;
if (vec($rmask, $self->fd, 1)) {
CLOSE($self,1);
}
}
sub READLINE {
my $self=shift;
my ($l, $gotten)=(0);
do {
if ((my $endl=index($self->rbuffer, "\n", $l)) >= 0) {
return substr($self->rbuffer, 0, $endl+1, "");
}
$l=length($self->rbuffer);
} while ($gotten=$self->do_read($self->fd,$self->rbuffer,1024,$l)) > 0;
die "error reading from Pipe: $!\n" if !defined $gotten;
undef;
}
sub PRINT {
my $self=shift;
$self->WRITE(join($, , @_).$\);
}
sub PRINTF {
my $self=shift;
$self->WRITE(sprintf(@_));
}
sub READ {
my $self=shift;
if (length($self->rbuffer)) {
my (undef, $len, $offset)=@_;
assign_min($len, length($self->rbuffer));
if ($offset) {
substr($_[0],$offset)=substr($self->rbuffer,0,$len,"");
} else {
$_[0]=substr($self->rbuffer,0,$len,"");
}
return $len;
} else {
$self->do_read($self->fd, @_);
}
}
sub do_read {
my ($self, $fd, undef, $len, $offset)=@_;
my $gotten;
if ($offset) {
my $app;
$gotten=POSIX::read($fd, $app, $len)
and substr($_[2],$offset)=$app;
} else {
$gotten=POSIX::read($fd, $_[2], $len);
}
if (!$gotten) {
CLOSE($self);
}
$gotten;
}
sub not_alone {
bless shift, "Poly::CollaborativePipe";
}
sub WRITE {
my $self=shift;
my ($str, $len);
if (@_==1) {
$str=$_[0]; $len=length($str);
} else {
$str=substr($_[0],$_[2],$len=$_[1]);
}
my $written=POSIX::write($self->fd, $str, $len);
if (!defined($written)) {
if ($!==POSIX::EAGAIN) {
$written=0;
} else {
CLOSE($self);
return undef;
}
}
if ($written<$len) {
$self->wbuffer=substr($str,$written,$len-$written);
vec($wmask,$self->fd,1)=1;
$self->not_alone if keys(%active)==1;
}
$len;
}
sub FILENO { shift->fd }
#####################################################################################
package Poly::ClosedPipe;
use Struct [ '@ISA' => 'Poly::Pipe' ];
sub READ { 0 }
sub WRITE { 0 }
sub CLOSE { 1 }
sub DESTROY { }
#####################################################################################
package Poly::CollaborativePipe;
use Struct [ '@ISA' => 'Poly::Pipe' ];
sub do_write {
my $self=shift;
if (@_) {
$self->wbuffer .= @_==1 ? $_[0] : substr($_[0],$_[2],$_[1]);
}
my $written=POSIX::write($self->fd, $self->wbuffer, length($self->wbuffer));
if (!defined($written)) {
if ($!==POSIX::EAGAIN) {
$written=0;
} else {
CLOSE($self);
return undef;
}
}
if ($written == length($self->wbuffer)) {
vec($wmask, $self->fd, 1)=0;
$self->wbuffer="";
$self->alone if keys %active==1;
} else {
substr($self->wbuffer, 0, $written)="";
}
$written;
}
sub do_read {
my ($self, $fd)=@_;
my ($rready, $wready, $gotten);
while (select $rready=$rmask, $wready=$wmask, undef, undef) {
if (vec($rready, $fd, 1)) {
return &Poly::Pipe::do_read;
}
foreach my $rfd (ones($wready)) {
do_write($channels[$rfd]);
}
foreach my $rfd (ones($rready)) {
my $pipe=$channels[$rfd];
Poly::Pipe::do_read($pipe, $rfd, $pipe->rbuffer, 1024, length($pipe->rbuffer));
}
}
undef;
}
sub WRITE {
my ($self)=@_;
if (!length($self->wbuffer)) {
return &Poly::Pipe::WRITE;
}
my ($rready, $wready, $gotten);
while (select $rready=$rmask, $wready=$wmask, undef, undef) {
if (vec($wready, $self->fd, 1)) {
return &do_write;
}
foreach my $rfd (ones($wready)) {
do_write($channels[$rfd]);
}
foreach my $rfd (ones($rready)) {
my $pipe=$channels[$rfd];
Poly::Pipe::do_read($pipe, $rfd, $pipe->rbuffer, 1024, length($pipe->rbuffer));
}
}
undef;
}
sub alone {
my $self=shift;
if (!length($self->wbuffer)) {
bless $self, "Poly::Pipe";
}
}
sub not_alone { }
1
syntax highlighted by Code2HTML, v. 0.9.1