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