ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/Coro/Event/Handle.pm
Revision: 1.10
Committed: Mon Sep 24 01:36:21 2001 UTC (25 years, 1 month ago) by root
Branch: MAIN
Changes since 1.9: +13 -4 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.10 no warnings qw(uninitialized);
22 root 1.9
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 root 1.10 =item $fh->unsysread($data)
136    
137     Pushes the given data into the input buffer. The following calls to
138     read/sysread will first return this data.
139    
140 root 1.4 =cut
141    
142     sub fh {
143 root 1.10 (tied ${$_[0]})->[0];
144     }
145    
146     sub unsysread {
147     substr tied(${$_[0]})->[3], 0, 0, $_[1];
148 root 1.1 }
149    
150     package Coro::Handle::FH;
151    
152 root 1.10 no warnings qw(uninitialized);
153 root 1.9
154 root 1.1 use Fcntl ();
155     use Errno ();
156     use Carp 'croak';
157    
158     use Coro::Event;
159     use Event::Watcher qw(R W E);
160    
161 root 1.6 # formerly a hash, but we are speed-critical, so try
162     # to be faster even if it hurts.
163     #
164     # 0 FH
165     # 1 desc
166     # 2 timeout
167     # 3 rb
168 root 1.10 # 4 wb # unused
169 root 1.6 # 5 rw
170     # 6 ww
171    
172 root 1.1 sub TIEHANDLE {
173     my $class = shift;
174 root 1.6 my %args = @_;
175 root 1.1
176 root 1.6 my $self = bless [], $class;
177     $self->[0] = $args{fh};
178     $self->[1] = $args{desc};
179     $self->[2] = $args{timeout};
180     $self->[3] = "";
181     $self->[4] = "";
182 root 1.1
183 root 1.6 fcntl $self->[0], &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK
184 root 1.1 or croak "fcntl(O_NONBLOCK): $!";
185    
186     $self;
187     }
188    
189 root 1.6 sub cleanup {
190     $_[0][3] = "";
191 root 1.7 ($_[0][5])->cancel if defined $_[0][5]; $_[0][5] = undef;
192 root 1.6
193     $_[0][4] = "";
194 root 1.7 ($_[0][6])->cancel if defined $_[0][6]; $_[0][6] = undef;
195 root 1.6 }
196    
197 root 1.1 sub OPEN {
198 root 1.6 &cleanup;
199 root 1.1 my $self = shift;
200 root 1.6 my $r = @_ == 2 ? open $self->[0], $_[0], $_[1]
201     : open $self->[0], $_[0], $_[1], $_[2];
202 root 1.1 if ($r) {
203 root 1.6 fcntl $self->[0], &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK
204 root 1.1 or croak "fcntl(O_NONBLOCK): $!";
205     }
206     $r;
207 root 1.9 }
208    
209     sub PRINT {
210     WRITE($_[0], $_[1]);
211     }
212    
213     sub PRINTF {
214     WRITE(shift, sprintf(shift,@_));
215     }
216    
217     sub GETC {
218     my $buf;
219     READ($_[0], $buf, 1);
220     $buf;
221     }
222    
223     sub BINMODE {
224     binmode $_[0][0];
225     }
226    
227     sub TELL {
228     use Carp (); Carp::croak("Coro::Handle's don't support tell()");
229     }
230    
231     sub SEEK {
232     use Carp (); Carp::croak("Coro::Handle's don't support seek()");
233     }
234    
235     sub EOF {
236     use Carp (); Carp::croak("Coro::Handle's don't support eof()");
237 root 1.1 }
238    
239     sub CLOSE {
240 root 1.6 &cleanup;
241     close $_[0][0];
242 root 1.1 }
243    
244 root 1.6 sub DESTROY {
245     &cleanup;
246 root 1.1 }
247    
248 root 1.6 sub FILENO {
249     fileno $_[0][0];
250 root 1.1 }
251    
252 root 1.8 # seems to be called for stringification (how weird), at least
253     # when DumpValue::dumpValue is used to print this.
254     sub FETCH {
255     "$_[0]<$_[0][1]>";
256     }
257    
258 root 1.1 sub readable {
259 root 1.6 ($_[0][5] ||= Coro::Event->io(
260     fd => $_[0][0],
261     desc => "$_[0][1] R",
262     timeout => $_[0][2],
263 root 1.1 poll => R+E,
264 root 1.3 ))->next->{Coro::Event}[5] & R;
265 root 1.1 }
266    
267 root 1.6 sub writable {
268     ($_[0][6] ||= Coro::Event->io(
269     fd => $_[0][0],
270     desc => "$_[0][1] W",
271     timeout => $_[0][2],
272     poll => W+E,
273     ))->next->{Coro::Event}[5] & W;
274     }
275    
276 root 1.1 sub WRITE {
277     my $len = defined $_[2] ? $_[2] : length $_[1];
278     my $ofs = $_[3];
279     my $res = 0;
280    
281     while() {
282 root 1.6 my $r = syswrite $_[0][0], $_[1], $len, $ofs;
283 root 1.1 if (defined $r) {
284     $len -= $r;
285     $ofs += $r;
286     $res += $r;
287     last unless $len;
288     } elsif ($! != Errno::EAGAIN) {
289     last;
290     }
291 root 1.6 last unless &writable;
292 root 1.1 }
293    
294     return $res;
295     }
296    
297     sub READ {
298     my $len = $_[2];
299     my $ofs = $_[3];
300     my $res = 0;
301    
302     # first deplete the read buffer
303 root 1.6 if (defined $_[0][3]) {
304     my $l = length $_[0][3];
305 root 1.1 if ($l <= $len) {
306 root 1.6 substr($_[1], $ofs) = $_[0][3]; undef $_[0][3];
307 root 1.1 $len -= $l;
308     $res += $l;
309     return $res unless $len;
310     } else {
311 root 1.6 substr($_[1], $ofs) = substr($_[0][3], 0, $len);
312     substr($_[0][3], 0, $len) = "";
313 root 1.1 return $len;
314     }
315     }
316    
317     while() {
318 root 1.6 my $r = sysread $_[0][0], $_[1], $len, $ofs;
319 root 1.1 if (defined $r) {
320     $len -= $r;
321     $ofs += $r;
322     $res += $r;
323     last unless $len && $r;
324     } elsif ($! != Errno::EAGAIN) {
325     last;
326     }
327 root 1.6 last unless &readable;
328 root 1.1 }
329    
330     return $res;
331     }
332    
333     sub READLINE {
334 root 1.6 my $irs = @_ > 1 ? $_[1] : $/;
335 root 1.1
336     while() {
337 root 1.6 my $pos = index $_[0][3], $irs;
338 root 1.1 if ($pos >= 0) {
339     $pos += length $irs;
340 root 1.6 my $res = substr $_[0][3], 0, $pos;
341     substr ($_[0][3], 0, $pos) = "";
342 root 1.1 return $res;
343     }
344 root 1.6
345     my $r = sysread $_[0][0], $_[0][3], 8192, length $_[0][3];
346 root 1.1 if (defined $r) {
347     return undef unless $r;
348 root 1.6 } elsif ($! != Errno::EAGAIN || !&readable) {
349 root 1.1 return undef;
350     }
351     }
352     }
353    
354     1;
355    
356     =head1 BUGS
357    
358     - Perl's IO-Handle model is THE bug.
359    
360     =head1 AUTHOR
361    
362     Marc Lehmann <pcg@goof.com>
363     http://www.goof.com/pcg/marc/
364    
365     =cut
366