ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Event/Handle.pm
Revision: 1.4
Committed: Sun Sep 2 00:54:00 2001 UTC (22 years, 9 months ago) by root
Branch: MAIN
Changes since 1.3: +15 -3 lines
Log Message:
*** empty log message ***

File Contents

# Content
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 sub readable { tied(${$_[0]})->readable }
73 sub writable { tied(${$_[0]})->writable }
74
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 sub fileno { tied(${$_[0]})->FILENO }
101 sub close { tied(${$_[0]})->CLOSE }
102
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 my $self = tied(${$_[0]});
114 if (@_) {
115 $self->{timeout} = $_[0];
116 $self->{rw}->timeout($_[0]) if $self->{rw};
117 $self->{ww}->timeout($_[0]) if $self->{ww};
118 }
119 $self->{timeout};
120 }
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 }
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 sub TIEHANDLE {
146 my $class = shift;
147
148 my $self = bless {
149 rb => "",
150 wb => "",
151 @_,
152 }, $class;
153
154 fcntl $self->{fh}, &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK
155 or croak "fcntl(O_NONBLOCK): $!";
156
157 $self;
158 }
159
160 sub OPEN {
161 my $self = shift;
162 $self->CLOSE;
163 my $r = @_ == 2 ? open $self->{fh}, $_[0], $_[1]
164 : open $self->{fh}, $_[0], $_[1], $_[2];
165 if ($r) {
166 fcntl $self->{fh}, &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK
167 or croak "fcntl(O_NONBLOCK): $!";
168 }
169 $r;
170 }
171
172 sub CLOSE {
173 my $self = shift;
174 $self->{rb} =
175 $self->{wb} = "";
176 (delete $self->{rw})->cancel if exists $self->{rw};
177 (delete $self->{ww})->cancel if exists $self->{ww};
178 close $self->{fh};
179 }
180
181 sub FILENO {
182 fileno $_[0]->{fh};
183 }
184
185 sub writable {
186 ($_[0]->{ww} ||= Coro::Event->io(
187 fd => $_[0]->{fh},
188 desc => "$_[0]->{desc} WW",
189 timeout => $_[0]->{timeout},
190 poll => W+E,
191 ))->next->{Coro::Event}[5] & W;
192 }
193
194 sub readable {
195 ($_[0]->{rw} ||= Coro::Event->io(
196 fd => $_[0]->{fh},
197 desc => "$_[0]->{desc} RW",
198 timeout => $_[0]->{timeout},
199 poll => R+E,
200 ))->next->{Coro::Event}[5] & R;
201 }
202
203 sub WRITE {
204 my $self = $_[0];
205 my $len = defined $_[2] ? $_[2] : length $_[1];
206 my $ofs = $_[3];
207 my $res = 0;
208
209 while() {
210 my $r = syswrite $self->{fh}, $_[1], $len, $ofs;
211 if (defined $r) {
212 $len -= $r;
213 $ofs += $r;
214 $res += $r;
215 last unless $len;
216 } elsif ($! != Errno::EAGAIN) {
217 last;
218 }
219 last unless $self->writable;
220 }
221
222 return $res;
223 }
224
225 sub READ {
226 my $self = $_[0];
227 my $len = $_[2];
228 my $ofs = $_[3];
229 my $res = 0;
230
231 # first deplete the read buffer
232 if (exists $self->{rb}) {
233 my $l = length $self->{rb};
234 if ($l <= $len) {
235 substr($_[1], $ofs) = delete $self->{rb};
236 $len -= $l;
237 $res += $l;
238 return $res unless $len;
239 } else {
240 substr($_[1], $ofs) = substr($self->{rb}, 0, $len);
241 substr($self->{rb}, 0, $len) = "";
242 return $len;
243 }
244 }
245
246 while() {
247 my $r = sysread $self->{fh}, $_[1], $len, $ofs;
248 if (defined $r) {
249 $len -= $r;
250 $ofs += $r;
251 $res += $r;
252 last unless $len && $r;
253 } elsif ($! != Errno::EAGAIN) {
254 last;
255 }
256 last unless $self->readable;
257 }
258
259 return $res;
260 }
261
262 sub READLINE {
263 my $self = shift;
264 my $irs = @_ ? shift : $/;
265
266 while() {
267 my $pos = index $self->{rb}, $irs;
268 if ($pos >= 0) {
269 $pos += length $irs;
270 my $res = substr $self->{rb}, 0, $pos;
271 substr ($self->{rb}, 0, $pos) = "";
272 return $res;
273 }
274 my $r = sysread $self->{fh}, $self->{rb}, 8192, length $self->{rb};
275 if (defined $r) {
276 return undef unless $r;
277 } elsif ($! != Errno::EAGAIN || !$self->readable) {
278 return undef;
279 }
280 }
281 }
282
283 sub DESTROY {
284 &CLOSE;
285 }
286
287 1;
288
289 =head1 BUGS
290
291 - Perl's IO-Handle model is THE bug.
292
293 =head1 AUTHOR
294
295 Marc Lehmann <pcg@goof.com>
296 http://www.goof.com/pcg/marc/
297
298 =cut
299