ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro.pm
Revision: 1.37
Committed: Mon Sep 24 02:25:44 2001 UTC (22 years, 8 months ago) by root
Branch: MAIN
Changes since 1.36: +6 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Coro - coroutine process abstraction
4
5 =head1 SYNOPSIS
6
7 use Coro;
8
9 async {
10 # some asynchronous thread of execution
11 };
12
13 # alternatively create an async process like this:
14
15 sub some_func : Coro {
16 # some more async code
17 }
18
19 cede;
20
21 =head1 DESCRIPTION
22
23 This module collection manages coroutines. Coroutines are similar to
24 Threads but don't run in parallel.
25
26 This module is still experimental, see the BUGS section below.
27
28 In this module, coroutines are defined as "callchain + lexical variables
29 + @_ + $_ + $@ + $^W + C stack), that is, a coroutine has it's own
30 callchain, it's own set of lexicals and it's own set of perl's most
31 important global variables.
32
33 =cut
34
35 package Coro;
36
37 no warnings qw(uninitialized);
38
39 use Coro::State;
40
41 use base Exporter;
42
43 $VERSION = 0.5;
44
45 @EXPORT = qw(async cede schedule terminate current);
46 %EXPORT_TAGS = (
47 prio => [qw(PRIO_MAX PRIO_HIGH PRIO_NORMAL PRIO_LOW PRIO_IDLE PRIO_MIN)],
48 );
49 @EXPORT_OK = @{$EXPORT_TAGS{prio}};
50
51 {
52 my @async;
53 my $init;
54
55 # this way of handling attributes simply is NOT scalable ;()
56 sub import {
57 Coro->export_to_level(1, @_);
58 my $old = *{(caller)[0]."::MODIFY_CODE_ATTRIBUTES"}{CODE};
59 *{(caller)[0]."::MODIFY_CODE_ATTRIBUTES"} = sub {
60 my ($package, $ref) = (shift, shift);
61 my @attrs;
62 for (@_) {
63 if ($_ eq "Coro") {
64 push @async, $ref;
65 unless ($init++) {
66 eval q{
67 sub INIT {
68 &async(pop @async) while @async;
69 }
70 };
71 }
72 } else {
73 push @attrs, $_;
74 }
75 }
76 return $old ? $old->($package, $ref, @attrs) : @attrs;
77 };
78 }
79
80 }
81
82 =item $main
83
84 This coroutine represents the main program.
85
86 =cut
87
88 our $main = new Coro;
89
90 =item $current (or as function: current)
91
92 The current coroutine (the last coroutine switched to). The initial value is C<$main> (of course).
93
94 =cut
95
96 # maybe some other module used Coro::Specific before...
97 if ($current) {
98 $main->{specific} = $current->{specific};
99 }
100
101 our $current = $main;
102
103 sub current() { $current }
104
105 =item $idle
106
107 The coroutine to switch to when no other coroutine is running. The default
108 implementation prints "FATAL: deadlock detected" and exits.
109
110 =cut
111
112 # should be done using priorities :(
113 our $idle = new Coro sub {
114 print STDERR "FATAL: deadlock detected\n";
115 exit(51);
116 };
117
118 # this coroutine is necessary because a coroutine
119 # cannot destroy itself.
120 my @destroy;
121 my $manager = new Coro sub {
122 while() {
123 # by overwriting the state object with the manager we destroy it
124 # while still being able to schedule this coroutine (in case it has
125 # been readied multiple times. this is harmless since the manager
126 # can be called as many times as neccessary and will always
127 # remove itself from the runqueue
128 (pop @destroy)->{_coro_state} = $manager->{_coro_state} while @destroy;
129 &schedule;
130 }
131 };
132
133 # static methods. not really.
134
135 =head2 STATIC METHODS
136
137 Static methods are actually functions that operate on the current process only.
138
139 =over 4
140
141 =item async { ... } [@args...]
142
143 Create a new asynchronous process and return it's process object
144 (usually unused). When the sub returns the new process is automatically
145 terminated.
146
147 # create a new coroutine that just prints its arguments
148 async {
149 print "@_\n";
150 } 1,2,3,4;
151
152 The coderef you submit MUST NOT be a closure that refers to variables
153 in an outer scope. This does NOT work. Pass arguments into it instead.
154
155 =cut
156
157 sub async(&@) {
158 my $pid = new Coro @_;
159 $manager->ready; # this ensures that the stack is cloned from the manager
160 $pid->ready;
161 $pid;
162 }
163
164 =item schedule
165
166 Calls the scheduler. Please note that the current process will not be put
167 into the ready queue, so calling this function usually means you will
168 never be called again.
169
170 =cut
171
172 =item cede
173
174 "Cede" to other processes. This function puts the current process into the
175 ready queue and calls C<schedule>, which has the effect of giving up the
176 current "timeslice" to other coroutines of the same or higher priority.
177
178 =cut
179
180 =item terminate
181
182 Terminates the current process.
183
184 Future versions of this function will allow result arguments.
185
186 =cut
187
188 sub terminate {
189 $current->cancel;
190 &schedule;
191 die; # NORETURN
192 }
193
194 =back
195
196 # dynamic methods
197
198 =head2 PROCESS METHODS
199
200 These are the methods you can call on process objects.
201
202 =over 4
203
204 =item new Coro \&sub [, @args...]
205
206 Create a new process and return it. When the sub returns the process
207 automatically terminates. To start the process you must first put it into
208 the ready queue by calling the ready method.
209
210 The coderef you submit MUST NOT be a closure that refers to variables
211 in an outer scope. This does NOT work. Pass arguments into it instead.
212
213 =cut
214
215 sub _newcoro {
216 terminate &{+shift};
217 }
218
219 sub new {
220 my $class = shift;
221 bless {
222 _coro_state => (new Coro::State $_[0] && \&_newcoro, @_),
223 }, $class;
224 }
225
226 =item $process->ready
227
228 Put the current process into the ready queue.
229
230 =cut
231
232 =item $process->cancel
233
234 Like C<terminate>, but terminates the specified process instead.
235
236 =cut
237
238 sub cancel {
239 push @destroy, $_[0];
240 $manager->ready;
241 &schedule if $current == $_[0];
242 }
243
244 =item $oldprio = $process->prio($newprio)
245
246 Sets the priority of the process. Higher priority processes get run before
247 lower priority processes. Priorities are smalled signed integer (currently
248 -4 .. +3), that you can refer to using PRIO_xxx constants (use the import
249 tag :prio to get then):
250
251 PRIO_MAX > PRIO_HIGH > PRIO_NORMAL > PRIO_LOW > PRIO_IDLE > PRIO_MIN
252 3 > 1 > 0 > -1 > -3 > -4
253
254 # set priority to HIGH
255 current->prio(PRIO_HIGH);
256
257 The idle coroutine ($Coro::idle) always has a lower priority than any
258 existing coroutine.
259
260 Changing the priority of the current process will take effect immediately,
261 but changing the priority of processes in the ready queue (but not
262 running) will only take effect after the next schedule (of that
263 process). This is a bug that will be fixed in some future version.
264
265 =cut
266
267 sub prio {
268 my $old = $_[0]{prio};
269 $_[0]{prio} = $_[1] if @_ > 1;
270 $old;
271 }
272
273 =item $newprio = $process->nice($change)
274
275 Similar to C<prio>, but subtract the given value from the priority (i.e.
276 higher values mean lower priority, just as in unix).
277
278 =cut
279
280 sub nice {
281 $_[0]{prio} -= $_[1];
282 }
283
284 =back
285
286 =cut
287
288 1;
289
290 =head1 BUGS/LIMITATIONS
291
292 - you must make very sure that no coro is still active on global destruction.
293 very bad things might happen otherwise (usually segfaults).
294 - this module is not thread-safe. You must only ever use this module from
295 the same thread (this requirement might be loosened in the future to
296 allow per-thread schedulers, but Coro::State does not yet allow this).
297
298 =head1 SEE ALSO
299
300 L<Coro::Channel>, L<Coro::Cont>, L<Coro::Specific>, L<Coro::Semaphore>,
301 L<Coro::Signal>, L<Coro::State>, L<Coro::Event>, L<Coro::RWLock>,
302 L<Coro::Handle>, L<Coro::Socket>.
303
304 =head1 AUTHOR
305
306 Marc Lehmann <pcg@goof.com>
307 http://www.goof.com/pcg/marc/
308
309 =cut
310