ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro.pm
Revision: 1.36
Committed: Mon Sep 24 01:36:20 2001 UTC (22 years, 8 months ago) by root
Branch: MAIN
Changes since 1.35: +2 -0 lines
Log Message:
*** empty log message ***

File Contents

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