ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/cvsroot/docs/pws2002/coro.sdf
Revision: 1.5
Committed: Sun Feb 10 16:39:35 2002 UTC (24 years, 7 months ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.4: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 !init OPT_STYLE="paper"
2
3 !define DOC_NAME "Coroutinen und Continuations mit dem Coro-Modul"
4 !define DOC_AUTHOR "Marc Lehmann <pcg@goof.com>"
5 !build_title
6
7 H1: Was sind Coroutinen und Continuations?
8
9 Prozedurale Programme laufen normalerweise sequenziell ab und springen
10 manchml in Unterprogramme/Funktionen. Es ist nicht möglich, aus einem
11 Unterprogramm heraus kurzzeitig in den Aufrufer zurückzuspringen und später
12 an derselben Stelle weiterzuarbeiten.
13
14 Dies liegt daran, dass Perl, wie viele andere Sprachen, Funktionsaufrufe
15 mit einem Stack implementieren, den man in der gleichen Reihenfolge
16 abbauen muss, wie man ihn aufbaut.
17
18 Continuations abstrahieren diesen Stack, d.h. es gibt nicht nur eine
19 Aufruffolge, sondern viele. Zwischen diesen kann an beliebigen Stellen
20 gewechselt werden. Exception-handling, nichtlokale Sprünge, Multitasking
21 und Threads können mit Continuations implementiert werden.
22
23 Coroutinen sind eine Anwendung von Continuations, bei denen meherere
24 unabhängige Ablaufinstanzen nacheinander kurzzeitig ausgeführt werden, so
25 dass der Eindruck gleichzeitigen Ablaufs entstehen kann (kooperatives
26 Multitasking). Der Unterschied zu Continuations ist im Wesentlichen der,
27 dass der Wechsel normalerweise nicht explizit erfolgt und keine Parameter
28 zwischen den Instanzen ausgetauscht werden, da die Reihenfolge nicht
29 festgelegt ist.
30
31 H1: Die Entstehung des Coro-Moduls
32
33 Continuations für Perl5 stehen seit ca. 1996 auf meinem "TODO"-Zettel,
34 aber da ich immer dachte, man könne das nicht schnell genug (Kopieren des
35 gesamten Stacks oder schlimmer?) implementieren bzw. die Implementation
36 wäre viel zu komplex um jemals stabil zu laufen.
37
38 H1: Das Problem
39
40 Um Coroutinen zu implementieren, reicht es, zwei Primitiven zu schreiben
41 (die Namen stammen aus Modula-2, die Perl-Syntax sieht etwas anders aus):
42
43 NEWPROCESS(process,coderef)
44 TRANSFER(oldprocess,newprocess)
45
46 C<NEWPROCESS> erzeugt einen neuen "Prozess", wobei ein "Prozess" im
47 Wesentlichen einen Aufrufstack (zum Schachteln von Funktionsaufrufen)
48 und einen Startpunkt (C<coderef>) besitzt. Diese Daten werden in einer
49 Struktur (C<process>) abgelegt.
50
51 Um einen solchen Prozess zu starten muss man die Kontrolle an ihn abgeben,
52 indem man C<TRANSFER> mit einer leeren C<process>-Struktur als erstes
53 Argument und einer gültigen (z.B. von C<NEWPROCESS>) C<process>-Struktur
54 als zweites Argument aufruft.
55
56 C<TRANSFER> sichert nun die Daten des {{aktuellen}} Prozesses in
57 C<oldprocess> und "springt" in den neuen.
58
59 Damit lassen sich Continuations und kooperatives und präemptives
60 Multitasking implementieren, wenn man es zu nutzen weiß.
61
62 H1: Teil 1: Implementation
63
64 H2: Erste Erfolge und erste Probleme
65
66 Im Juli 2001 war es dann so weit: In einem Anflug von Leichtsinn dachte
67 ich mir, "ein paar Pointer-Austauscher könnten doch zum Ziel führen".
68
69 (Es folgen einige haarsträubende Implementationsdetails, wer will, kann
70 die überspringen und direkt zum interessanten Teil übergehen ;)
71
72 Und tatsächlich, wenige Stunden (und Zeilen) später hatte ich ein Modul,
73 das die beiden obigen Primitiven implementiert. Es funktionierte sogar:
74
75 !block C
76 save_state(pTHX_ Coro__State c, int flags)
77 {
78 c->curstackinfo = PL_curstackinfo;
79 c->curstack = PL_curstack;
80 c->mainstack = PL_mainstack;
81 c->stack_sp = PL_stack_sp;
82 c->op = PL_op;
83 ...
84 c->curcop = PL_curcop;
85 c->top_env = PL_top_env;
86 }
87
88 load_state(pTHX_ Coro__State c)
89 {
90 PL_curstackinfo = c->curstackinfo;
91 PL_curstack = c->curstack;
92 PL_mainstack = c->mainstack;
93 PL_stack_sp = c->stack_sp;
94 PL_op = c->op;
95 ...
96 PL_curcop = c->curcop;
97 PL_top_env = c->top_env;
98 }
99 !endblock
100
101 Bis einmal zwei Coroutinen dieselbe Funktion aufriefen. Viele
102 Stunden später kam dann das "Aha! So macht Perl das also. Na so ein
103 Mist...". Leider reicht es nicht, einfach die vielen Stacks auszutauschen,
104 die Perl benutzt. Denn Perl modifiziert bei jedem Aufruf einer Funktion
105 diese (genauer: den CV) selbst:
106
107 !block C
108 /* aus pp_entersub */
109 CvDEPTH(cv)++;
110 if (CvDEPTH(cv) < 2)
111 (void)SvREFCNT_inc(cv);
112 else { /* save temporaries on recursion? */
113 PERL_STACK_OVERFLOW_CHECK();
114 if (CvDEPTH(cv) > AvFILLp(padlist)) {
115 /* hier wird eine neue padlist erzeugt - 40 Zeilen Magie */
116 ...
117 }
118 }
119 ...
120 PL_curpad = AvARRAY((AV*)svp[CvDEPTH(cv)]);
121 !endblock
122
123 Da wurde mir auch klar, weshalb Threads so langsam sind, denn die müssen
124 unglaubliche Anstrengungen unternehmen, damit sich einzelne Threads nicht
125 in die Quere kommen. C<pp_entersub> ist alles andere als trivial, ein
126 Wunder, dass Perl so schnell ist.
127
128 Im Wesentlichen geht es darum, für jede Rekursionsstufe eine C<padlist>
129 (in der werden lokale Variablen u.ä. gespeichert) zu erzeugen, die erste
130 schon beim Kompilieren.
131
132 Solange eine Coroutine nicht in eine Funktion springt, die schon rekursiv
133 aufgerufen wurde, ist das kein Problem, da C<CvDEPTH> dann 1 ist und die
134 erste padlist leer. Andernfalls wird die Rekursionsstufe erhöht, auch
135 kein Problem. Wenn die erste Coroutine dann aber wieder aus der Funktion
136 zurückkehren will, gibt es ein Problem, denn das käme der Aufgabe
137 gleich, die n-te Rekursionsstufe zu beenden während die n+1-te noch immer
138 aktiv ist.
139
140 Die Lösung ist eklig, aber noch nicht unzumutbar langsam: Da ein
141 Perl-Modul nicht die Freiheit hat, C<pp_entersub> zu verändern (die
142 Perl-Thread-Implementation kann sich das leisten), muss man den Aufrufstack
143 hinaufgewandern und manuell eine Art "Rücksprung" organisieren.
144
145 !block C
146 save_state(pTHX_ Coro__State c, int flags)
147 ...
148 /* this loop was inspired by pp_caller */
149 for (;;)
150 {
151 while (cxix >= 0)
152 {
153 PERL_CONTEXT *cx = &ccstk[cxix--];
154
155 if (CxTYPE(cx) == CXt_SUB)
156 {
157 CV *cv = cx->blk_sub.cv;
158 if (CvDEPTH(cv))
159 {
160 EXTEND (SP, CvDEPTH(cv)*2);
161
162 while (--CvDEPTH(cv))
163 {
164 /* this tells the restore code to increment CvDEPTH */
165 PUSHs (Nullsv);
166 PUSHs ((SV *)cv);
167 }
168
169 PUSHs ((SV *)CvPADLIST(cv));
170 PUSHs ((SV *)cv);
171
172 get_padlist (cv); /* this is a monster */
173 }
174 }
175 ...
176 if (top_si->si_type == PERLSI_MAIN)
177 break;
178
179 top_si = top_si->si_prev;
180 ccstk = top_si->si_cxstack;
181 cxix = top_si->si_cxix;
182 }
183 ...
184
185 load_state(pTHX_ Coro__State c)
186 ...
187 /* now do the ugly restore mess */
188 while ((cv = (CV *)POPs))
189 {
190 AV *padlist = (AV *)POPs;
191
192 if (padlist)
193 {
194 put_padlist (cv); /* mark this padlist as available */
195 CvPADLIST(cv) = padlist;
196 }
197
198 ++CvDEPTH(cv);
199 }
200 !endblock
201
202 Der lustigste Teil verbirgt sich hinter:
203
204 get_padlist (cv); /* this is a monster */
205
206 Denn, während man die neu erzeugten padlists einfach sichern kann, muss
207 die erste neu erzeugt werden, ein höchst umständlicher Vorgang, der
208 deshalb auch (mit einem Hash) gecached wird.
209
210 Damit war bewiesen, dass Coroutinen tatsächlich so viele Probleme machen,
211 wie ich befürchtet hatte.
212
213 H2: Das vorläufige Ende
214
215 Aber es kam noch schlimmer. Beispiel: Perl ruft eine XS-Funktion auf, und
216 diese wieder einen Perl-Callback. Der führt einen Coroutinenwechsel
217 durch und die neue Coroutinen macht ein C<return> - wohin? In die
218 XS-Funktion, die natürlich Ergebnisse auf dem Stack erwartet, die ebenso
219 natürlich nicht da sind. dies ist auch der Grund dafür, dass der "fake
220 threads"-Ansatz von Perl (vorerst) zum Scheitern verurteilt ist.
221
222 An diesem Punkt habe ich erstmal aufgegeben. Die Aussicht, auch eine
223 portable Coroutinenimplementation für C zu finden, waren Null, sie werden
224 ja noch nicht einem in irgendwelchen Standards erwähnt (dachte ich).
225
226 Naja, selbst schreiben war angesagt - tatsächlich kann man, lediglich
227 mit UNIX95-Funktionen, portabel Coroutinen erzeugen. Leider ist mir
228 kein System bekannt, dass sich wirklich ganz an den Standard hielte
229 (von Grausamkeiten wie IRIX mal ganz abgesehen, siehe sigaltstack,
230 das vollkommen dokumentiert das vollkommen sinnlose macht), aber die
231 Unterschiede sind gering. Sogar unter der eingeschränkten Win32-API kann
232 man durch direktes herumpoken in C<jmp_buf> relativ schmerzlos eine
233 Implementation bekommen.
234
235 Im Coro-Modul gibt es im Verzeichnis C<Coro/libcoro> seitdem eine
236 relativ portable, sehr kleine (366 Zeilen inkl. Dokumentation ;)
237 Coroutinenimplementation für C.
238
239 Das Coro-Modul erzeugt entweder für jede Coroutine in Perl eine Coroutine
240 in C, oder optional nur "on demand", d.h. wenn sich der C-Stackpointer
241 verändert hat, eine gefährliche, aber in der Praxis gut funktionierende
242 Heuristik.
243
244 H1: Teil 2: Implementation von Coroutinen und Continuations in Perl
245
246 H2: Die Perl-API
247
248 C<NEWPROCESS> und C<TRANSFER> werden vom C<Coro::State>-Modul implementiert.
249 C<NEWPROCESS> sieht in Perl so aus:
250
251 !block perl
252 # eine "leere" Coroutine, bereit, gefüllt zu werden
253 $main = new Coro::State;
254
255 # eine neue Coroutine, zu der man wechseln kann
256 $new = new Coro::State sub {
257 # ... coroutine
258 }, @args;
259 !endblock
260
261 Und C<TRANSFER> sieht so aus:
262
263 !block perl
264 # etwas asymetrisch:
265 $main->transfer($new);
266 # oder symmetrischer
267 Coro::State::transfer($main,$new);
268 !endblock
269
270 H2: Continuations
271
272 Nicht, dass ich das Modul viel benutzen würde, aber ich wollte zeigen,
273 dass es geht: Das C<Coro::Cont>-Modul exportiert zwei Funktionen, C<csub>,
274 mit dem sich neue Continuations erzeugen lassen und C<yield>, das so
275 ähnlich wie C<return> wirkt. Außerdem werden Attribute unterstützt, so,
276 dass man Continuations so schreiben kann:
277
278 !block perl
279 use Coro::Cont;
280
281 sub generator : Cont {
282 my $state = time;
283 while() {
284 $state = $state * 31231 % 65531;
285 yield $state % $_[0];
286 }
287 }
288 !endblock
289
290 Der erste Aufruf initialisiert den Zustand (Zuweisung an C<$state>), bei
291 jedem weiteren wird eine (schlechte) Zufallszahl im Bereich C<0..$_[0]>
292 zurückgeliefert, wobei @_ sich jedesmal ändert. Das Attributsystem von
293 Perl5 ist ziemlich schwer zu benutzen (mehrere Module können es sich nicht
294 einfach teilen, Attribute sind automatisch global etc..), weshalb ich
295 darauf nicht näher eingehe ;)
296
297 Die Implementation ist einigermaßen trickreich, da die Standardimplementation
298 von C<transfer> das Array C<@_> mitspeichert, es also nicht so einfach übergeben
299 werden kann. Deshalb kann man C<transfer> ein drittes Argument, eine Bitmaske
300 mit Flags, übergeben, die angibt, ob C<@_> oder C<$_> u.ä. Teil des
301 "Prozesszustandes" werden oder nicht.
302
303 C<csub> erzeugt zwei C<Coro::State>-Objekte, eines für den Aufrufer und eines
304 für die Continuation:
305
306 !block perl
307 sub csub(&) {
308 my $code = $_[0];
309 my $prev = new Coro::State;
310
311 my $coro = new Coro::State sub {
312 # we do this superfluous switch just to
313 # avoid the parameter passing problem
314 # on the first call
315 &yield;
316 &$code while 1;
317 };
318 !endblock
319
320 D.h. die Code-Referenz wird in einer Schleife aufgerufen. Da die Parameter
321 beim ersten Aufruf der Coroutine etwas anders übergeben werden als
322 später bei C<yield>, wird als erstes ein C<yield> ausgeführt, damit alle
323 Aufrufe identisch sind.
324
325 Als nächstes wird die neu erzeugte Coroutine {{einmal}} aufgerufen (damit
326 sie "yield"-en kann):
327
328 !block perl
329 push @$$return, [$coro, $prev];
330 &Coro::State::transfer($prev, $coro, 0);
331 !endblock
332
333 In der gobalen Variablen C<$return> befindet sich eine Referenz
334 auf ein Array, in dem die "Rücksprung"-Coroutinen gespeichert sind,
335 d.h. C<Coro::Cont> macht fast den gleichen "Fehler" wie C<pp_entersub>,
336 aber C<$$return> ist nicht wirklich global (wie ich gleich zeige ;)
337
338 Als letztes wird eine Code-Referenz zurückgegeben, die das Aufrufen der
339 Coroutine für uns erledigt:
340
341 !block perl
342 return sub {
343 push @$$return, [$coro, $prev];
344 &Coro::State::transfer($prev, $coro, 0);
345 wantarray ? @_ : $_[0];
346 };
347 !endblock
348
349 Auch hier wird die "Rücksprungaddresse" für C<yield> in C<@$$return>
350 gespeichert und dann die Coroutine aufgerufen, die beim nächsten C<yield>
351 zurückkehrt. Die Argumente, die die Coroutine an C<yield> übergeben hat,
352 stehen immer noch in C<@_>.
353
354 Die Funktion C<yield> ist in XS implementiert, die
355 Prototyp-Implementation in Perl sah jedoch so aus:
356
357 !block perl
358 sub yield(@) {
359 &Coro::State::transfer(@{pop @$$return}, 0);
360 wantarray ? @_ : $_[0];
361 }
362 !endblock
363
364 Auch nichts Überraschendes, es wird zum Aufrufer zurückgegeben. Beim
365 nächsten Aufruf wird das neue C<@_> zurückgegeben, d.h. der Aufruf
366 müsste lauten: C<@_ = yield ...>, und das ist der Grund, weshalb es
367 in XS implementiert wurde, denn in XS kann man das C<@_> des Aufrufers
368 verändern. Wäre nicht dieser Umstand. so würde auch C<yield> in reinem
369 Perl implementiert sein.
370
371 Das verbleibende Problem ist die globale Variable C<$return>. Tatsächlich
372 ist sie ein C<Coro::Specific>-Objekt und ist "Coroutinen"spezifisch, d.h.
373 kann in jeder Coroutine (hier meine ich ein C<Coro>-Objekt und nicht das
374 C<Coro::State>-Objekt) einen anderen Wert besitzen.
375
376 H2: C<Coro::Specific>
377
378 Mit C<Coro::State> kann man eigene Prozess-Abstraktionen basteln. Damit
379 C<Coro::Specific> funktioniert, muss man lediglich einen
380 coroutinen-/prozessspezifischen Hash in C<$Coro::current> speichern, und
381 genau das macht das C<Coro>-Modul.
382
383 C<Coro::Specific->new> gibt eine Referenz auf einen ge'tie'ten Scalar zurück, der
384 wiederum bei C<FETCH> und C<STORE> einen Skalar im Array
385 C<@{$Coro::current->{specific}}> verändert. Solange das C<Coro>-Modul nicht
386 geladen ist, ist das immer derselbe, danach ist er coroutinenspezifisch.
387
388 !block perl
389 my $idx;
390
391 sub new {
392 my $var;
393 tie $var, Coro::Specific::;
394 \$var;
395 }
396
397 sub TIESCALAR {
398 my $idx = $idx++;
399 bless \$idx, $_[0];
400 }
401
402 sub FETCH {
403 $Coro::current->{specific}[${$_[0]}];
404 }
405
406 sub STORE {
407 $Coro::current->{specific}[${$_[0]}] = $_[1];
408 }
409 !endblock
410
411 Auf diese Weise kann man in anderen Modulen ohne schlechtes Gewissen
412 C<Coro::Specific> verwenden, da weder C<Coro::State> noch C<Coro> geladen
413 sein müssen.
414
415 H2: Prozesse selbst gemacht
416
417 Der nächste Schritt, nach Continuations, Variablen und (primitiven)
418 Coroutinen sind richtige Prozesse. Diese werden im C<Coro>-Modul
419 implementiert, das Prozesserzeugung, Kommunikation, Prioritäten etc.
420 anbietet.
421
422 Das sieht dann so aus:
423
424 !block perl
425 use Coro:
426
427 async {
428 # ein neuer "Prozess"
429 };
430
431 my $coro = async {
432 terminate;
433 };
434
435 $coro->prio(PRIO_MAX);
436 $coro->join;
437
438 cede; # gib die CPU frei für andere Prozesse
439
440 # usw.. hat ja "jeder" schon mal gesehen ;-]
441 !endblock
442
443 Die Implementation ist in einigen Teilen in XS, der Geschwindigkeit
444 wegen. Wenn das Modul geladen wird, erzeugt es zuerst einen
445 "Hauptprozess", der für das Hauptprogramm steht (das Hauptprogramm
446 korrekt auf eine Coroutine abzubilden, ist sowieso ein sehr schwieriges
447 Unterfangen - welche Coroutine DESTROY't die anderen Coroutinen am
448 Programmende, wenn das Hauptprogramm nicht mehr existiert?) und sorgt für
449 die Übernahme des bisherigen C<@{$Coro::current->{specific}}>.
450
451 !block perl
452 our $main = new Coro;
453
454 # maybe some other module used Coro::Specific before...
455 if ($current) {
456 $main->{specific} = $current->{specific};
457 }
458
459 our $current = $main;
460 !endblock
461
462 Dann folgt die Erzeugung eines Idle-Prozesses, der Rechenzeit verbrät,
463 wenn kein Prozess mehr läuft:
464
465 !block perl
466 our $idle = new Coro sub {
467 print STDERR "FATAL: deadlock detected\n";
468 exit(51);
469 };
470 !endblock
471
472 Jaja, reingefallen. Wenn kein Prozess mehr läuft, haben wir einen
473 Deadlock, zumindest, solange man Signale außer acht lässt. Das ändert
474 sich, wenn man Events benutzt (z.B. mit C<Coro::Event>), weshalb der
475 Idle-Prozess auswechselbar ist.
476
477 Neue Prozesse werden mit C<async> oder C<Coro->new> erzeugt:
478
479 !block perl
480 sub _newcoro {
481 terminate &{+shift};
482 }
483
484 sub new {
485 my $class = shift;
486 bless {
487 _coro_state => (new Coro::State $_[0] && \&_newcoro, @_),
488 }, $class;
489 }
490
491 sub async(&@) {
492 my $pid = new Coro @_;
493 $manager->ready; # this ensures that the stack is cloned from the manager
494 $pid->ready;
495 $pid;
496 }
497 !endblock
498
499 Ein Prozess ist also wenig mehr als ein nackter Hash, in dessen
500 C<_coro_state>-Slot ein C<Coro::State>-Objekt gespeichert ist. Ähnlich
501 wie PDL sieht C<transfer> in diesem Slot nach einem C<Coro::State>-Objekt.
502
503 Dass C<async> den C<$manager> in Bereitschaft versetzt und nicht nur den
504 neuen Prozess, ist nicht auf Anhieb verständlich: Der Grund dafür ist,
505 dass so die meisten Prozesse mit einem definierten Stackpointer erzeugt
506 werden, so dass derselbe C-Stack für alle Prozesse verwendet werden kann,
507 zumindest anfänglich.
508
509 Am Ende eines Prozesslebens steht ein C<terminate>, oder ein C<cancel>:
510
511 !block perl
512 sub cancel {
513 push @destroy, $_[0];
514 $manager->ready;
515 &schedule if $current == $_[0];
516 }
517 !endblock
518
519 C<schedule> springt direkt in den Scheduler, der den nächsten
520 lauffähigen Prozess aus der Warteschlange nimmt und zum aktuellen
521 macht. Er ist (jaja, "the need for speed") in XS implementiert, sieht aber
522 etwa (keine Prioritäten) so aus:
523
524 !block perl
525 sub schedule {
526 my $previous = $current;
527 $current = shift @runqueue;
528 Coro::State::transfer($current, $previous);
529 }
530 !endblock
531
532 Der aktuelle Prozess wird nicht automatisch wieder aufgerufen, dazu muss
533 man ihn wieder mit der C<ready>-Methode in die Warteschlange setzen. Um
534 nur kurz andere Prozesse laufen zu lassen, konnte man früher C<yield>
535 benutzen, aber das ging schon für Continuations drauf, und Damian Conway
536 fand das wichtiger. Also musste ich einen neuen Namen finden:
537
538 !block perl
539 sub cede {
540 $current->ready;
541 schedule;
542 }
543 !endblock
544
545 Einen Prozess direkt zu zerstören, ist keine gute Idee. Zum einen könnte
546 er mehrfach in der C<ready>-Queue stehen, zum anderen sollte er sich
547 selbst C<DESTROY>en können, aber da er sich dabei selbst den C-Stack
548 wegzieht, muss dies von einem anderen Prozess aus stattfinden. Der
549 Manager-Prozess stellt genau dies sicher (und verständigt auch gleich
550 eventuell wartende Prozesse):
551
552 !block perl
553 my @destroy;
554 my $manager;
555 $manager = new Coro sub {
556 while() {
557 # by overwriting the state object with the manager we destroy it
558 # while still being able to schedule this coroutine (in case it has
559 # been readied multiple times. this is harmless since the manager
560 # can be called as many times as neccessary and will always
561 # remove itself from the runqueue
562 while (@destroy) {
563 my $coro = pop @destroy;
564 $coro->{status} ||= [];
565 $_->ready for @{delete $coro->{join} || []};
566 $coro->{_coro_state} = $manager->{_coro_state};
567 }
568 &schedule;
569 }
570 };
571 !endblock
572
573 H2: Signale, Semaphoren, Channels und Locks
574
575 Hat man Prozesse, die man erzeugen, anhalten, schedulen und wieder beenden
576 kann, so muss man sie koordinieren. Zum Beispiel mit C<Coro::Signal>'s:
577
578 !block perl
579 sub send {
580 if (@{$_[0][1]}) {
581 (shift @{$_[0][1]})->ready;
582 } else {
583 $_[0][0] = 1;
584 }
585 }
586
587 sub wait {
588 if ($_[0][0]) {
589 $_[0][0] = 0;
590 } else {
591 push @{$_[0][1]}, $Coro::current;
592 Coro::schedule;
593 }
594 }
595 !endblock
596
597 Getreu dem Motto "Pseudo-Hashes müssen sterben!", etwas ungewöhnlich
598 ausgelegt, verwendet C<Coro::Signal> ein Array und keinen Hash. Das erste
599 Element ist nur ein Flag, das angibt, ob das Signal gesendet wurde (falls
600 niemand darauf wartet). Das zweite Element ist ein Array wartender
601 Prozessen.
602
603 C<send> weckt den ersten wartenden Prozess auf oder - falls es keinen gibt
604 - setzt das Flag. Wenn man auf ein Signal wartet, wird zuerst geprüft, ob
605 es schon aufgetreten ist, sonst reiht sich der aktuelle Prozess in die
606 Warteschlange und legt sich schlafen.
607
608 H1: Teil 3: Die Außenwelt
609
610 H2: C<Event> für Coro: C<Coro::Event>
611
612 Multitasking innerhalb von Perl ist ja ganz nett, aber das erste
613
614 !block perl
615 my $line = <STDIN>;
616 !endblock
617
618 bringt das ganze System zum Erliegen. Wenn man viele asynchrone
619 Ein-/Ausgabekanäle hat, die in unterschiedlicher Reihenfolge bedient
620 werden sollen, braucht man eine Ereignissteuerung. Das Standardmodul für
621 diesen Fall ist das (leider nicht mehr gewartete und auf vielen Systemen
622 nicht mehr lauffähige) Event-Modul, das jedoch für jedes Ereigenis einen
623 Callback erfordert.
624
625 Das C<Coro::Event>-Modul benutzt Event (oder ein anderes Modul, es gibt
626 nur keines ;), statt eines Callbacks wird der Prozess solange blockiert,
627 bis das Ereignis eintritt:
628
629 !block perl
630 my $event = Coro::Event->timer(after => 1, interval => 1, hard => 1);
631
632 while() {
633 $event->next;
634 print "one event every second\n";
635 }
636 !endblock
637
638 C<next> gibt dabei ein Event-Objekt zurück, ähnlich dem Event-Objekt,
639 das Callbacks des Event-Moduls erhalten. Eine frühe Implementation von
640 C<next> gab tatsächlich genau dieses Objekt zurück:
641
642 !block perl
643 # dies ist der Callback, der jedem Event-Watcher zugewiesen wird:
644 sub std_cb {
645 # das private-Feld enthält ein Array,
646 # das im ersten Element den wartenden Prozess
647 # und im zweiten das Event-Objekt speichert
648 my $w = $_[0]->w;
649 my $q = $w->private;
650 $q->[1] = $_[0];
651 if ($q->[0]) { # somebody waiting?
652 $q->[0]->ready;
653 &Coro::schedule;
654 } else {
655 $w->stop;
656 }
657 }
658
659 sub next {
660 my $w = $_[0];
661 my $q = $w->private;
662 if ($q->[1]) { # event waiting?
663 $w->again unless $w->is_cancelled;
664 } elsif ($q->[0]) {
665 croak "only one coroutine can wait for an event";
666 } else {
667 local $q->[0] = $Coro::current;
668 &Coro::schedule;
669 }
670 pop @$q;
671 }
672 !endblock
673
674 Dies war nicht nur relativ ineffizient (zwei Prozesswechsel pro Ereignis),
675 das Event-Modul mochte das auch gar nicht, da es die Event-Objekte intern
676 wiederverwendet und Zugriffe darauf nach Rückkehr aus dem Callback recht
677 zufällig bearbeitete.
678
679 Die Lösung für beide Probleme ist wieder einmal XS. Zum Glück
680 exportiert C<Event> eine fast dokumentierte Schnittstelle dafür (wie auch
681 Coro eine XS-Schnittstelle bereitstellt). C<Coro::Event> speichert die
682 Event-Daten in einem Array, wobei nur die Werte für C<hits>, C<prio> und
683 C<got> gesichert werden, da kein Event mehr als diese benötigt.
684
685 Durch Events kann es passieren, dass alle Prozesse auf ein Ereignis warten, also muss
686 der Idle-Prozess überschrieben werden:
687
688 !block perl
689 $Coro::idle = new Coro sub {
690 while () {
691 Event::one_event; # inefficient
692 Coro::schedule;
693 }
694 };
695 !endblock
696
697 C<one_event> ist nicht sehr effizient, weshalb man das Hauptprogramm am
698 besten durch einen Aufruf von C<Event::loop> zur Hauptschleife degradiert
699 und der Idle-Prozess nie laufen muss.
700
701 Um nicht bei jedem Ereignis zwei Prozesswechsel durchführen zu müssen,
702 legt der Callback die wartenden Prozesse nur in die Ready-Queue. Dabei
703 ergibt sich das Problem, dass Event keine dokumentierte Möglichkeit
704 bietet, {{vor}} dem Aufruf von C<poll> oder C<select> (oder was auch
705 immer intern verwendet wird) einen Callback auszuführen, der die
706 bereitstehenden Prozesse ausführt.
707
708 Zwar kann man mit:
709
710 !block perl
711 Event->add_hooks(prepare => ..);
712 !endblock
713
714 Einen Callback für diesen Fall einbauen, nur wird er zu spät aufgerufen,
715 es gehen also Ereignisse verloren. Ausserdem quittiert Event einige
716 Aufrufe innerhalb dieses Callbacks mit Segmentation Faults.
717
718 Die Lösung liegt in einem speziellen Idle-Watcher mit der Priorität
719 C<PRIO_NORMAL>. Idle-Watcher mit dieser Priorität werden kurz vor dem
720 Aufruf von C<poll> aufgerufen, andere Prioritäten führen zu zu häufigen
721 oder gar keinen Aufrufen.
722
723 Wenn ein Ereignis auftritt, wird mit C<$watcher->now> dieser Watcher
724 "gestartet", der dann solange Prozesse scheduled bis keine mehr laufen:
725
726 !block perl
727 #define NEED_SCHEDULE if (!do_schedule) \
728 { \
729 do_schedule = 1; \
730 GEventAPI->now ((pe_watcher *)scheduler); \
731 }
732
733 scheduler_cb(pe_event *pe)
734 {
735 while (CORO_NREADY)
736 CORO_CEDE;
737
738 do_schedule = 0;
739 }
740
741 # overwrite the ready function
742 void
743 ready(self)
744 SV * self
745 PROTOTYPE: $
746 CODE:
747 NEED_SCHEDULE;
748 CORO_READY (self);
749 !endblock
750
751 Wenn das Hauptprogramm artig C<Event::loop> benutzt, läuft dieser
752 Callback immer im Kontext des Hauptprogramms, der Idle-Prozess wird nicht
753 benutzt.
754
755 H2: Non-Blocking but Blocking Filehandles
756
757 Damit man das Ganze sinnvoll (und natürlich) nutzen kann, braucht man
758 non-blocking-IO. Das Ziel ist es, Programme so schreiben zu können:
759
760 !block perl
761 # Ein finger-Prozess, der andere Prozesse nicht blockiert
762 sub finger {
763 my $user = shift;
764 my $host = shift;
765
766 my $fh = new Coro::Socket PeerHost => $host, PeerPort => "finger"
767 or die;
768
769 print $fh "$user\n";
770
771 print "$user\@$host: $_" while <$fh>;
772 print "$user\@$host: done\n";
773 }
774 !endblock
775
776 Dazu muss man Filehandles tie'en, ein komplizierter Prozess, da
777 Filehandles in Perl sehr merkwürdige Objekte, und vor allem keine Objekte
778 sind. Dies erledigt das C<Coro::Handle>-Modul, das im Wesentlichen eine
779 Funktion C<unblock> exportiert, die aus einem normalen Filehandle einen
780 nichtblockierenden macht:
781
782 !block perl
783 my $stdin = unblock \*STDIN;
784
785 while(<$stdin>) {
786 ...
787 }
788 !endblock
789
790 Anders als andere Module (C<Data::Location>) werden dabei keine
791 echten Filehandles erzeugt, da dies zu viele Probleme
792 mit sich bringt. Stattdessen wird ein anonymer GLOB an das
793 C<Coro::Handle::FH>-Package getied, um C<syswrite>, C<readline> etc.
794 abzufangen, zusätzlich wird der GLOB in das C<Coro::Handle>-Package
795 ge'bless'ed, um auch Methoden abzufangen:
796
797 !block perl
798 my $fh = shift or return;
799 my $self = do { local *Coro::Handle };
800
801 my ($package, $filename, $line) = caller;
802 $filename =~ s/^.*[\/\\]//;
803
804 tie $self, Coro::Handle::FH, fh => $fh, desc => "$filename:$line", @_;
805
806 my $_fh = select bless \$self, $class; $| = 1; select $_fh;
807 !endblock
808
809 In C<Coro::Handle> stehen dann "glue"-Methoden:
810
811 !block perl
812 sub readline { tied(${+shift})->READLINE(@_) }
813 sub read { Coro::Handle::FH::READ (tied ${$_[0]}, $_[1], $_[2], $_[3]) }
814 sub sysread { Coro::Handle::FH::READ (tied ${$_[0]}, $_[1], $_[2], $_[3]) }
815 sub syswrite { Coro::Handle::FH::WRITE (tied ${$_[0]}, $_[1], $_[2], $_[3]) }
816 sub print { Coro::Handle::FH::WRITE (tied ${+shift}, join "", @_) }
817 sub printf { Coro::Handle::FH::PRINTF(tied ${+shift}, @_) }
818 sub fileno { Coro::Handle::FH::FILENO(tied ${$_[0]}) }
819 sub close { Coro::Handle::FH::CLOSE (tied ${$_[0]}) }
820 !endblock
821
822 Und einige weitere, die nur mit C<Coro::Handle>s Sinn machen:
823
824 !block perl
825 sub readable { Coro::Handle::FH::readable(tied ${$_[0]}) }
826 sub writable { Coro::Handle::FH::writable(tied ${$_[0]}) }
827 !endblock
828
829 Die eigentliche Implementation ist dann in C<Coro::Handle::FH> zu finden,
830 z.B. für C<WRITE>:
831
832 !block perl
833 sub writable {
834 ($_[0][6] ||= Coro::Event->io(
835 fd => $_[0][0],
836 desc => "$_[0][1] W",
837 timeout => $_[0][2],
838 poll => W+E,
839 ))->next->{Coro::Event}[5] & W;
840 }
841
842 sub WRITE {
843 my $len = defined $_[2] ? $_[2] : length $_[1];
844 my $ofs = $_[3];
845 my $res = 0;
846
847 while() {
848 my $r = syswrite $_[0][0], $_[1], $len, $ofs;
849 if (defined $r) {
850 $len -= $r;
851 $ofs += $r;
852 $res += $r;
853 last unless $len;
854 } elsif ($! != Errno::EAGAIN) {
855 last;
856 }
857 last unless &writable;
858 }
859
860 return $res;
861 }
862 !endblock
863
864 Ja, die Hässlichkeit (C<READLINE> habe ich noch gar nicht gezeigt ;) ist
865 ein Grund mehr, das Ganze zu abstrahieren. Die eigentliche Arbeit wird von
866 der C<writable>-Methode erledigt, die beim ersten Aufruf einen Watcher
867 erzeugt und dann mit C<next> auf das nächste Ereignis wartet.
868
869 Am Rande muss ich noch bemerken, dass "Ereignis" nicht ganz korrekt
870 ist. Weder C<select> noch C<poll> warten auf "Ereignisse", noch tun
871 das die meisten anderen Event-Modelle, sie prüfen lediglich auf einen
872 gewünschten Zustand, ist dieser schon erreicht, wird ein "Ereignis"
873 ausgelöst, auch, wenn eigentlich nichts passiert ist.
874
875 Und aus der Abteilung Kurioses: Beim Wandeln eines Filehandle in einen
876 String wird offenbar die C<FETCH>-Methode aufgerufen.
877
878 H2: Von Handles zu Sockets
879
880 Da Dateien niemals "blockieren" und Perl kein AIO unterstützt, ist
881 C<Coro::Handle> eigentlich nur für Pipes und Sockets interessant. Damit
882 man auch ohne blockieren C<connect>en kann, gibt es mit C<Coro::Socket>
883 ein Modul, das sich so nah wie möglich an die C<IO::Socket::INET>-API
884 hält.
885
886 Der Konstruktor benutzt die folgende Methode für ein
887 non-blocking-connect:
888
889 !block perl
890 sub _prepare_socket {
891 my ($class, $arg) = @_;
892
893 socket my $fh, PF_INET, $arg->{Type}, _proto($arg->{Proto})
894 or return;
895
896 $fh = bless Coro::Handle->new_from_fh($fh, timeout => $arg{Timeout}), $class
897 or return;
898
899 ...
900 }
901
902 sub new {
903 ...
904 for (@sa) {
905 $fh = $class->_prepare_socket(\%arg)
906 or return;
907
908 $! = 0;
909
910 if ($fh->connect($_)) {
911 next unless writable $fh;
912 $! = unpack "i", $fh->getsockopt(SOL_SOCKET, SO_ERROR);
913 }
914
915 $! or last;
916
917 $!{ECONNREFUSED} or $!{ENETUNREACH} or $!{ETIMEDOUT} or $!{EHOSTUNREACH}
918 or return;
919 }
920 ...
921 }
922
923 sub connect { connect tied(${$_[0]})->[0], $_[1] or $! == Errno::EINPROGRESS }
924 !endblock
925
926 H1: Beispiele
927
928 H2: Ein alter Traum: LWP non-blocking
929
930 Wenn man Coro für sonst nichts braucht, auch in "normalen"
931 Programmen kann man Coro dazu benutzen, LWP (blockiert bei Anfragen) und
932 Ereignisgesteuerte Programme (z.B. Tk) zu kombinieren. Dazu muss man
933 "lediglich" den C<IO::Socket::INET>-Konstruktor überschreiben:
934
935 !block perl
936 use Coro::Socket;
937 use IO::Socket::INET;
938 sub IO::Socket::INET::new {
939 shift; new Coro::Socket @_;
940 };
941 !endblock
942
943 Danach kann man loslegen und gleichzeitig mehrere LWP-Requests starten:
944
945 !block perl
946 use Coro;
947 use Coro::Event;
948 use LWP::Simple;
949
950 $SIG{PIPE} = 'IGNORE';
951
952 async {
953 get "http://.../";
954
955 };
956
957 async {
958 get "http://.../";
959 };
960
961 loop;
962 !endblock
963
964 H2: Ein Prototyp für einen Server
965
966 Ein "herkömmlicher" Server sieht im Pseudocode so aus:
967
968 !block perl
969 my $socket = <neue listen-Socket erzeugen>
970
971 while () {
972 my $fh = $socket->accpt;
973 if (fork == 0) {
974 serve_request;
975 exit;
976 }
977 }
978 !endblock
979
980 Mit Coroutinen sieht das genauso aus, nur verwendet man statt C<fork> ein
981 C<async>:
982
983 !block perl
984 sub handle_connection {
985 my $fh = $_[0];
986 while (<$fh>) {
987 ...
988 }
989 }
990
991 my $port = new Coro::Socket
992 LocalPort => "imap2",
993 ReuseAddr => 1,
994 Listen => 1,
995 or die;
996
997 async {
998 slog 1, "accepting connections";
999 while () {
1000 my $fh = $port->accept;
1001 slog 3, "accepted $fh on $port";
1002 async \&handle_connection, $fh;
1003 undef $fh;
1004 }
1005 };
1006
1007 loop;
1008 !endblock
1009
1010 Die Vorteile sind - neben einem geringeren Verbrauch an Systemressourcen
1011 - dass die einzelnen für die Clients zuständigen Prozesse untereinander
1012 kommunizieren können. Mein Webserver z.B. kann Informationen über Clients
1013 austauschen, mein IMAP-Server kann problemlos die asynchronen "neue Mail
1014 empfangen"-Nachrichten an angeschlossene Clients weitergeben. Man kann
1015 solche Server auch problemlos zusammen in denselben Prozess laden (dazu
1016 muss man nur eines der beiden C<loop>-Statements entfernen).
1017
1018 A1: Verfügbarkeit
1019
1020 Das Coro-Modul gibts auf CPAN - getestet wurde es bisher nur unter
1021 Linux/x86, IRIX und Cygwin, wobei es unter Cygwin wohl noch einige
1022 Probleme gibt, die ich aber nicht debuggen kann. Perl-5.6 ist
1023 Minimalversion, was daran liegt, dass ich Perl-5.6-Features für XS
1024 verwende. Ein Port auf ältere Perls sollte nicht schwierig sein.
1025
1026 A2: Interessante URLs
1027
1028 Etwas Off-Topic, aber durchaus lesbar:
1029
1030 * Etwas Geschichte (Achtung, lustig!): http://brics.dk/~cw97/ProceedingS/01.ps.gz
1031 * Subcontinuations: http://indiana.edu/~dyb/papers/subK.ps
1032
1033
1034
1035
1036