home *** CD-ROM | disk | FTP | other *** search
/ PC Professionell 2004 December / PCpro_2004_12.ISO / files / webserver / xampp / xampp-perl-addon-1.4.9-installer.exe / SysRW.pm < prev    next >
Encoding:
Perl POD Document  |  2003-11-26  |  6.8 KB  |  236 lines

  1. # $Id: SysRW.pm,v 1.26 2003/11/26 03:52:07 rcaputo Exp $
  2.  
  3. # Copyright 1998 Rocco Caputo <rcaputo@cpan.org>.  All rights
  4. # reserved.  This program is free software; you can redistribute it
  5. # and/or modify it under the same terms as Perl itself.
  6.  
  7. package POE::Driver::SysRW;
  8. use POE::Preprocessor ( isa => "POE::Macro::UseBytes" );
  9.  
  10. use strict;
  11.  
  12. use vars qw($VERSION);
  13. $VERSION = do {my@r=(q$Revision: 1.26 $=~/\d+/g);sprintf"%d."."%04d"x$#r,@r};
  14.  
  15. use Errno qw(EAGAIN EWOULDBLOCK);
  16. use Carp qw(croak);
  17.  
  18. sub OUTPUT_QUEUE        () { 0 }
  19. sub CURRENT_OCTETS_DONE () { 1 }
  20. sub CURRENT_OCTETS_LEFT () { 2 }
  21. sub BLOCK_SIZE          () { 3 }
  22. sub TOTAL_OCTETS_LEFT   () { 4 }
  23.  
  24. #------------------------------------------------------------------------------
  25.  
  26. sub new {
  27.   my $type = shift;
  28.   my $self = bless [
  29.     [ ],   # OUTPUT_QUEUE
  30.     0,     # CURRENT_OCTETS_DONE
  31.     0,     # CURRENT_OCTETS_LEFT
  32.     65536, # BLOCK_SIZE
  33.     0,     # TOTAL_OCTETS_LEFT
  34.   ], $type;
  35.  
  36.   if (@_) {
  37.     if (@_ % 2) {
  38.       croak "$type requires an even number of parameters, if any";
  39.     }
  40.     my %args = @_;
  41.     if (defined $args{BlockSize}) {
  42.       $self->[BLOCK_SIZE] = delete $args{BlockSize};
  43.       croak "$type BlockSize must be greater than 0"
  44.         if ($self->[BLOCK_SIZE] <= 0);
  45.     }
  46.     if (keys %args) {
  47.       my @bad_args = sort keys %args;
  48.       croak "$type has unknown parameter(s): @bad_args";
  49.     }
  50.   }
  51.  
  52.   $self;
  53. }
  54.  
  55. #------------------------------------------------------------------------------
  56.  
  57. sub put {
  58.   my ($self, $chunks) = @_;
  59.   my $old_queue_octets = $self->[TOTAL_OCTETS_LEFT];
  60.  
  61.   {% use_bytes %}
  62.  
  63.   foreach (grep { length } @$chunks) {
  64.     $self->[TOTAL_OCTETS_LEFT] += length;
  65.     push @{$self->[OUTPUT_QUEUE]}, $_;
  66.   }
  67.  
  68.   if ($self->[TOTAL_OCTETS_LEFT] && (!$old_queue_octets)) {
  69.     $self->[CURRENT_OCTETS_LEFT] = length($self->[OUTPUT_QUEUE]->[0]);
  70.     $self->[CURRENT_OCTETS_DONE] = 0;
  71.   }
  72.  
  73.   $self->[TOTAL_OCTETS_LEFT];
  74. }
  75.  
  76. #------------------------------------------------------------------------------
  77.  
  78. sub get {
  79.   my ($self, $handle) = @_;
  80.  
  81.   my $result = sysread($handle, my $buffer = '', $self->[BLOCK_SIZE]);
  82.  
  83.   # sysread() was sucessful.  Return whatever was read.
  84.   return [ $buffer ] if $result;
  85.  
  86.   # 18:01 <dngor> sysread() clears $! when it returns 0 for eof?
  87.   # 18:01 <merlyn> nobody clears $!
  88.   # 18:01 <merlyn> returning 0 is not an error
  89.   # 18:01 <merlyn> returning -1 is an error, and sets $!
  90.   # 18:01 <merlyn> eof is not an error. :)
  91.  
  92.   # 18:21 <dngor> perl -wle '$!=1; warn "\$!=",$!+0; \
  93.   #               warn "sysread=",sysread(STDIN,my $x="",100); \
  94.   #               die "\$!=",$!+0' < /dev/null
  95.   # 18:23 <lathos> $!=1 at foo line 1.
  96.   # 18:23 <lathos> sysread=0 at foo line 1.
  97.   # 18:23 <lathos> $!=0 at foo line 1.
  98.   # 18:23 <lathos> 5.6.0 on Darwin.
  99.   # 18:23 <dngor> Same, 5.6.1 on fbsd 4.4-stable.
  100.   #               read(2) must be clearing errno or something.
  101.  
  102.   # sysread() returned 0, signifying EOF.  Although $! is magically
  103.   # set to 0 on EOF, it may not be portable to rely on this.
  104.   if (defined $result) {
  105.     $! = 0;
  106.     return undef;
  107.   }
  108.  
  109.   # Nonfatal sysread() error.  Return an empty list.
  110.   return [ ] if $! == EAGAIN or $! == EWOULDBLOCK;
  111.  
  112.   # fatal sysread error
  113.   undef;
  114. }
  115.  
  116. #------------------------------------------------------------------------------
  117.  
  118. sub flush {
  119.   my ($self, $handle) = @_;
  120.  
  121.   {% use_bytes %}
  122.  
  123.   # syswrite() it, like we're supposed to
  124.   while (@{$self->[OUTPUT_QUEUE]}) {
  125.     my $wrote_count = syswrite($handle,
  126.                                $self->[OUTPUT_QUEUE]->[0],
  127.                                $self->[CURRENT_OCTETS_LEFT],
  128.                                $self->[CURRENT_OCTETS_DONE],
  129.                               );
  130.  
  131.     unless ($wrote_count) {
  132.       $! = 0 if $! == EAGAIN or $! == EWOULDBLOCK;
  133.       last;
  134.     }
  135.  
  136.     $self->[CURRENT_OCTETS_DONE] += $wrote_count;
  137.     $self->[TOTAL_OCTETS_LEFT] -= $wrote_count;
  138.     unless ($self->[CURRENT_OCTETS_LEFT] -= $wrote_count) {
  139.       shift(@{$self->[OUTPUT_QUEUE]});
  140.       if (@{$self->[OUTPUT_QUEUE]}) {
  141.         $self->[CURRENT_OCTETS_DONE] = 0;
  142.         $self->[CURRENT_OCTETS_LEFT] = length($self->[OUTPUT_QUEUE]->[0]);
  143.       }
  144.       else {
  145.         $self->[CURRENT_OCTETS_DONE] = $self->[CURRENT_OCTETS_LEFT] = 0;
  146.       }
  147.     }
  148.   }
  149.  
  150.   $self->[TOTAL_OCTETS_LEFT];
  151. }
  152.  
  153. #------------------------------------------------------------------------------
  154.  
  155. sub get_out_messages_buffered {
  156.   scalar(@{$_[0]->[OUTPUT_QUEUE]});
  157. }
  158.  
  159. ###############################################################################
  160. 1;
  161.  
  162. __END__
  163.  
  164. =head1 NAME
  165.  
  166. POE::Driver::SysRW - an abstract sysread/syswrite file driver
  167.  
  168. =head1 SYNOPSIS
  169.  
  170.   $driver = POE::Driver::SysRW->new();
  171.   $arrayref_of_data_chunks = $driver->get($filehandle);
  172.   $queue_octets = $driver->put($arrayref_of_data_chunks);
  173.   $queue_octets = $driver->flush($filehandle);
  174.   $queue_messages = $driver->get_out_messages_buffered();
  175.  
  176. =head1 DESCRIPTION
  177.  
  178. This driver implements an abstract interface to sysread and syswrite.
  179.  
  180. =head1 PUBLIC METHODS
  181.  
  182. =over 2
  183.  
  184. =item new BlockSize => $block_size
  185.  
  186. =item new
  187.  
  188. new() creates a new SysRW driver.  It accepts one optional named
  189. parameter, BlockSize, which indicates the maximum number of octets it
  190. will read at a time.  For speed, syswrite() tries to send as much
  191. information as it can.
  192.  
  193. BlockSize defaults to 65536 if it is omitted.  Higher values improve
  194. performance in high-throughput applications at the expense of
  195. consuming more resident memory.  Lower values reduce memory
  196. consumption with corresponding throughput penalties.
  197.  
  198.   my $driver = POE::Driver::SysRW->new( BlockSize => $block_size );
  199.  
  200.   my $driver = POE::Driver::SysRW->new;
  201.  
  202. =back
  203.  
  204. =head1 DESIGN NOTES
  205.  
  206. Driver::SysRW uses a queue of output messages.  This means that
  207. BLOCK_SIZE is not used for writing.  Rather, each message put()
  208. through the driver is written in its entirety (or not, if it fails).
  209. This often means more syswrite() calls than necessary, however it
  210. makes memory management much easier.
  211.  
  212. If the driver used a scalar buffer for output, it would be necessary
  213. to use substr() to remove the beginning of it after it was written.
  214. Each substr() call requires the end of the string be moved down to its
  215. beginning.  That is a lot of memory copying.
  216.  
  217. The buffer could be allowed to grow until it has flushed entirely.
  218. This would be eliminate extra memory copies entirely, but it would
  219. then be possible to create programs where the buffer was not allowed
  220. to shrink at all.  That would quickly become bad.
  221.  
  222. Better ideas are welcome.
  223.  
  224. =head1 SEE ALSO
  225.  
  226. POE::Driver.
  227.  
  228. The SEE ALSO section in L<POE> contains a table of contents covering
  229. the entire POE distribution.
  230.  
  231. =head1 AUTHORS & COPYRIGHTS
  232.  
  233. Please see L<POE> for more information about authors and contributors.
  234.  
  235. =cut
  236.