ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Coro/Event/Handle.pm
Revision: 1.9
Committed: Mon Sep 24 00:51:19 2001 UTC (25 years, 1 month ago) by root
Branch: MAIN
Changes since 1.8: +48 -11 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 =head1 NAME
2    
3     Coro::Handle - non-blocking io with a blocking interface.
4    
5     =head1 SYNOPSIS
6    
7     use Coro::Handle;
8    
9     =head1 DESCRIPTION
10    
11     This module implements io-handles in a coroutine-compatible way, that is,
12     other coroutines can run while reads or writes block on the handle. It
13     does NOT inherit from IO::Handle but uses tied objects.
14    
15     =over 4
16    
17     =cut
18    
19     package Coro::Handle;
20    
21 root 1.9 no warnings;
22    
23 root 1.1 use Errno ();
24     use base 'Exporter';
25    
26     $VERSION = 0.45;
27    
28     @EXPORT = qw(unblock);
29    
30     =item $fh = new_from_fh Coro::Handle $fhandle [, arg => value...]
31    
32     Create a new non-blocking io-handle using the given
33     perl-filehandle. Returns undef if no fhandle is given. The only other
34     supported argument is "timeout", which sets a timeout for each operation.
35    
36     =cut
37    
38     sub new_from_fh {
39     my $class = shift;
40     my $fh = shift or return;
41     my $self = do { local *Coro::Handle };
42    
43     my ($package, $filename, $line) = caller;
44     $filename =~ s/^.*[\/\\]//;
45    
46     tie $self, Coro::Handle::FH, fh => $fh, desc => "$filename:$line", @_;
47    
48     my $_fh = select bless \$self, $class; $| = 1; select $_fh;
49     }
50    
51     =item $fh = unblock $fh
52    
53     This is a convinience function that just calls C<new_from_fh> on the given
54     filehandle. Use it to replace a normal perl filehandle by a non-blocking
55     equivalent.
56    
57     =cut
58    
59     sub unblock($) {
60     new_from_fh Coro::Handle $_[0];
61     }
62    
63     =item $fh->writable, $fh->readable
64    
65     Wait until the filehandle is readable or writable (and return true) or
66     until an error condition happens (and return false).
67    
68     =cut
69    
70 root 1.5 sub readable { Coro::Handle::FH::readable(tied ${$_[0]}) }
71     sub writable { Coro::Handle::FH::writable(tied ${$_[0]}) }
72 root 1.1
73     =item $fh->readline([$terminator])
74    
75     Like the builtin of the same name, but allows you to specify the input
76     record separator in a coroutine-safe manner (i.e. not using a global
77     variable).
78    
79     =cut
80    
81     sub readline { tied(${+shift})->READLINE(@_) }
82    
83     =item $fh->autoflush([...])
84    
85     Always returns true, arguments are being ignored (exists for compatibility
86     only). Might change in the future.
87    
88     =cut
89    
90     sub autoflush { !0 }
91    
92 root 1.9 =item $fh->fileno, $fh->close,
93     $fh->read, $fh->sysread, $fh->syswrite,
94     $fh->print, $fh->printf
95    
96     Work like their function equivalents (except read, which works like
97     sysread. You should not use the read function with Coro::Handles, it will
98     work but it's not efficient).
99 root 1.1
100     =cut
101    
102 root 1.9 sub read { Coro::Handle::FH::READ (tied ${$_[0]}, $_[1], $_[2], $_[3]) }
103     sub sysread { Coro::Handle::FH::READ (tied ${$_[0]}, $_[1], $_[2], $_[3]) }
104     sub syswrite { Coro::Handle::FH::WRITE (tied ${$_[0]}, $_[1], $_[2], $_[3]) }
105     sub print { Coro::Handle::FH::WRITE (tied ${+shift}, join "", @_) }
106     sub printf { Coro::Handle::FH::PRINTF(tied ${+shift}, @_) }
107     sub fileno { Coro::Handle::FH::FILENO(tied ${$_[0]}) }
108     sub close { Coro::Handle::FH::CLOSE (tied ${$_[0]}) }
109 root 1.1
110     =item $fh->timeout([...])
111    
112     The optional agrument sets the new timeout (in seconds) for this
113     handle. Returns the current (new) value.
114    
115     C<0> is a valid timeout, use C<undef> to disable the timeout.
116    
117     =cut
118    
119     sub timeout {
120 root 1.4 my $self = tied(${$_[0]});
121 root 1.6 if (@_ > 1) {
122     $self->[2] = $_[1];
123     $self->[5]->timeout($_[1]) if $self->[5];
124     $self->[6]->timeout($_[1]) if $self->[6];
125 root 1.1 }
126 root 1.6 $self->[2];
127 root 1.4 }
128    
129     =item $fh->fh
130    
131     Returns the "real" (non-blocking) filehandle. Use this if you want to
132     do operations on the file handle you cannot do using the Coro::Handle
133     interface.
134    
135     =cut
136    
137     sub fh {
138     tied(${$_[0]})->{fh};
139 root 1.1 }
140    
141     package Coro::Handle::FH;
142    
143 root 1.9 no warnings;
144    
145 root 1.1 use Fcntl ();
146     use Errno ();
147     use Carp 'croak';
148    
149     use Coro::Event;
150     use Event::Watcher qw(R W E);
151    
152 root 1.6 # formerly a hash, but we are speed-critical, so try
153     # to be faster even if it hurts.
154     #
155     # 0 FH
156     # 1 desc
157     # 2 timeout
158     # 3 rb
159     # 4 wb
160     # 5 rw
161     # 6 ww
162    
163 root 1.1 sub TIEHANDLE {
164     my $class = shift;
165 root 1.6 my %args = @_;
166 root 1.1
167 root 1.6 my $self = bless [], $class;
168     $self->[0] = $args{fh};
169     $self->[1] = $args{desc};
170     $self->[2] = $args{timeout};
171     $self->[3] = "";
172     $self->[4] = "";
173 root 1.1
174 root 1.6 fcntl $self->[0], &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK
175 root 1.1 or croak "fcntl(O_NONBLOCK): $!";
176    
177     $self;
178     }
179    
180 root 1.6 sub cleanup {
181     $_[0][3] = "";
182 root 1.7 ($_[0][5])->cancel if defined $_[0][5]; $_[0][5] = undef;
183 root 1.6
184     $_[0][4] = "";
185 root 1.7 ($_[0][6])->cancel if defined $_[0][6]; $_[0][6] = undef;
186 root 1.6 }
187    
188 root 1.1 sub OPEN {
189 root 1.6 &cleanup;
190 root 1.1 my $self = shift;
191 root 1.6 my $r = @_ == 2 ? open $self->[0], $_[0], $_[1]
192     : open $self->[0], $_[0], $_[1], $_[2];
193 root 1.1 if ($r) {
194 root 1.6 fcntl $self->[0], &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK
195 root 1.1 or croak "fcntl(O_NONBLOCK): $!";
196     }
197     $r;
198 root 1.9 }
199    
200     sub PRINT {
201     WRITE($_[0], $_[1]);
202     }
203    
204     sub PRINTF {
205     WRITE(shift, sprintf(shift,@_));
206     }
207    
208     sub GETC {
209     my $buf;
210     READ($_[0], $buf, 1);
211     $buf;
212     }
213    
214     sub BINMODE {
215     binmode $_[0][0];
216     }
217    
218     sub TELL {
219     use Carp (); Carp::croak("Coro::Handle's don't support tell()");
220     }
221    
222     sub SEEK {
223     use Carp (); Carp::croak("Coro::Handle's don't support seek()");
224     }
225    
226     sub EOF {
227     use Carp (); Carp::croak("Coro::Handle's don't support eof()");
228 root 1.1 }
229    
230     sub CLOSE {
231 root 1.6 &cleanup;
232     close $_[0][0];
233 root 1.1 }
234    
235 root 1.6 sub DESTROY {
236     &cleanup;
237 root 1.1 }
238    
239 root 1.6 sub FILENO {
240     fileno $_[0][0];
241 root 1.1 }
242    
243 root 1.8 # seems to be called for stringification (how weird), at least
244     # when DumpValue::dumpValue is used to print this.
245     sub FETCH {
246     "$_[0]<$_[0][1]>";
247     }
248    
249 root 1.1 sub readable {
250 root 1.6 ($_[0][5] ||= Coro::Event->io(
251     fd => $_[0][0],
252     desc => "$_[0][1] R",
253     timeout => $_[0][2],
254 root 1.1 poll => R+E,
255 root 1.3 ))->next->{Coro::Event}[5] & R;
256 root 1.1 }
257    
258 root 1.6 sub writable {
259     ($_[0][6] ||= Coro::Event->io(
260     fd => $_[0][0],
261     desc => "$_[0][1] W",
262     timeout => $_[0][2],
263     poll => W+E,
264     ))->next->{Coro::Event}[5] & W;
265     }
266    
267 root 1.1 sub WRITE {
268     my $len = defined $_[2] ? $_[2] : length $_[1];
269     my $ofs = $_[3];
270     my $res = 0;
271    
272     while() {
273 root 1.6 my $r = syswrite $_[0][0], $_[1], $len, $ofs;
274 root 1.1 if (defined $r) {
275     $len -= $r;
276     $ofs += $r;
277     $res += $r;
278     last unless $len;
279     } elsif ($! != Errno::EAGAIN) {
280     last;
281     }
282 root 1.6 last unless &writable;
283 root 1.1 }
284    
285     return $res;
286     }
287    
288     sub READ {
289     my $len = $_[2];
290     my $ofs = $_[3];
291     my $res = 0;
292    
293     # first deplete the read buffer
294 root 1.6 if (defined $_[0][3]) {
295     my $l = length $_[0][3];
296 root 1.1 if ($l <= $len) {
297 root 1.6 substr($_[1], $ofs) = $_[0][3]; undef $_[0][3];
298 root 1.1 $len -= $l;
299     $res += $l;
300     return $res unless $len;
301     } else {
302 root 1.6 substr($_[1], $ofs) = substr($_[0][3], 0, $len);
303     substr($_[0][3], 0, $len) = "";
304 root 1.1 return $len;
305     }
306     }
307    
308     while() {
309 root 1.6 my $r = sysread $_[0][0], $_[1], $len, $ofs;
310 root 1.1 if (defined $r) {
311     $len -= $r;
312     $ofs += $r;
313     $res += $r;
314     last unless $len && $r;
315     } elsif ($! != Errno::EAGAIN) {
316     last;
317     }
318 root 1.6 last unless &readable;
319 root 1.1 }
320    
321     return $res;
322     }
323    
324     sub READLINE {
325 root 1.6 my $irs = @_ > 1 ? $_[1] : $/;
326 root 1.1
327     while() {
328 root 1.6 my $pos = index $_[0][3], $irs;
329 root 1.1 if ($pos >= 0) {
330     $pos += length $irs;
331 root 1.6 my $res = substr $_[0][3], 0, $pos;
332     substr ($_[0][3], 0, $pos) = "";
333 root 1.1 return $res;
334     }
335 root 1.6
336     my $r = sysread $_[0][0], $_[0][3], 8192, length $_[0][3];
337 root 1.1 if (defined $r) {
338     return undef unless $r;
339 root 1.6 } elsif ($! != Errno::EAGAIN || !&readable) {
340 root 1.1 return undef;
341     }
342     }
343     }
344    
345     1;
346    
347     =head1 BUGS
348    
349     - Perl's IO-Handle model is THE bug.
350    
351     =head1 AUTHOR
352    
353     Marc Lehmann <pcg@goof.com>
354     http://www.goof.com/pcg/marc/
355    
356     =cut
357