ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/Handle.pm
Revision: 1.5
Committed: Sat Jul 28 01:41:58 2001 UTC (22 years, 10 months ago) by root
Branch: MAIN
Changes since 1.4: +22 -4 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.13;
25
26 @EXPORT = qw(unblock);
27
28 =item $fh = new_from_fh Coro::Handle $fhandle
29
30 Create a new non-blocking io-handle using the given
31 perl-filehandle. Returns undef if no fhandle is given.
32
33 =cut
34
35 sub new_from_fh {
36 my $class = shift;
37 my $fh = shift or return;
38 my $self = do { local *Coro::Handle };
39
40 tie $self, Coro::Handle::FH, $fh;
41
42 my $_fh = select bless \$self, $class; $| = 1; select $_fh;
43 }
44
45 =item $fh = unblock $fh
46
47 This is a convinience function that just calls C<new_from_fh> on the given
48 filehandle. Use it to replace a normal perl filehandle by a non-blocking
49 equivalent.
50
51 =cut
52
53 sub unblock($) {
54 new_from_fh Coro::Handle $_[0];
55 }
56
57 sub read { read $_[0], $_[1], $_[2], $_[3] }
58 sub sysread { sysread $_[0], $_[1], $_[2], $_[3] }
59 sub syswrite { syswrite $_[0], $_[1], $_[2], $_[3] }
60
61 =item $fh->writable, $fh->readable
62
63 Wait until the filehandle is readable or writable (and return true) or
64 until an error condition happens (and return false).
65
66 =cut
67
68 sub readable { tied(${$_[0]})->readable }
69 sub writable { tied(${$_[0]})->writable }
70
71 =item $fh->readline([$terminator])
72
73 Like the builtin of the same name, but allows you to specify the input
74 record separator in a coroutine-safe manner (i.e. not usign a global
75 variable).
76
77 =cut
78
79 sub readline { tied(${+shift})->READLINE(@_) }
80
81 =item $fh->autoflush([...])
82
83 Always returns true, arguments are being ignored (exists for compatibility
84 only).
85
86 =cut
87
88 sub autoflush { !0 }
89
90 package Coro::Handle::FH;
91
92 use Fcntl ();
93 use Errno ();
94
95 use Coro::Event;
96 use Event::Watcher qw(R W E);
97
98 use base 'Tie::Handle';
99
100 sub TIEHANDLE {
101 my ($class, $fh) = @_;
102
103 fcntl $fh, &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK
104 or die "fcntl(O_NONBLOCK): $!";
105
106 bless {
107 fh => $fh,
108 rb => "",
109 wb => "",
110 }, $_[0];
111
112 }
113
114 sub OPEN {
115 my $self = shift;
116 $self->CLOSE;
117 my $r = @_ == 2 ? open $self->{fh}, $_[0], $_[1]
118 : open $self->{fh}, $_[0], $_[1], $_[2];
119 if ($r) {
120 fcntl $self->{fh}, &Fcntl::F_SETFL, &Fcntl::O_NONBLOCK
121 or die "fcntl(O_NONBLOCK): $!";
122 }
123 $r;
124 }
125
126 sub CLOSE {
127 my $self = shift;
128 $self->{rb} =
129 $self->{wb} = "";
130 (delete $self->{rw})->cancel if $self->{rw};
131 (delete $self->{ww})->cancel if $self->{rw};
132 close $self->{fh};
133 }
134
135 sub writable {
136 ($_[0]->{ww} ||= Coro::Event->io(fd => $_[0]->{fh}, poll => W+E))->next->got & W;
137 }
138
139 sub readable {
140 ($_[0]->{rw} ||= Coro::Event->io(fd => $_[0]->{fh}, poll => R+E))->next->got & R;
141 }
142
143 sub WRITE {
144 my $self = $_[0];
145 my $len = defined $_[2] ? $_[2] : length $_[1];
146 my $ofs = $_[3];
147 my $res = 0;
148
149 while() {
150 my $r = syswrite $self->{fh}, $_[1], $len, $ofs;
151 if (defined $r) {
152 $len -= $r;
153 $ofs += $r;
154 $res += $r;
155 last unless $len;
156 } elsif ($! != Errno::EAGAIN) {
157 last;
158 }
159 last unless $self->writable;
160 }
161
162 return $res;
163 }
164
165 sub READ {
166 my $self = $_[0];
167 my $len = $_[2];
168 my $ofs = $_[3];
169 my $res = 0;
170
171 while() {
172 my $r = sysread $self->{fh}, $_[1], $len, $ofs;
173 if (defined $r) {
174 $len -= $r;
175 $ofs += $r;
176 $res += $r;
177 last unless $len && $r;
178 } elsif ($! != Errno::EAGAIN) {
179 last;
180 }
181 last unless $self->readable;
182 }
183
184 return $res;
185 }
186
187 sub READLINE {
188 my $self = shift;
189 my $irs = @_ ? shift : $/;
190
191 while() {
192 my $pos = index $self->{rb}, $irs;
193 if ($pos >= 0) {
194 $pos += length $/;
195 my $res = substr $self->{rb}, 0, $pos;
196 substr ($self->{rb}, 0, $pos) = "";
197 return $res;
198 }
199 my $r = sysread $self->{fh}, $self->{rb}, 8192, length $self->{rb};
200 if (defined $r) {
201 return undef unless $r;
202 } elsif ($! != Errno::EAGAIN || !$self->readable) {
203 return undef;
204 }
205 }
206 }
207
208 1;
209
210 =head1 BUGS
211
212 - Perl's IO-Handle model is THE bug.
213 - READLINE cannot be mixed with other forms of input.
214
215 =head1 AUTHOR
216
217 Marc Lehmann <pcg@goof.com>
218 http://www.goof.com/pcg/marc/
219
220 =cut
221