home *** CD-ROM | disk | FTP | other *** search
/ isnet Internet / Isnet Internet CD.iso / prog / hiz / 09 / 09.exe / adynware.exe / perl / lib / IO / Select.pm < prev    next >
Encoding:
Perl POD Document  |  1999-12-28  |  7.6 KB  |  364 lines

  1.  
  2. package IO::Select;
  3.  
  4. =head1 NAME
  5.  
  6. IO::Select - OO interface to the select system call
  7.  
  8. =head1 SYNOPSIS
  9.  
  10.     use IO::Select;
  11.  
  12.     $s = IO::Select->new();
  13.  
  14.     $s->add(\*STDIN);
  15.     $s->add($some_handle);
  16.  
  17.     @ready = $s->can_read($timeout);
  18.  
  19.     @ready = IO::Select->new(@handles)->read(0);
  20.  
  21. =head1 DESCRIPTION
  22.  
  23. The C<IO::Select> package implements an object approach to the system C<select>
  24. function call. It allows the user to see what IO handles, see L<IO::Handle>,
  25. are ready for reading, writing or have an error condition pending.
  26.  
  27. =head1 CONSTRUCTOR
  28.  
  29. =over 4
  30.  
  31. =item new ( [ HANDLES ] )
  32.  
  33. The constructor creates a new object and optionally initialises it with a set
  34. of handles.
  35.  
  36. =back
  37.  
  38. =head1 METHODS
  39.  
  40. =over 4
  41.  
  42. =item add ( HANDLES )
  43.  
  44. Add the list of handles to the C<IO::Select> object. It is these values that
  45. will be returned when an event occurs. C<IO::Select> keeps these values in a
  46. cache which is indexed by the C<fileno> of the handle, so if more than one
  47. handle with the same C<fileno> is specified then only the last one is cached.
  48.  
  49. Each handle can be an C<IO::Handle> object, an integer or an array
  50. reference where the first element is a C<IO::Handle> or an integer.
  51.  
  52. =item remove ( HANDLES )
  53.  
  54. Remove all the given handles from the object. This method also works
  55. by the C<fileno> of the handles. So the exact handles that were added
  56. need not be passed, just handles that have an equivalent C<fileno>
  57.  
  58. =item exists ( HANDLE )
  59.  
  60. Returns a true value (actually the handle itself) if it is present.
  61. Returns undef otherwise.
  62.  
  63. =item handles
  64.  
  65. Return an array of all registered handles.
  66.  
  67. =item can_read ( [ TIMEOUT ] )
  68.  
  69. Return an array of handles that are ready for reading. C<TIMEOUT> is
  70. the maximum amount of time to wait before returning an empty list. If
  71. C<TIMEOUT> is not given and any handles are registered then the call
  72. will block.
  73.  
  74. =item can_write ( [ TIMEOUT ] )
  75.  
  76. Same as C<can_read> except check for handles that can be written to.
  77.  
  78. =item has_error ( [ TIMEOUT ] )
  79.  
  80. Same as C<can_read> except check for handles that have an error
  81. condition, for example EOF.
  82.  
  83. =item count ()
  84.  
  85. Returns the number of handles that the object will check for when
  86. one of the C<can_> methods is called or the object is passed to
  87. the C<select> static method.
  88.  
  89. =item bits()
  90.  
  91. Return the bit string suitable as argument to the core select() call.
  92.  
  93. =item bits()
  94.  
  95. Return the bit string suitable as argument to the core select() call.
  96.  
  97. =item select ( READ, WRITE, ERROR [, TIMEOUT ] )
  98.  
  99. C<select> is a static method, that is you call it with the package
  100. name like C<new>. C<READ>, C<WRITE> and C<ERROR> are either C<undef>
  101. or C<IO::Select> objects. C<TIMEOUT> is optional and has the same
  102. effect as for the core select call.
  103.  
  104. The result will be an array of 3 elements, each a reference to an array
  105. which will hold the handles that are ready for reading, writing and have
  106. error conditions respectively. Upon error an empty array is returned.
  107.  
  108. =back
  109.  
  110. =head1 EXAMPLE
  111.  
  112. Here is a short example which shows how C<IO::Select> could be used
  113. to write a server which communicates with several sockets while also
  114. listening for more connections on a listen socket
  115.  
  116.     use IO::Select;
  117.     use IO::Socket;
  118.  
  119.     $lsn = new IO::Socket::INET(Listen => 1, LocalPort => 8080);
  120.     $sel = new IO::Select( $lsn );
  121.     
  122.     while(@ready = $sel->can_read) {
  123.         foreach $fh (@ready) {
  124.             if($fh == $lsn) {
  125.                 $new = $lsn->accept;
  126.                 $sel->add($new);
  127.             }
  128.             else {
  129.  
  130.                 $sel->remove($fh);
  131.                 $fh->close;
  132.             }
  133.         }
  134.     }
  135.  
  136. =head1 AUTHOR
  137.  
  138. Graham Barr E<lt>F<Graham.Barr@tiuk.ti.com>E<gt>
  139.  
  140. =head1 COPYRIGHT
  141.  
  142. Copyright (c) 1995 Graham Barr. All rights reserved. This program is free
  143. software; you can redistribute it and/or modify it under the same terms
  144. as Perl itself.
  145.  
  146. =cut
  147.  
  148. use     strict;
  149. use     vars qw($VERSION @ISA);
  150. require Exporter;
  151.  
  152. $VERSION = "1.10";
  153.  
  154. @ISA = qw(Exporter); # This is only so we can do version checking
  155.  
  156. sub VEC_BITS () {0}
  157. sub FD_COUNT () {1}
  158. sub FIRST_FD () {2}
  159.  
  160. sub new
  161. {
  162.  my $self = shift;
  163.  my $type = ref($self) || $self;
  164.  
  165.  my $vec = bless [undef,0], $type;
  166.  
  167.  $vec->add(@_)
  168.     if @_;
  169.  
  170.  $vec;
  171. }
  172.  
  173. sub add
  174. {
  175.  shift->_update('add', @_);
  176. }
  177.  
  178.  
  179. sub remove
  180. {
  181.  shift->_update('remove', @_);
  182. }
  183.  
  184.  
  185. sub exists
  186. {
  187.  my $vec = shift;
  188.  $vec->[$vec->_fileno(shift) + FIRST_FD];
  189. }
  190.  
  191.  
  192. sub _fileno
  193. {
  194.  my($self, $f) = @_;
  195.  $f = $f->[0] if ref($f) eq 'ARRAY';
  196.  ($f =~ /^\d+$/) ? $f : fileno($f);
  197. }
  198.  
  199. sub _update
  200. {
  201.  my $vec = shift;
  202.  my $add = shift eq 'add';
  203.  
  204.  my $bits = $vec->[VEC_BITS];
  205.  $bits = '' unless defined $bits;
  206.  
  207.  my $count = 0;
  208.  my $f;
  209.  foreach $f (@_)
  210.   {
  211.    my $fn = $vec->_fileno($f);
  212.    next unless defined $fn;
  213.    my $i = $fn + FIRST_FD;
  214.    if ($add) {
  215.      if (defined $vec->[$i]) {
  216.      $vec->[$i] = $f;  # if array rest might be different, so we update
  217.      next;
  218.      }
  219.      $vec->[FD_COUNT]++;
  220.      vec($bits, $fn, 1) = 1;
  221.      $vec->[$i] = $f;
  222.    } else {      # remove
  223.      next unless defined $vec->[$i];
  224.      $vec->[FD_COUNT]--;
  225.      vec($bits, $fn, 1) = 0;
  226.      $vec->[$i] = undef;
  227.    }
  228.    $count++;
  229.   }
  230.  $vec->[VEC_BITS] = $vec->[FD_COUNT] ? $bits : undef;
  231.  $count;
  232. }
  233.  
  234. sub can_read
  235. {
  236.  my $vec = shift;
  237.  my $timeout = shift;
  238.  my $r = $vec->[VEC_BITS];
  239.  
  240.  defined($r) && (select($r,undef,undef,$timeout) > 0)
  241.     ? handles($vec, $r)
  242.     : ();
  243. }
  244.  
  245. sub can_write
  246. {
  247.  my $vec = shift;
  248.  my $timeout = shift;
  249.  my $w = $vec->[VEC_BITS];
  250.  
  251.  defined($w) && (select(undef,$w,undef,$timeout) > 0)
  252.     ? handles($vec, $w)
  253.     : ();
  254. }
  255.  
  256. sub has_error
  257. {
  258.  my $vec = shift;
  259.  my $timeout = shift;
  260.  my $e = $vec->[VEC_BITS];
  261.  
  262.  defined($e) && (select(undef,undef,$e,$timeout) > 0)
  263.     ? handles($vec, $e)
  264.     : ();
  265. }
  266.  
  267. sub count
  268. {
  269.  my $vec = shift;
  270.  $vec->[FD_COUNT];
  271. }
  272.  
  273. sub bits
  274. {
  275.  my $vec = shift;
  276.  $vec->[VEC_BITS];
  277. }
  278.  
  279. sub as_string  # for debugging
  280. {
  281.  my $vec = shift;
  282.  my $str = ref($vec) . ": ";
  283.  my $bits = $vec->bits;
  284.  my $count = $vec->count;
  285.  $str .= defined($bits) ? unpack("b*", $bits) : "undef";
  286.  $str .= " $count";
  287.  my @handles = @$vec;
  288.  splice(@handles, 0, FIRST_FD);
  289.  for (@handles) {
  290.      $str .= " " . (defined($_) ? "$_" : "-");
  291.  }
  292.  $str;
  293. }
  294.  
  295. sub _max
  296. {
  297.  my($a,$b,$c) = @_;
  298.  $a > $b
  299.     ? $a > $c
  300.         ? $a
  301.         : $c
  302.     : $b > $c
  303.         ? $b
  304.         : $c;
  305. }
  306.  
  307. sub select
  308. {
  309.  shift
  310.    if defined $_[0] && !ref($_[0]);
  311.  
  312.  my($r,$w,$e,$t) = @_;
  313.  my @result = ();
  314.  
  315.  my $rb = defined $r ? $r->[VEC_BITS] : undef;
  316.  my $wb = defined $w ? $w->[VEC_BITS] : undef;
  317.  my $eb = defined $e ? $e->[VEC_BITS] : undef;
  318.  
  319.  if(select($rb,$wb,$eb,$t) > 0)
  320.   {
  321.    my @r = ();
  322.    my @w = ();
  323.    my @e = ();
  324.    my $i = _max(defined $r ? scalar(@$r)-1 : 0,
  325.                 defined $w ? scalar(@$w)-1 : 0,
  326.                 defined $e ? scalar(@$e)-1 : 0);
  327.  
  328.    for( ; $i >= FIRST_FD ; $i--)
  329.     {
  330.      my $j = $i - FIRST_FD;
  331.      push(@r, $r->[$i])
  332.         if defined $rb && defined $r->[$i] && vec($rb, $j, 1);
  333.      push(@w, $w->[$i])
  334.         if defined $wb && defined $w->[$i] && vec($wb, $j, 1);
  335.      push(@e, $e->[$i])
  336.         if defined $eb && defined $e->[$i] && vec($eb, $j, 1);
  337.     }
  338.  
  339.    @result = (\@r, \@w, \@e);
  340.   }
  341.  @result;
  342. }
  343.  
  344.  
  345. sub handles
  346. {
  347.  my $vec = shift;
  348.  my $bits = shift;
  349.  my @h = ();
  350.  my $i;
  351.  my $max = scalar(@$vec) - 1;
  352.  
  353.  for ($i = FIRST_FD; $i <= $max; $i++)
  354.   {
  355.    next unless defined $vec->[$i];
  356.    push(@h, $vec->[$i])
  357.       if !defined($bits) || vec($bits, $i - FIRST_FD, 1);
  358.   }
  359.  
  360.  @h;
  361. }
  362.  
  363. 1;
  364.