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