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

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.7 #if 1
6 root 1.3 # define CHK(x) (void *)0
7     #else
8     # define CHK(x) if (!(x)) croak("FATAL, CHK: " #x)
9     #endif
10    
11 root 1.7 #define MAY_FLUSH /* increases codesize */
12    
13 root 1.11 #define SUB_INIT "Coro::State::initialize"
14 root 1.8
15 root 1.7 #define SAVE_DEFAV 0x00000001
16     #define SAVE_DEFSV 0x00000002
17     #define SAVE_ERRSV 0x00000004
18    
19     #define SAVE_ALL -1
20    
21 root 1.1 struct coro {
22 root 1.7 /* optionally saved, might be zero */
23 root 1.3 AV *defav;
24 root 1.7 SV *defsv;
25     SV *errsv;
26 root 1.1
27 root 1.7 /* saved global state not related to stacks */
28     U8 dowarn;
29    
30     /* the stacks and related info (callchain etc..) */
31 root 1.1 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 root 1.7 /* data associated with this coroutine (initial args) */
58 root 1.3 AV *args;
59 root 1.1 };
60    
61     typedef struct coro *Coro__State;
62     typedef struct coro *Coro__State_or_hashref;
63    
64 root 1.3 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 root 1.7 #if 0 /* return -ENOTUNDERSTOOD */
138 root 1.3 /* 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 root 1.7 #ifdef MAY_FLUSH
161 root 1.3 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 root 1.7 #endif
180 root 1.3
181 root 1.7 /* the next two functions merely cache the padlists */
182 root 1.4 STATIC void
183     get_padlist (CV *cv)
184 root 1.3 {
185 root 1.4 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 root 1.3 }
206    
207 root 1.7 #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 root 1.3 static void
302 root 1.7 save_state(pTHX_ Coro__State c, int flags)
303 root 1.3 {
304     {
305     dSP;
306     I32 cxix = cxstack_ix;
307 root 1.11 PERL_CONTEXT *ccstk = cxstack;
308 root 1.3 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 root 1.11 do
320 root 1.3 {
321 root 1.4 PERL_CONTEXT *cx = &ccstk[cxix--];
322 root 1.3
323     if (CxTYPE(cx) == CXt_SUB)
324     {
325     CV *cv = cx->blk_sub.cv;
326     if (CvDEPTH(cv))
327     {
328     #ifdef USE_THREADS
329 root 1.7 /*XPUSHs ((SV *)CvOWNER(cv));*/
330     /*CvOWNER(cv) = 0;*/
331     /*error must unlock this cv etc.. etc...*/
332 root 1.3 #endif
333 root 1.7 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 root 1.3 PUSHs ((SV *)CvPADLIST(cv));
343     PUSHs ((SV *)cv);
344    
345 root 1.7 get_padlist (cv); /* this is a monster */
346 root 1.3 }
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 root 1.7 while (cxix >= 0);
356 root 1.3
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 root 1.7 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 root 1.11 /* 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 root 1.3 c->dowarn = PL_dowarn;
378 root 1.7
379 root 1.3 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 root 1.1
406 root 1.7 /*
407     * destroy the stacks, the callchain etc...
408     * still there is a memleak of 128 bytes...
409     */
410 root 1.1 STATIC void
411 root 1.4 destroy_stacks(pTHX)
412 root 1.1 {
413 root 1.4 /* is this ugly, I ask? */
414     while (PL_scopestack_ix)
415     LEAVE;
416    
417 root 1.7 /* 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 root 1.4 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 root 1.7 {
429     dSP;
430     SWITCHSTACK (PL_curstack, PL_curstackinfo->si_stack);
431     PUTBACK; /* possibly superfluous */
432     }
433    
434     dounwind(-1);
435    
436 root 1.4 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 root 1.1 }
448    
449 root 1.8 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 root 1.3
513     MODULE = Coro::State PACKAGE = Coro::State
514 root 1.1
515     PROTOTYPES: ENABLE
516    
517 root 1.3 BOOT:
518 root 1.11 { /* {} necessary for stoopid perl-5.6.x */
519 root 1.7 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 root 1.3 if (!padlist_cache)
526     padlist_cache = newHV ();
527 root 1.9 }
528 root 1.3
529 root 1.1 Coro::State
530 root 1.3 _newprocess(args)
531     SV * args
532     PROTOTYPE: $
533 root 1.1 CODE:
534     Coro__State coro;
535 root 1.3
536     if (!SvROK (args) || SvTYPE (SvRV (args)) != SVt_PVAV)
537 root 1.7 croak ("Coro::State::_newprocess expects an arrayref");
538 root 1.1
539     New (0, coro, 1, struct coro);
540    
541     coro->mainstack = 0; /* actual work is done inside transfer */
542 root 1.3 coro->args = (AV *)SvREFCNT_inc (SvRV (args));
543 root 1.1
544     RETVAL = coro;
545     OUTPUT:
546     RETVAL
547    
548     void
549 root 1.11 transfer(prev, next, flags = SAVE_ALL)
550 root 1.3 Coro::State_or_hashref prev
551     Coro::State_or_hashref next
552 root 1.7 int flags
553 root 1.8 PROTOTYPE: @
554 root 1.1 CODE:
555    
556 root 1.8 transfer (aTHX_ prev, next, flags);
557 root 1.1
558     void
559     DESTROY(coro)
560 root 1.3 Coro::State coro
561 root 1.1 CODE:
562    
563     if (coro->mainstack)
564     {
565     struct coro temp;
566    
567 root 1.7 SAVE(aTHX_ (&temp), SAVE_ALL);
568 root 1.3 LOAD(aTHX_ coro);
569 root 1.1
570 root 1.4 destroy_stacks ();
571 root 1.1
572 root 1.7 LOAD((&temp)); /* this will get rid of defsv etc.. */
573 root 1.1 }
574    
575     Safefree (coro);
576 root 1.7
577     void
578     flush()
579     CODE:
580     #ifdef MAY_FLUSH
581     flush_padlist_cache ();
582     #endif
583 root 1.1
584 root 1.8 MODULE = Coro::State PACKAGE = Coro::Cont
585    
586 root 1.11 # this is dirty (do you hear me?) and should be in it's own .xs
587 root 1.8
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 root 1.11 /* set up @_ -- ugly */
601 root 1.8 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 root 1.1