ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/State.xs
Revision: 1.11
Committed: Sat Jul 21 18:21:45 2001 UTC (22 years, 10 months ago) by root
Branch: MAIN
Changes since 1.10: +12 -7 lines
Log Message:
*** empty log message ***

File Contents

# Content
1 #include "EXTERN.h"
2 #include "perl.h"
3 #include "XSUB.h"
4
5 #if 1
6 # define CHK(x) (void *)0
7 #else
8 # define CHK(x) if (!(x)) croak("FATAL, CHK: " #x)
9 #endif
10
11 #define MAY_FLUSH /* increases codesize */
12
13 #define SUB_INIT "Coro::State::initialize"
14
15 #define SAVE_DEFAV 0x00000001
16 #define SAVE_DEFSV 0x00000002
17 #define SAVE_ERRSV 0x00000004
18
19 #define SAVE_ALL -1
20
21 struct coro {
22 /* optionally saved, might be zero */
23 AV *defav;
24 SV *defsv;
25 SV *errsv;
26
27 /* saved global state not related to stacks */
28 U8 dowarn;
29
30 /* the stacks and related info (callchain etc..) */
31 PERL_SI *curstackinfo;
32 AV *curstack;
33 AV *mainstack;
34 SV **stack_sp;
35 OP *op;
36 SV **curpad;
37 SV **stack_base;
38 SV **stack_max;
39 SV **tmps_stack;
40 I32 tmps_floor;
41 I32 tmps_ix;
42 I32 tmps_max;
43 I32 *markstack;
44 I32 *markstack_ptr;
45 I32 *markstack_max;
46 I32 *scopestack;
47 I32 scopestack_ix;
48 I32 scopestack_max;
49 ANY *savestack;
50 I32 savestack_ix;
51 I32 savestack_max;
52 OP **retstack;
53 I32 retstack_ix;
54 I32 retstack_max;
55 COP *curcop;
56
57 /* data associated with this coroutine (initial args) */
58 AV *args;
59 };
60
61 typedef struct coro *Coro__State;
62 typedef struct coro *Coro__State_or_hashref;
63
64 static HV *padlist_cache;
65
66 /* mostly copied from op.c:cv_clone2 */
67 STATIC AV *
68 clone_padlist (AV *protopadlist)
69 {
70 AV *av;
71 I32 ix;
72 AV *protopad_name = (AV *) * av_fetch (protopadlist, 0, FALSE);
73 AV *protopad = (AV *) * av_fetch (protopadlist, 1, FALSE);
74 SV **pname = AvARRAY (protopad_name);
75 SV **ppad = AvARRAY (protopad);
76 I32 fname = AvFILLp (protopad_name);
77 I32 fpad = AvFILLp (protopad);
78 AV *newpadlist, *newpad_name, *newpad;
79 SV **npad;
80
81 newpad_name = newAV ();
82 for (ix = fname; ix >= 0; ix--)
83 av_store (newpad_name, ix, SvREFCNT_inc (pname[ix]));
84
85 newpad = newAV ();
86 av_fill (newpad, AvFILLp (protopad));
87 npad = AvARRAY (newpad);
88
89 newpadlist = newAV ();
90 AvREAL_off (newpadlist);
91 av_store (newpadlist, 0, (SV *) newpad_name);
92 av_store (newpadlist, 1, (SV *) newpad);
93
94 av = newAV (); /* will be @_ */
95 av_extend (av, 0);
96 av_store (newpad, 0, (SV *) av);
97 AvFLAGS (av) = AVf_REIFY;
98
99 for (ix = fpad; ix > 0; ix--)
100 {
101 SV *namesv = (ix <= fname) ? pname[ix] : Nullsv;
102 if (namesv && namesv != &PL_sv_undef)
103 {
104 char *name = SvPVX (namesv); /* XXX */
105 if (SvFLAGS (namesv) & SVf_FAKE || *name == '&')
106 { /* lexical from outside? */
107 npad[ix] = SvREFCNT_inc (ppad[ix]);
108 }
109 else
110 { /* our own lexical */
111 SV *sv;
112 if (*name == '&')
113 sv = SvREFCNT_inc (ppad[ix]);
114 else if (*name == '@')
115 sv = (SV *) newAV ();
116 else if (*name == '%')
117 sv = (SV *) newHV ();
118 else
119 sv = NEWSV (0, 0);
120 if (!SvPADBUSY (sv))
121 SvPADMY_on (sv);
122 npad[ix] = sv;
123 }
124 }
125 else if (IS_PADGV (ppad[ix]) || IS_PADCONST (ppad[ix]))
126 {
127 npad[ix] = SvREFCNT_inc (ppad[ix]);
128 }
129 else
130 {
131 SV *sv = NEWSV (0, 0);
132 SvPADTMP_on (sv);
133 npad[ix] = sv;
134 }
135 }
136
137 #if 0 /* return -ENOTUNDERSTOOD */
138 /* Now that vars are all in place, clone nested closures. */
139
140 for (ix = fpad; ix > 0; ix--) {
141 SV* namesv = (ix <= fname) ? pname[ix] : Nullsv;
142 if (namesv
143 && namesv != &PL_sv_undef
144 && !(SvFLAGS(namesv) & SVf_FAKE)
145 && *SvPVX(namesv) == '&'
146 && CvCLONE(ppad[ix]))
147 {
148 CV *kid = cv_clone((CV*)ppad[ix]);
149 SvREFCNT_dec(ppad[ix]);
150 CvCLONE_on(kid);
151 SvPADMY_on(kid);
152 npad[ix] = (SV*)kid;
153 }
154 }
155 #endif
156
157 return newpadlist;
158 }
159
160 #ifdef MAY_FLUSH
161 STATIC AV *
162 free_padlist (AV *padlist)
163 {
164 /* may be during global destruction */
165 if (SvREFCNT(padlist))
166 {
167 I32 i = AvFILLp(padlist);
168 while (i >= 0)
169 {
170 SV **svp = av_fetch(padlist, i--, FALSE);
171 SV *sv = svp ? *svp : Nullsv;
172 if (sv)
173 SvREFCNT_dec(sv);
174 }
175
176 SvREFCNT_dec((SV*)padlist);
177 }
178 }
179 #endif
180
181 /* the next two functions merely cache the padlists */
182 STATIC void
183 get_padlist (CV *cv)
184 {
185 SV **he = hv_fetch (padlist_cache, (void *)&cv, sizeof (CV *), 0);
186
187 if (he && AvFILLp ((AV *)*he) >= 0)
188 CvPADLIST (cv) = (AV *)av_pop ((AV *)*he);
189 else
190 CvPADLIST (cv) = clone_padlist (CvPADLIST (cv));
191 }
192
193 STATIC void
194 put_padlist (CV *cv)
195 {
196 SV **he = hv_fetch (padlist_cache, (void *)&cv, sizeof (CV *), 1);
197
198 if (SvTYPE (*he) != SVt_PVAV)
199 {
200 SvREFCNT_dec (*he);
201 *he = (SV *)newAV ();
202 }
203
204 av_push ((AV *)*he, (SV *)CvPADLIST (cv));
205 }
206
207 #ifdef MAY_FLUSH
208 STATIC void
209 flush_padlist_cache ()
210 {
211 HV *hv = padlist_cache;
212 padlist_cache = newHV ();
213
214 if (hv_iterinit (hv))
215 {
216 HE *he;
217 AV *padlist;
218
219 while (!!(he = hv_iternext (hv)))
220 {
221 AV *av = (AV *)HeVAL(he);
222
223 /* casting is fun. */
224 while (&PL_sv_undef != (SV *)(padlist = (AV *)av_pop (av)))
225 free_padlist (padlist);
226 }
227 }
228
229 SvREFCNT_dec (hv);
230 }
231 #endif
232
233 #define SB do {
234 #define SE } while (0)
235
236 #define LOAD(state) SB load_state(aTHX_ state); SPAGAIN; SE
237 #define SAVE(state,flags) SB PUTBACK; save_state(aTHX_ state,flags); SE
238
239 #define REPLACE_SV(sv,val) SB SvREFCNT_dec(sv); (sv) = (val); SE
240
241 static void
242 load_state(pTHX_ Coro__State c)
243 {
244 PL_dowarn = c->dowarn;
245
246 PL_curstackinfo = c->curstackinfo;
247 PL_curstack = c->curstack;
248 PL_mainstack = c->mainstack;
249 PL_stack_sp = c->stack_sp;
250 PL_op = c->op;
251 PL_curpad = c->curpad;
252 PL_stack_base = c->stack_base;
253 PL_stack_max = c->stack_max;
254 PL_tmps_stack = c->tmps_stack;
255 PL_tmps_floor = c->tmps_floor;
256 PL_tmps_ix = c->tmps_ix;
257 PL_tmps_max = c->tmps_max;
258 PL_markstack = c->markstack;
259 PL_markstack_ptr = c->markstack_ptr;
260 PL_markstack_max = c->markstack_max;
261 PL_scopestack = c->scopestack;
262 PL_scopestack_ix = c->scopestack_ix;
263 PL_scopestack_max = c->scopestack_max;
264 PL_savestack = c->savestack;
265 PL_savestack_ix = c->savestack_ix;
266 PL_savestack_max = c->savestack_max;
267 PL_retstack = c->retstack;
268 PL_retstack_ix = c->retstack_ix;
269 PL_retstack_max = c->retstack_max;
270 PL_curcop = c->curcop;
271
272 if (c->defav) REPLACE_SV (GvAV (PL_defgv), c->defav);
273 if (c->defsv) REPLACE_SV (DEFSV , c->defsv);
274 if (c->errsv) REPLACE_SV (ERRSV , c->errsv);
275
276 {
277 dSP;
278 CV *cv;
279
280 /* now do the ugly restore mess */
281 while ((cv = (CV *)POPs))
282 {
283 AV *padlist = (AV *)POPs;
284
285 if (padlist)
286 {
287 put_padlist (cv); /* mark this padlist as available */
288 CvPADLIST(cv) = padlist;
289 #ifdef USE_THREADS
290 /*CvOWNER(cv) = (struct perl_thread *)POPs;*/
291 #endif
292 }
293
294 ++CvDEPTH(cv);
295 }
296
297 PUTBACK;
298 }
299 }
300
301 static void
302 save_state(pTHX_ Coro__State c, int flags)
303 {
304 {
305 dSP;
306 I32 cxix = cxstack_ix;
307 PERL_CONTEXT *ccstk = cxstack;
308 PERL_SI *top_si = PL_curstackinfo;
309
310 /*
311 * the worst thing you can imagine happens first - we have to save
312 * (and reinitialize) all cv's in the whole callchain :(
313 */
314
315 PUSHs (Nullsv);
316 /* this loop was inspired by pp_caller */
317 for (;;)
318 {
319 do
320 {
321 PERL_CONTEXT *cx = &ccstk[cxix--];
322
323 if (CxTYPE(cx) == CXt_SUB)
324 {
325 CV *cv = cx->blk_sub.cv;
326 if (CvDEPTH(cv))
327 {
328 #ifdef USE_THREADS
329 /*XPUSHs ((SV *)CvOWNER(cv));*/
330 /*CvOWNER(cv) = 0;*/
331 /*error must unlock this cv etc.. etc...*/
332 #endif
333 EXTEND (SP, CvDEPTH(cv)*2);
334
335 while (--CvDEPTH(cv))
336 {
337 /* this tells the restore code to increment CvDEPTH */
338 PUSHs (Nullsv);
339 PUSHs ((SV *)cv);
340 }
341
342 PUSHs ((SV *)CvPADLIST(cv));
343 PUSHs ((SV *)cv);
344
345 get_padlist (cv); /* this is a monster */
346 }
347 }
348 else if (CxTYPE(cx) == CXt_FORMAT)
349 {
350 /* I never used formats, so how should I know how these are implemented? */
351 /* my bold guess is as a simple, plain sub... */
352 croak ("CXt_FORMAT not yet handled. Don't switch coroutines from within formats");
353 }
354 }
355 while (cxix >= 0);
356
357 if (top_si->si_type == PERLSI_MAIN)
358 break;
359
360 top_si = top_si->si_prev;
361 ccstk = top_si->si_cxstack;
362 cxix = top_si->si_cxix;
363 }
364
365 PUTBACK;
366 }
367
368 c->defav = flags & SAVE_DEFAV ? (AV *)SvREFCNT_inc (GvAV (PL_defgv)) : 0;
369 c->defsv = flags & SAVE_DEFSV ? SvREFCNT_inc (DEFSV) : 0;
370 c->errsv = flags & SAVE_ERRSV ? SvREFCNT_inc (ERRSV) : 0;
371
372 /* I have not the slightest idea of why av_reify is necessary */
373 /* but if it's missing the defav contents magically get replaced sometimes */
374 if (c->defav)
375 av_reify (c->defav);
376
377 c->dowarn = PL_dowarn;
378
379 c->curstackinfo = PL_curstackinfo;
380 c->curstack = PL_curstack;
381 c->mainstack = PL_mainstack;
382 c->stack_sp = PL_stack_sp;
383 c->op = PL_op;
384 c->curpad = PL_curpad;
385 c->stack_base = PL_stack_base;
386 c->stack_max = PL_stack_max;
387 c->tmps_stack = PL_tmps_stack;
388 c->tmps_floor = PL_tmps_floor;
389 c->tmps_ix = PL_tmps_ix;
390 c->tmps_max = PL_tmps_max;
391 c->markstack = PL_markstack;
392 c->markstack_ptr = PL_markstack_ptr;
393 c->markstack_max = PL_markstack_max;
394 c->scopestack = PL_scopestack;
395 c->scopestack_ix = PL_scopestack_ix;
396 c->scopestack_max = PL_scopestack_max;
397 c->savestack = PL_savestack;
398 c->savestack_ix = PL_savestack_ix;
399 c->savestack_max = PL_savestack_max;
400 c->retstack = PL_retstack;
401 c->retstack_ix = PL_retstack_ix;
402 c->retstack_max = PL_retstack_max;
403 c->curcop = PL_curcop;
404 }
405
406 /*
407 * destroy the stacks, the callchain etc...
408 * still there is a memleak of 128 bytes...
409 */
410 STATIC void
411 destroy_stacks(pTHX)
412 {
413 /* is this ugly, I ask? */
414 while (PL_scopestack_ix)
415 LEAVE;
416
417 /* sure it is, but more important: is it correct?? :/ */
418 while (PL_tmps_ix > PL_tmps_floor) /* should only ever be one iteration */
419 FREETMPS;
420
421 while (PL_curstackinfo->si_next)
422 PL_curstackinfo = PL_curstackinfo->si_next;
423
424 while (PL_curstackinfo)
425 {
426 PERL_SI *p = PL_curstackinfo->si_prev;
427
428 {
429 dSP;
430 SWITCHSTACK (PL_curstack, PL_curstackinfo->si_stack);
431 PUTBACK; /* possibly superfluous */
432 }
433
434 dounwind(-1);
435
436 SvREFCNT_dec(PL_curstackinfo->si_stack);
437 Safefree(PL_curstackinfo->si_cxstack);
438 Safefree(PL_curstackinfo);
439 PL_curstackinfo = p;
440 }
441
442 Safefree(PL_tmps_stack);
443 Safefree(PL_markstack);
444 Safefree(PL_scopestack);
445 Safefree(PL_savestack);
446 Safefree(PL_retstack);
447 }
448
449 STATIC void
450 transfer(pTHX_ struct coro *prev, struct coro *next, int flags)
451 {
452 dSP;
453
454 if (prev != next)
455 {
456 /*
457 * this could be done in newprocess which would lead to
458 * extremely elegant and fast (just SAVE/LOAD)
459 * code here, but lazy allocation of stacks has also
460 * some virtues and the overhead of the if() is nil.
461 */
462 if (next->mainstack)
463 {
464 SAVE (prev, flags);
465 LOAD (next);
466 /* mark this state as in-use */
467 next->mainstack = 0;
468 next->tmps_ix = -2;
469 }
470 else if (next->tmps_ix == -2)
471 {
472 croak ("tried to transfer to running coroutine");
473 }
474 else
475 {
476 /*
477 * emulate part of the perl startup here.
478 */
479 UNOP myop;
480
481 SAVE (prev, -1); /* first get rid of the old state */
482
483 init_stacks (); /* from perl.c */
484 SPAGAIN;
485
486 PL_op = (OP *)&myop;
487 /*PL_curcop = 0;*/
488 SvREFCNT_dec (GvAV (PL_defgv));
489 GvAV (PL_defgv) = next->args;
490
491 Zero(&myop, 1, UNOP);
492 myop.op_next = Nullop;
493 myop.op_flags = OPf_WANT_VOID;
494
495 PUSHMARK(SP);
496 XPUSHs ((SV*)get_cv(SUB_INIT, TRUE));
497 /*
498 * the next line is slightly wrong, as PL_op->op_next
499 * is actually being executed so we skip the first op.
500 * that doesn't matter, though, since it is only
501 * pp_nextstate and we never return...
502 * ah yes, and I don't care anyways ;)
503 */
504 PUTBACK;
505 PL_op = pp_entersub(aTHX);
506 SPAGAIN;
507
508 ENTER; /* necessary e.g. for dounwind */
509 }
510 }
511 }
512
513 MODULE = Coro::State PACKAGE = Coro::State
514
515 PROTOTYPES: ENABLE
516
517 BOOT:
518 { /* {} necessary for stoopid perl-5.6.x */
519 HV * stash = gv_stashpvn("Coro::State", 10, TRUE);
520
521 newCONSTSUB (stash, "SAVE_DEFAV", newSViv (SAVE_DEFAV));
522 newCONSTSUB (stash, "SAVE_DEFSV", newSViv (SAVE_DEFSV));
523 newCONSTSUB (stash, "SAVE_ERRSV", newSViv (SAVE_ERRSV));
524
525 if (!padlist_cache)
526 padlist_cache = newHV ();
527 }
528
529 Coro::State
530 _newprocess(args)
531 SV * args
532 PROTOTYPE: $
533 CODE:
534 Coro__State coro;
535
536 if (!SvROK (args) || SvTYPE (SvRV (args)) != SVt_PVAV)
537 croak ("Coro::State::_newprocess expects an arrayref");
538
539 New (0, coro, 1, struct coro);
540
541 coro->mainstack = 0; /* actual work is done inside transfer */
542 coro->args = (AV *)SvREFCNT_inc (SvRV (args));
543
544 RETVAL = coro;
545 OUTPUT:
546 RETVAL
547
548 void
549 transfer(prev, next, flags = SAVE_ALL)
550 Coro::State_or_hashref prev
551 Coro::State_or_hashref next
552 int flags
553 PROTOTYPE: @
554 CODE:
555
556 transfer (aTHX_ prev, next, flags);
557
558 void
559 DESTROY(coro)
560 Coro::State coro
561 CODE:
562
563 if (coro->mainstack)
564 {
565 struct coro temp;
566
567 SAVE(aTHX_ (&temp), SAVE_ALL);
568 LOAD(aTHX_ coro);
569
570 destroy_stacks ();
571
572 LOAD((&temp)); /* this will get rid of defsv etc.. */
573 }
574
575 Safefree (coro);
576
577 void
578 flush()
579 CODE:
580 #ifdef MAY_FLUSH
581 flush_padlist_cache ();
582 #endif
583
584 MODULE = Coro::State PACKAGE = Coro::Cont
585
586 # this is dirty (do you hear me?) and should be in it's own .xs
587
588 void
589 result(...)
590 PROTOTYPE: @
591 CODE:
592 static SV *returnstk;
593 SV *sv;
594 AV *defav = GvAV (PL_defgv);
595 struct coro *prev, *next;
596
597 if (!returnstk)
598 returnstk = SvRV (get_sv ("Coro::Cont::return", FALSE));
599
600 /* set up @_ -- ugly */
601 av_clear (defav);
602 av_fill (defav, items - 1);
603 while (items--)
604 av_store (defav, items, SvREFCNT_inc (ST(items)));
605
606 mg_get (returnstk); /* isn't documentation wrong for mg_get? */
607 sv = av_pop ((AV *)SvRV (returnstk));
608 prev = (struct coro *)SvIV ((SV*)SvRV (*av_fetch ((AV *)SvRV (sv), 0, 0)));
609 next = (struct coro *)SvIV ((SV*)SvRV (*av_fetch ((AV *)SvRV (sv), 1, 0)));
610 SvREFCNT_dec (sv);
611 transfer(prev, next, 0);
612