Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

371 lines
7.5 KiB

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