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