ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro.pm
(Generate patch)

Comparing Coro/Coro.pm (file contents):
Revision 1.3 by root, Tue Jul 3 04:02:31 2001 UTC vs.
Revision 1.8 by root, Sat Jul 14 22:14:21 2001 UTC

1=head1 NAME 1=head1 NAME
2 2
3Coro - create and manage coroutines 3Coro - coroutine process abstraction
4 4
5=head1 SYNOPSIS 5=head1 SYNOPSIS
6 6
7 use Coro; 7 use Coro;
8 8
9 $new = new Coro sub { 9 async {
10 print "in coroutine, switching back\n"; 10 # some asynchronous thread of execution
11 $Coro::main->resume;
12 print "in coroutine again, switching back\n";
13 $Coro::main->resume;
14 }; 11 };
15 12
16 print "in main, switching to coroutine\n"; 13 # alternatively create an async process like this:
17 $new->resume; 14
18 print "back in main, switch to coroutine again\n"; 15 sub some_func : Coro {
19 $new->resume; 16 # some more async code
20 print "back in main\n"; 17 }
18
19 yield;
21 20
22=head1 DESCRIPTION 21=head1 DESCRIPTION
23
24This module implements coroutines. Coroutines, similar to continuations,
25allow you to run more than one "thread of execution" in parallel. Unlike
26threads this, only voluntary switching is used so locking problems are
27greatly reduced.
28
29Although this is the "main" module of the Coro family it provides only
30low-level functionality. See L<Coro::Process> and related modules for a
31more useful process abstraction including scheduling.
32
33=over 4
34 22
35=cut 23=cut
36 24
37package Coro; 25package Coro;
38 26
39BEGIN { 27use Coro::State;
40 $VERSION = 0.01;
41 28
42 require XSLoader; 29use base Exporter;
43 XSLoader::load Coro, $VERSION; 30
31$VERSION = 0.03;
32
33@EXPORT = qw(async yield schedule);
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 }
44} 62}
63
64my $idle = new Coro sub {
65 &yield while 1;
66};
45 67
46=item $main 68=item $main
47 69
48This coroutine represents the main program. 70This coroutine represents the main program.
71
72=cut
73
74$main = new Coro;
49 75
50=item $current 76=item $current
51 77
52The current coroutine (the last coroutine switched to). The initial value is C<$main> (of course). 78The current coroutine (the last coroutine switched to). The initial value is C<$main> (of course).
53 79
54=cut 80=cut
55 81
56$main = $current = _newprocess { 82# maybe some other module used Coro::Specific before...
57 # never being called 83if ($current) {
58}; 84 $main->{specific} = $current->{specific};
85}
59 86
60=item $error, $error_msg, $error_coro 87$current = $main;
61 88
62This coroutine will be called on fatal errors. C<$error_msg> and 89# we really need priorities...
63C<$error_coro> return the error message and the error-causing coroutine, 90my @ready = (); # the ready queue. hehe, rather broken ;)
64respectively. 91
92# static methods. not really.
93
94=head2 STATIC METHODS
95
96Static methods are actually functions that operate on the current process only.
97
98=over 4
99
100=item async { ... };
101
102Create a new asynchronous process and return it's process object
103(usually unused). When the sub returns the new process is automatically
104terminated.
65 105
66=cut 106=cut
67 107
68$error_msg = 108sub async(&) {
69$error_coro = undef; 109 (new Coro $_[0])->ready;
70
71$error = _newprocess {
72 print STDERR "FATAL: $error_msg\nprogram aborted\n";
73 exit 250;
74};
75
76=item $coro = new $coderef [, @args]
77
78Create a new coroutine and return it. The first C<resume> call to this
79coroutine will start execution at the given coderef. If it returns it
80should return a coroutine to switch to. If, after returning, the coroutine
81is C<resume>d again it starts execution again at the givne coderef.
82
83=cut
84
85sub new {
86 my $class = $_[0];
87 my $proc = $_[1];
88 bless _newprocess {
89 do {
90 eval { &$proc->resume };
91 if ($@) {
92 ($error_msg, $error_coro) = ($@, $current);
93 $error->resume;
94 }
95 } while ();
96 }, $class;
97} 110}
98 111
99=item $coro->resume 112=item schedule
100 113
101Resume execution at the given coroutine. 114Calls the scheduler. Please note that the current process will not be put
115into the ready queue, so calling this function usually means you will
116never be called again.
102 117
103=cut 118=cut
104 119
105my $prev; 120my $prev;
106 121
107sub resume { 122sub schedule {
108 $prev = $current; $current = $_[0]; 123 ($prev, $current) = ($current, shift @ready);
109 _transfer($prev, $current); 124 Coro::State::transfer($prev, $current);
110} 125}
111 126
1121; 127=item yield
128
129Yield to other processes. This function puts the current process into the
130ready queue and calls C<schedule>.
131
132=cut
133
134sub yield {
135 $current->ready;
136 &schedule;
137}
138
139=item terminate
140
141Terminates the current process.
142
143=cut
144
145sub terminate {
146 &schedule;
147}
113 148
114=back 149=back
115 150
116=head1 BUGS 151# dynamic methods
117 152
118This module has not yet been extensively tested. 153=head2 PROCESS METHODS
119 154
120=head1 SEE ALSO 155These are the methods you can call on process objects.
121 156
122L<Coro::Process>, L<Coro::Signal>. 157=over 4
158
159=item new Coro \&sub;
160
161Create a new process and return it. When the sub returns the process
162automatically terminates. To start the process you must first put it into
163the ready queue by calling the ready method.
164
165=cut
166
167sub new {
168 my $class = shift;
169 my $proc = $_[0];
170 bless {
171 _coro_state => new Coro::State ($proc ? sub { &$proc; &terminate } : $proc),
172 }, $class;
173}
174
175=item $process->ready
176
177Put the current process into the ready queue.
178
179=cut
180
181sub ready {
182 push @ready, $_[0];
183}
184
185=back
186
187=cut
188
1891;
123 190
124=head1 AUTHOR 191=head1 AUTHOR
125 192
126 Marc Lehmann <pcg@goof.com> 193 Marc Lehmann <pcg@goof.com>
127 http://www.goof.com/pcg/marc/ 194 http://www.goof.com/pcg/marc/

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines