# 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