ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/Event.pm
Revision: 1.17
Committed: Fri Aug 3 12:51:56 2001 UTC (22 years, 10 months ago) by root
Branch: MAIN
Changes since 1.16: +9 -6 lines
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.13;
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 sub std_cb {
82 my $w = $_[0]->w;
83 my $q = $w->private;
84 $q->[1] = $_[0];
85 if ($q->[0]) { # somebody waiting?
86 $q->[0]->ready;
87 Coro::schedule;
88 } else {
89 $w->stop;
90 }
91 }
92
93 for my $flavour (qw(idle var timer io signal)) {
94 push @EXPORT, "do_$flavour";
95 my $new = \&{"Event::$flavour"};
96 my $class = "Coro::Event::$flavour";
97 @{"${class}::ISA"} = (Coro::Event::, "Event::$flavour");
98 my $coronew = sub {
99 # how does one do method-call-by-name?
100 # my $w = $class->SUPER::$flavour(@_);
101
102 $_[0] eq Coro::Event::
103 or croak "event constructor \"Coro::Event->$flavour\" must be called as a static method";
104
105 my $q = []; # [$coro, $event]
106 my $w = $new->(
107 desc => $flavour,
108 @_,
109 cb => \&std_cb,
110 );
111 $w->private($q); # using private as attribute is pretty useless...
112 bless $w, $class; # reblessing due to broken Event
113 };
114 *{ $flavour } = $coronew;
115 *{"do_$flavour"} = sub {
116 unshift @_, Coro::Event::;
117 my $e = (&$coronew)->next;
118 $e->w->cancel;
119 $e;
120 };
121 }
122
123 sub next {
124 my $w = $_[0];
125 my $q = $w->private;
126 if ($q->[1]) { # event waiting?
127 $w->again unless $w->is_cancelled;
128 } elsif ($q->[0]) {
129 croak "only one coroutine can wait for an event";
130 } else {
131 local $q->[0] = $Coro::current;
132 Coro::schedule;
133 }
134 delete $q->[1];
135 }
136
137 =item sweep
138
139 Similar to Event::one_event and Event::sweep: The idle task is called once
140 (this has the effect of jumping back into the Event loop once to serve new
141 events).
142
143 The reason this function exists is that you sometimes want to serve events
144 while doing other work. Calling C<Coro::cede> does not work because
145 C<cede> implies that the current coroutine is runnable and does not call
146 into the Event dispatcher.
147
148 =cut
149
150 sub sweep {
151 one_event(0); # for now
152 }
153
154 =item $result = loop([$timeout])
155
156 This is the version of C<loop> you should use instead of C<Event::loop>
157 when using this module - it will ensure correct scheduling in the presence
158 of events.
159
160 =cut
161
162 sub loop(;$) {
163 local $Coro::idle = $Coro::current;
164 Coro::schedule; # become idle task, which is implicitly ready
165 &Event::loop;
166 }
167
168 =item unloop([$result])
169
170 Same as Event::unloop (provided here for your convinience only).
171
172 =cut
173
174 $Coro::idle = new Coro sub {
175 while () {
176 Event::one_event; # inefficient
177 Coro::schedule;
178 }
179 };
180
181 1;
182
183 =head1 AUTHOR
184
185 Marc Lehmann <pcg@goof.com>
186 http://www.goof.com/pcg/marc/
187
188 =cut
189