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