ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro.pm
Revision: 1.21
Committed: Sun Jul 22 03:24:10 2001 UTC (22 years, 10 months ago) by root
Branch: MAIN
Changes since 1.20: +7 -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     yield;
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     + @_ + $_ + $@ + $^W), that is, a coroutine has it's own callchain, it's
30     own set of lexicals and it's own set of perl's most important global
31     variables.
32    
33 root 1.21 WARNING: When using this module, make sure that, at program end, no
34     coroutines are still running OR just call exit before falling off the
35     end. The reason for this is that some coroutine of yours might have called
36     into a C function, and falling off the end of main:: results in returning
37     to that C function instead if to the main C interpreter.
38    
39 root 1.8 =cut
40    
41     package Coro;
42    
43     use Coro::State;
44    
45     use base Exporter;
46    
47 root 1.20 $VERSION = 0.10;
48 root 1.8
49 root 1.19 @EXPORT = qw(async yield schedule terminate current);
50 root 1.8 @EXPORT_OK = qw($current);
51    
52     {
53     my @async;
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     } else {
66 root 1.17 push @attrs, $_;
67 root 1.8 }
68     }
69 root 1.17 return $old ? $old->($package, $ref, @attrs) : @attrs;
70 root 1.8 };
71     }
72    
73     sub INIT {
74 root 1.20 &async(pop @async) while @async;
75 root 1.8 }
76     }
77    
78     =item $main
79 root 1.2
80 root 1.8 This coroutine represents the main program.
81 root 1.1
82     =cut
83    
84 root 1.9 our $main = new Coro;
85 root 1.8
86 root 1.19 =item $current (or as function: current)
87 root 1.1
88 root 1.8 The current coroutine (the last coroutine switched to). The initial value is C<$main> (of course).
89 root 1.1
90 root 1.8 =cut
91    
92     # maybe some other module used Coro::Specific before...
93     if ($current) {
94     $main->{specific} = $current->{specific};
95 root 1.1 }
96    
97 root 1.9 our $current = $main;
98 root 1.19
99     sub current() { $current }
100 root 1.9
101     =item $idle
102    
103     The coroutine to switch to when no other coroutine is running. The default
104     implementation prints "FATAL: deadlock detected" and exits.
105    
106     =cut
107    
108     # should be done using priorities :(
109     our $idle = new Coro sub {
110     print STDERR "FATAL: deadlock detected\n";
111     exit(51);
112     };
113 root 1.8
114     # we really need priorities...
115 root 1.16 my @ready; # the ready queue. hehe, rather broken ;)
116 root 1.8
117     # static methods. not really.
118    
119     =head2 STATIC METHODS
120    
121     Static methods are actually functions that operate on the current process only.
122    
123     =over 4
124    
125 root 1.13 =item async { ... } [@args...]
126 root 1.8
127     Create a new asynchronous process and return it's process object
128     (usually unused). When the sub returns the new process is automatically
129     terminated.
130    
131 root 1.13 # create a new coroutine that just prints its arguments
132     async {
133     print "@_\n";
134     } 1,2,3,4;
135    
136     The coderef you submit MUST NOT be a closure that refers to variables
137     in an outer scope. This does NOT work. Pass arguments into it instead.
138    
139 root 1.8 =cut
140    
141 root 1.13 sub async(&@) {
142     my $pid = new Coro @_;
143 root 1.11 $pid->ready;
144     $pid;
145 root 1.8 }
146 root 1.1
147 root 1.8 =item schedule
148 root 1.6
149 root 1.8 Calls the scheduler. Please note that the current process will not be put
150     into the ready queue, so calling this function usually means you will
151     never be called again.
152 root 1.1
153     =cut
154    
155 root 1.8 my $prev;
156    
157     sub schedule {
158 root 1.9 # should be done using priorities :(
159     ($prev, $current) = ($current, shift @ready || $idle);
160 root 1.8 Coro::State::transfer($prev, $current);
161 root 1.1 }
162    
163 root 1.8 =item yield
164 root 1.1
165 root 1.8 Yield to other processes. This function puts the current process into the
166     ready queue and calls C<schedule>.
167 root 1.7
168 root 1.8 =cut
169    
170     sub yield {
171     $current->ready;
172     &schedule;
173     }
174 root 1.7
175 root 1.8 =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.13 $current->{_results} = [@_];
185 root 1.21 delete $current->{_coro_state};
186 root 1.8 &schedule;
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.1
227 root 1.8 sub ready {
228     push @ready, $_[0];
229     }
230 root 1.1
231 root 1.8 =back
232 root 1.2
233 root 1.8 =cut
234 root 1.2
235 root 1.8 1;
236 root 1.14
237 root 1.17 =head1 BUGS/LIMITATIONS
238 root 1.14
239     - could be faster, especially when the core would introduce special
240     support for coroutines (like it does for threads).
241     - there is still a memleak on coroutine termination that I could not
242     identify. Could be as small as a single SV.
243     - this module is not well-tested.
244 root 1.17 - if variables or arguments "disappear" (become undef) or become
245     corrupted please contact the author so he cen iron out the
246     remaining bugs.
247     - this module is not thread-safe. You must only ever use this module from
248     the same thread (this requirement might be loosened in the future to
249 root 1.20 allow per-thread schedulers, but Coro::State does not yet allow this).
250 root 1.9
251     =head1 SEE ALSO
252    
253     L<Coro::Channel>, L<Coro::Cont>, L<Coro::Specific>, L<Coro::Semaphore>,
254 root 1.10 L<Coro::Signal>, L<Coro::State>, L<Coro::Event>.
255 root 1.1
256     =head1 AUTHOR
257    
258     Marc Lehmann <pcg@goof.com>
259     http://www.goof.com/pcg/marc/
260    
261     =cut
262