ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro.pm
Revision: 1.13
Committed: Tue Jul 17 00:24:14 2001 UTC (22 years, 11 months ago) by root
Branch: MAIN
Changes since 1.12: +26 -9 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 =head1 NAME
2
3 Coro - coroutine process abstraction
4
5 =head1 SYNOPSIS
6
7 use Coro;
8
9 async {
10 # some asynchronous thread of execution
11 };
12
13 # alternatively create an async process like this:
14
15 sub some_func : Coro {
16 # some more async code
17 }
18
19 yield;
20
21 =head1 DESCRIPTION
22
23 =cut
24
25 package Coro;
26
27 use Coro::State;
28
29 use base Exporter;
30
31 $VERSION = 0.05;
32
33 @EXPORT = qw(async yield schedule terminate);
34 @EXPORT_OK = qw($current);
35
36 {
37 use subs 'async';
38
39 my @async;
40
41 # this way of handling attributes simply is NOT scalable ;()
42 sub import {
43 Coro->export_to_level(1, @_);
44 my $old = *{(caller)[0]."::MODIFY_CODE_ATTRIBUTES"}{CODE};
45 *{(caller)[0]."::MODIFY_CODE_ATTRIBUTES"} = sub {
46 my ($package, $ref) = (shift, shift);
47 my @attrs;
48 for (@_) {
49 if ($_ eq "Coro") {
50 push @async, $ref;
51 } else {
52 push @attrs, @_;
53 }
54 }
55 return $old ? $old->($package, $name, @attrs) : @attrs;
56 };
57 }
58
59 sub INIT {
60 async pop @async while @async;
61 }
62 }
63
64 =item $main
65
66 This coroutine represents the main program.
67
68 =cut
69
70 our $main = new Coro;
71
72 =item $current
73
74 The current coroutine (the last coroutine switched to). The initial value is C<$main> (of course).
75
76 =cut
77
78 # maybe some other module used Coro::Specific before...
79 if ($current) {
80 $main->{specific} = $current->{specific};
81 }
82
83 our $current = $main;
84
85 =item $idle
86
87 The coroutine to switch to when no other coroutine is running. The default
88 implementation prints "FATAL: deadlock detected" and exits.
89
90 =cut
91
92 # should be done using priorities :(
93 our $idle = new Coro sub {
94 print STDERR "FATAL: deadlock detected\n";
95 exit(51);
96 };
97
98 # we really need priorities...
99 ## my @ready; #d#
100 our @ready = (); # the ready queue. hehe, rather broken ;)
101
102 # static methods. not really.
103
104 =head2 STATIC METHODS
105
106 Static methods are actually functions that operate on the current process only.
107
108 =over 4
109
110 =item async { ... } [@args...]
111
112 Create a new asynchronous process and return it's process object
113 (usually unused). When the sub returns the new process is automatically
114 terminated.
115
116 # create a new coroutine that just prints its arguments
117 async {
118 print "@_\n";
119 } 1,2,3,4;
120
121 The coderef you submit MUST NOT be a closure that refers to variables
122 in an outer scope. This does NOT work. Pass arguments into it instead.
123
124 =cut
125
126 sub async(&@) {
127 my $pid = new Coro @_;
128 $pid->ready;
129 $pid;
130 }
131
132 =item schedule
133
134 Calls the scheduler. Please note that the current process will not be put
135 into the ready queue, so calling this function usually means you will
136 never be called again.
137
138 =cut
139
140 my $prev;
141
142 sub schedule {
143 # should be done using priorities :(
144 ($prev, $current) = ($current, shift @ready || $idle);
145 Coro::State::transfer($prev, $current);
146 }
147
148 =item yield
149
150 Yield to other processes. This function puts the current process into the
151 ready queue and calls C<schedule>.
152
153 =cut
154
155 sub yield {
156 $current->ready;
157 &schedule;
158 }
159
160 =item terminate
161
162 Terminates the current process.
163
164 Future versions of this function will allow result arguments.
165
166 =cut
167
168 sub terminate {
169 $current->{_results} = [@_];
170 &schedule;
171 }
172
173 =back
174
175 # dynamic methods
176
177 =head2 PROCESS METHODS
178
179 These are the methods you can call on process objects.
180
181 =over 4
182
183 =item new Coro \&sub [, @args...]
184
185 Create a new process and return it. When the sub returns the process
186 automatically terminates. To start the process you must first put it into
187 the ready queue by calling the ready method.
188
189 The coderef you submit MUST NOT be a closure that refers to variables
190 in an outer scope. This does NOT work. Pass arguments into it instead.
191
192 =cut
193
194 sub _newcoro {
195 terminate &{+shift};
196 }
197
198 sub new {
199 my $class = shift;
200 bless {
201 _coro_state => (new Coro::State $_[0] && \&_newcoro, @_),
202 }, $class;
203 }
204
205 =item $process->ready
206
207 Put the current process into the ready queue.
208
209 =cut
210
211 sub ready {
212 push @ready, $_[0];
213 }
214
215 =back
216
217 =cut
218
219 1;
220
221 =head1 SEE ALSO
222
223 L<Coro::Channel>, L<Coro::Cont>, L<Coro::Specific>, L<Coro::Semaphore>,
224 L<Coro::Signal>, L<Coro::State>, L<Coro::Event>.
225
226 =head1 AUTHOR
227
228 Marc Lehmann <pcg@goof.com>
229 http://www.goof.com/pcg/marc/
230
231 =cut
232