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