ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Event/Event.pm
Revision: 1.1
Committed: Thu Aug 16 21:55:34 2001 UTC (22 years, 9 months ago) by root
Branch: MAIN
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Coro::Event - do events the coro-way
4
5 =head1 SYNOPSIS
6
7 use Coro;
8 use Coro::Event;
9
10 sub keyboard : Coro {
11 my $w = Coro::Event->io(fd => *STDIN, poll => 'r');
12 while() {
13 print "cmd> ";
14 my $ev = $w->next; my $cmd = <STDIN>;
15 unloop unless $cmd ne "";
16 print "data> ";
17 my $ev = $w->next; my $data = <STDIN>;
18 }
19 }
20
21 &loop;
22
23 =head1 DESCRIPTION
24
25 This module enables you to create programs using the powerful Event model
26 (and module), while retaining the linear style known from simple or
27 threaded programs.
28
29 This module provides a method and a function for every watcher type
30 (I<flavour>) (see L<Event>). The only difference between these and the
31 watcher constructors from Event is that you do not specify a callback
32 function - it will be managed by this module.
33
34 Your application should just create all necessary coroutines and then call
35 Coro::Event->main.
36
37 =over 4
38
39 =cut
40
41 package Coro::Event;
42
43 no warnings;
44
45 use Carp;
46
47 use Coro;
48 use Event qw(unloop); # we are re-exporting this, cooool!
49
50 use base 'Exporter';
51
52 @EXPORT = qw(loop unloop sweep);
53
54 $VERSION = 0.45;
55
56 =item $w = Coro::Event->flavour(args...)
57
58 Create and return a watcher of the given type.
59
60 Examples:
61
62 my $reader = Coro::Event->io(fd => $filehandle, poll => 'r');
63 $reader->next;
64
65 =cut
66
67 =item $w->next
68
69 Return the next event of the event queue of the watcher.
70
71 =cut
72
73 =item do_flavour(args...)
74
75 Create a watcher of the given type and immediately call it's next
76 method. This is less efficient then calling the constructor once and the
77 next method often, but it does save typing sometimes.
78
79 =cut
80
81 #Event->add_hooks(prepare => sub {
82 # &Coro::cede while &Coro::nready;
83 # 1e6;
84 #});
85
86 sub std_cb {
87 my $w = $_[0]->w;
88 my $q = $w->private;
89 $q->[1] = $_[0];
90 if ($q->[0]) { # somebody waiting?
91 $q->[0]->ready;
92 &Coro::schedule;
93 } else {
94 $w->stop;
95 }
96 }
97
98 for my $flavour (qw(idle var timer io signal)) {
99 push @EXPORT, "do_$flavour";
100 my $new = \&{"Event::$flavour"};
101 my $class = "Coro::Event::$flavour";
102 @{"${class}::ISA"} = (Coro::Event::, "Event::$flavour");
103 my $coronew = sub {
104 # how does one do method-call-by-name?
105 # my $w = $class->SUPER::$flavour(@_);
106
107 $_[0] eq Coro::Event::
108 or croak "event constructor \"Coro::Event->$flavour\" must be called as a static method";
109
110 my $q = []; # [$coro, $event]
111 my $w = $new->(
112 desc => $flavour,
113 @_,
114 cb => \&std_cb,
115 );
116 $w->private($q); # using private as attribute is pretty useless...
117 bless $w, $class; # reblessing due to broken Event
118 };
119 *{ $flavour } = $coronew;
120 *{"do_$flavour"} = sub {
121 unshift @_, Coro::Event::;
122 my $e = (&$coronew)->next;
123 $e->w->cancel;
124 $e;
125 };
126 }
127
128 sub next {
129 my $w = $_[0];
130 my $q = $w->private;
131 if ($q->[1]) { # event waiting?
132 $w->again unless $w->is_cancelled;
133 } elsif ($q->[0]) {
134 croak "only one coroutine can wait for an event";
135 } else {
136 local $q->[0] = $Coro::current;
137 &Coro::schedule;
138 }
139 pop @$q;
140 }
141
142 =item sweep
143
144 Similar to Event::one_event and Event::sweep: The idle task is called once
145 (this has the effect of jumping back into the Event loop once to serve new
146 events).
147
148 The reason this function exists is that you sometimes want to serve events
149 while doing other work. Calling C<Coro::cede> does not work because
150 C<cede> implies that the current coroutine is runnable and does not call
151 into the Event dispatcher.
152
153 =cut
154
155 sub sweep {
156 one_event(0); # for now
157 }
158
159 =item $result = loop([$timeout])
160
161 This is the version of C<loop> you should use instead of C<Event::loop>
162 when using this module - it will ensure correct scheduling in the presence
163 of events.
164
165 =begin comment
166
167 Unlike loop's counterpart it is not an error when no watchers are active -
168 loop silently returns in this case, as if unloop(undef) were called.
169
170 =end comment
171
172 =cut
173
174 sub loop(;$) {
175 local $Coro::idle = $Coro::current;
176 Coro::schedule; # become idle task, which is implicitly ready
177 &Event::loop;
178 }
179
180 =item unloop([$result])
181
182 Same as Event::unloop (provided here for your convinience only).
183
184 =cut
185
186 $Coro::idle = new Coro sub {
187 while () {
188 Event::one_event; # inefficient
189 Coro::schedule;
190 }
191 };
192
193 1;
194
195 =head1 AUTHOR
196
197 Marc Lehmann <pcg@goof.com>
198 http://www.goof.com/pcg/marc/
199
200 =cut
201