ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/Event.pm
Revision: 1.12
Committed: Sun Jul 22 03:24:10 2001 UTC (22 years, 10 months ago) by root
Branch: MAIN
Changes since 1.11: +6 -7 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 'Event';
51 use base 'Exporter';
52
53 @EXPORT = qw(loop unloop sweep);
54
55 $VERSION = 0.10;
56
57 =item $w = Coro::Event->flavour(args...)
58
59 Create and return a watcher of the given type.
60
61 Examples:
62
63 my $reader = Coro::Event->io(fd => $filehandle, poll => 'r');
64 $reader->next;
65
66 =cut
67
68 =item $w->next
69
70 Return the next event of the event queue of the watcher.
71
72 =cut
73
74 =item do_flavour(args...)
75
76 Create a watcher of the given type and immediately call it's next
77 method. This is less efficient then calling the constructor once and the
78 next method often, but it does save typing sometimes.
79
80 =cut
81
82 for my $flavour (qw(idle var timer io signal)) {
83 push @EXPORT, "do_$flavour";
84 my $new = \&{"Event::$flavour"};
85 my $class = "Coro::Event::$flavour";
86 @{"${class}::ISA"} = ("Coro::Event", "Event::$flavour");
87 my $coronew = sub {
88 # how does one do method-call-by-name?
89 # my $w = $class->SUPER::$flavour(@_);
90
91 $_[0] eq Coro::Event::
92 or croak "event constructor \"Coro::Event->$flavour\" must be called as a static method";
93
94 my $w;
95 my $q = []; # [$coro, $event]
96 $w = $new->(@_, cb => sub {
97 $q->[1] = $_[0];
98 if ($q->[0]) { # somebody waiting?
99 $q->[0]->ready;
100 Coro::schedule;
101 } else {
102 $w->stop;
103 }
104 });
105 $w->private($q); # using private as attribute is pretty useless...
106 bless $w, $class; # reblessing due to broken Event
107 };
108 *{ $flavour } = $coronew;
109 *{"do_$flavour"} = sub {
110 unshift @_, Coro::Event::;
111 (&$coronew)->next;
112 };
113 }
114
115 sub next {
116 my $q = $_[0]->private;
117 croak "only one coroutine can wait for an event" if $q->[0];
118 if (!$q->[1]) { # no event waiting?
119 local $q->[0] = $Coro::current;
120 Coro::schedule;
121 } else {
122 $_[0]->again unless $_[0]->is_canceled;
123 }
124 delete $q->[1];
125 }
126
127 =item sweep
128
129 Similar to Event::one_event and Event::sweep: The idle task is called once
130 (this has the effect of jumping back into the Event loop once to serve new
131 events).
132
133 The reason this function exists is that you sometimes want to serve events
134 while doing other work. Calling C<Coro::yield> does not work because
135 C<yield> implies that the current coroutine is runnable and does not call
136 into the Event dispatcher.
137
138 =cut
139
140 sub sweep {
141 $Coro::idle->ready;
142 Coro::yield;
143 }
144
145 =item $result = loop([$timeout])
146
147 This is the version of C<loop> you should use instead of C<Event::loop>
148 when using this module - it will ensure correct scheduling in the presence
149 of events.
150
151 =cut
152
153 sub loop(;$) {
154 local $Coro::idle = $Coro::current;
155 Coro::schedule; # become idle task, which is implicitly ready
156 &Event::loop;
157 }
158
159 =item unloop([$result])
160
161 Same as Event::unloop (provided here for your convinience only).
162
163 =cut
164
165 $Coro::idle = new Coro sub {
166 while () {
167 Event::one_event; # inefficient
168 Coro::schedule;
169 }
170 };
171
172 1;
173
174 =head1 AUTHOR
175
176 Marc Lehmann <pcg@goof.com>
177 http://www.goof.com/pcg/marc/
178
179 =cut
180