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