ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro.pm
Revision: 1.30
Committed: Sat Aug 11 19:59:19 2001 UTC (22 years, 10 months ago) by root
Branch: MAIN
Changes since 1.29: +0 -20 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     use Coro::State;
38    
39     use base Exporter;
40    
41 root 1.29 $VERSION = 0.45;
42 root 1.8
43 root 1.22 @EXPORT = qw(async cede schedule terminate current);
44 root 1.8 @EXPORT_OK = qw($current);
45    
46     {
47     my @async;
48 root 1.26 my $init;
49 root 1.8
50     # this way of handling attributes simply is NOT scalable ;()
51     sub import {
52     Coro->export_to_level(1, @_);
53     my $old = *{(caller)[0]."::MODIFY_CODE_ATTRIBUTES"}{CODE};
54     *{(caller)[0]."::MODIFY_CODE_ATTRIBUTES"} = sub {
55     my ($package, $ref) = (shift, shift);
56     my @attrs;
57     for (@_) {
58     if ($_ eq "Coro") {
59     push @async, $ref;
60 root 1.26 unless ($init++) {
61     eval q{
62     sub INIT {
63     &async(pop @async) while @async;
64     }
65     };
66     }
67 root 1.8 } else {
68 root 1.17 push @attrs, $_;
69 root 1.8 }
70     }
71 root 1.17 return $old ? $old->($package, $ref, @attrs) : @attrs;
72 root 1.8 };
73     }
74    
75     }
76    
77     =item $main
78 root 1.2
79 root 1.8 This coroutine represents the main program.
80 root 1.1
81     =cut
82    
83 root 1.9 our $main = new Coro;
84 root 1.8
85 root 1.19 =item $current (or as function: current)
86 root 1.1
87 root 1.8 The current coroutine (the last coroutine switched to). The initial value is C<$main> (of course).
88 root 1.1
89 root 1.8 =cut
90    
91     # maybe some other module used Coro::Specific before...
92     if ($current) {
93     $main->{specific} = $current->{specific};
94 root 1.1 }
95    
96 root 1.9 our $current = $main;
97 root 1.19
98     sub current() { $current }
99 root 1.9
100     =item $idle
101    
102     The coroutine to switch to when no other coroutine is running. The default
103     implementation prints "FATAL: deadlock detected" and exits.
104    
105     =cut
106    
107     # should be done using priorities :(
108     our $idle = new Coro sub {
109     print STDERR "FATAL: deadlock detected\n";
110     exit(51);
111     };
112 root 1.8
113 root 1.24 # this coroutine is necessary because a coroutine
114     # cannot destroy itself.
115     my @destroy;
116     my $manager = new Coro sub {
117     while() {
118     delete ((pop @destroy)->{_coro_state}) while @destroy;
119     &schedule;
120     }
121     };
122    
123 root 1.8 # static methods. not really.
124    
125     =head2 STATIC METHODS
126    
127     Static methods are actually functions that operate on the current process only.
128    
129     =over 4
130    
131 root 1.13 =item async { ... } [@args...]
132 root 1.8
133     Create a new asynchronous process and return it's process object
134     (usually unused). When the sub returns the new process is automatically
135     terminated.
136    
137 root 1.13 # create a new coroutine that just prints its arguments
138     async {
139     print "@_\n";
140     } 1,2,3,4;
141    
142     The coderef you submit MUST NOT be a closure that refers to variables
143     in an outer scope. This does NOT work. Pass arguments into it instead.
144    
145 root 1.8 =cut
146    
147 root 1.13 sub async(&@) {
148     my $pid = new Coro @_;
149 root 1.24 $manager->ready; # this ensures that the stack is cloned from the manager
150 root 1.11 $pid->ready;
151     $pid;
152 root 1.8 }
153 root 1.1
154 root 1.8 =item schedule
155 root 1.6
156 root 1.8 Calls the scheduler. Please note that the current process will not be put
157     into the ready queue, so calling this function usually means you will
158     never be called again.
159 root 1.1
160     =cut
161    
162 root 1.22 =item cede
163 root 1.1
164 root 1.22 "Cede" to other processes. This function puts the current process into the
165     ready queue and calls C<schedule>, which has the effect of giving up the
166     current "timeslice" to other coroutines of the same or higher priority.
167 root 1.7
168 root 1.8 =cut
169    
170     =item terminate
171 root 1.7
172 root 1.8 Terminates the current process.
173 root 1.1
174 root 1.13 Future versions of this function will allow result arguments.
175    
176 root 1.1 =cut
177    
178 root 1.8 sub terminate {
179 root 1.28 $current->cancel;
180 root 1.23 &schedule;
181 root 1.28 die; # NORETURN
182 root 1.1 }
183 root 1.6
184 root 1.8 =back
185    
186     # dynamic methods
187    
188     =head2 PROCESS METHODS
189    
190     These are the methods you can call on process objects.
191 root 1.6
192 root 1.8 =over 4
193    
194 root 1.13 =item new Coro \&sub [, @args...]
195 root 1.8
196     Create a new process and return it. When the sub returns the process
197     automatically terminates. To start the process you must first put it into
198     the ready queue by calling the ready method.
199 root 1.6
200 root 1.13 The coderef you submit MUST NOT be a closure that refers to variables
201     in an outer scope. This does NOT work. Pass arguments into it instead.
202    
203 root 1.6 =cut
204    
205 root 1.13 sub _newcoro {
206     terminate &{+shift};
207     }
208    
209 root 1.8 sub new {
210     my $class = shift;
211     bless {
212 root 1.13 _coro_state => (new Coro::State $_[0] && \&_newcoro, @_),
213 root 1.8 }, $class;
214     }
215 root 1.6
216 root 1.8 =item $process->ready
217 root 1.1
218 root 1.8 Put the current process into the ready queue.
219 root 1.1
220 root 1.8 =cut
221 root 1.28
222     =item $process->cancel
223    
224     Like C<terminate>, but terminates the specified process instead.
225    
226     =cut
227    
228     sub cancel {
229     push @destroy, $_[0];
230     $manager->ready;
231 root 1.8 }
232 root 1.1
233 root 1.8 =back
234 root 1.2
235 root 1.8 =cut
236 root 1.2
237 root 1.8 1;
238 root 1.14
239 root 1.17 =head1 BUGS/LIMITATIONS
240 root 1.14
241     - could be faster, especially when the core would introduce special
242     support for coroutines (like it does for threads).
243     - there is still a memleak on coroutine termination that I could not
244     identify. Could be as small as a single SV.
245     - this module is not well-tested.
246 root 1.17 - if variables or arguments "disappear" (become undef) or become
247     corrupted please contact the author so he cen iron out the
248     remaining bugs.
249     - this module is not thread-safe. You must only ever use this module from
250     the same thread (this requirement might be loosened in the future to
251 root 1.20 allow per-thread schedulers, but Coro::State does not yet allow this).
252 root 1.9
253     =head1 SEE ALSO
254    
255     L<Coro::Channel>, L<Coro::Cont>, L<Coro::Specific>, L<Coro::Semaphore>,
256 root 1.25 L<Coro::Signal>, L<Coro::State>, L<Coro::Event>, L<Coro::RWLock>,
257 root 1.26 L<Coro::Handle>, L<Coro::Socket>.
258 root 1.1
259     =head1 AUTHOR
260    
261     Marc Lehmann <pcg@goof.com>
262     http://www.goof.com/pcg/marc/
263    
264     =cut
265