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

Comparing Coro/Coro.pm (file contents):
Revision 1.1 by root, Tue Jul 3 02:53:34 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 an 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 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
9=head1 DESCRIPTION 21=head1 DESCRIPTION
10
11=over 4
12 22
13=cut 23=cut
14 24
15package Coro; 25package Coro;
16 26
17BEGIN { 27use Coro::State;
18 $VERSION = 0.01;
19 28
20 require XSLoader; 29use base Exporter;
21 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 }
22} 62}
63
64my $idle = new Coro sub {
65 &yield while 1;
66};
23 67
24=item $main 68=item $main
25 69
26This coroutine represents the main program. 70This coroutine represents the main program.
71
72=cut
73
74$main = new Coro;
27 75
28=item $current 76=item $current
29 77
30The 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).
31 79
32=cut 80=cut
33 81
34$main = $current = _newprocess { 82# maybe some other module used Coro::Specific before...
35 # never being called 83if ($current) {
36}; 84 $main->{specific} = $current->{specific};
85}
37 86
38=item $error, $error_msg, $error_coro 87$current = $main;
39 88
40This coroutine will be called on fatal errors. C<$error_msg> and 89# we really need priorities...
41C<$error_coro> return the error message and the error-causing coroutine, 90my @ready = (); # the ready queue. hehe, rather broken ;)
42respectively. 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.
43 105
44=cut 106=cut
45 107
46$error_msg = 108sub async(&) {
47$error_coro = undef; 109 (new Coro $_[0])->ready;
48
49$error = _newprocess {
50 print STDERR "FATAL: $error_msg, program aborted\n";
51 exit 250;
52};
53
54=item $coro = new $coderef [, @args]
55
56Create a new coroutine and return it. The first C<resume> call to this
57coroutine will start execution at the given coderef. If it returns it
58should return a coroutine to switch to. If, after returning, the coroutine
59is C<resume>d again it starts execution again at the givne coderef.
60
61=cut
62
63sub new {
64 my $class = $_[0];
65 my $proc = $_[1];
66 bless _newprocess {
67 do {
68 eval { &$proc->resume };
69 if ($@) {
70 ($error_msg, $error_coro) = ($@, $current);
71 $error->resume;
72 }
73 } while ();
74 }, $class;
75} 110}
76 111
77=item $coro->resume 112=item schedule
78 113
79Resume 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.
80 117
81=cut 118=cut
82 119
83my $prev; 120my $prev;
84 121
85sub resume { 122sub schedule {
86 $prev = $current; $current = $_[0]; 123 ($prev, $current) = ($current, shift @ready);
87 _transfer($prev, $current); 124 Coro::State::transfer($prev, $current);
88} 125}
89 126
901; 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}
91 148
92=back 149=back
93 150
94=head1 BUGS 151# dynamic methods
95 152
96This module has not yet been extensively tested. 153=head2 PROCESS METHODS
154
155These are the methods you can call on process objects.
156
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;
97 190
98=head1 AUTHOR 191=head1 AUTHOR
99 192
100 Marc Lehmann <pcg@goof.com> 193 Marc Lehmann <pcg@goof.com>
101 http://www.goof.com/pcg/marc/ 194 http://www.goof.com/pcg/marc/

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines