ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/State.xs
Revision: 1.8
Committed: Thu Jul 19 04:13:22 2001 UTC (22 years, 10 months ago) by root
Branch: MAIN
Changes since 1.7: +95 -58 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.8 #define SUB_INIT "Coro::State::_newcoro"
14    
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     PERL_SI *top_si = PL_curstackinfo;
308     PERL_CONTEXT *ccstk = cxstack;
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.7 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.3 c->dowarn = PL_dowarn;
373 root 1.7
374 root 1.3 c->curstackinfo = PL_curstackinfo;
375     c->curstack = PL_curstack;
376     c->mainstack = PL_mainstack;
377     c->stack_sp = PL_stack_sp;
378     c->op = PL_op;
379     c->curpad = PL_curpad;
380     c->stack_base = PL_stack_base;
381     c->stack_max = PL_stack_max;
382     c->tmps_stack = PL_tmps_stack;
383     c->tmps_floor = PL_tmps_floor;
384     c->tmps_ix = PL_tmps_ix;
385     c->tmps_max = PL_tmps_max;
386     c->markstack = PL_markstack;
387     c->markstack_ptr = PL_markstack_ptr;
388     c->markstack_max = PL_markstack_max;
389     c->scopestack = PL_scopestack;
390     c->scopestack_ix = PL_scopestack_ix;
391     c->scopestack_max = PL_scopestack_max;
392     c->savestack = PL_savestack;
393     c->savestack_ix = PL_savestack_ix;
394     c->savestack_max = PL_savestack_max;
395     c->retstack = PL_retstack;
396     c->retstack_ix = PL_retstack_ix;
397     c->retstack_max = PL_retstack_max;
398     c->curcop = PL_curcop;
399     }
400 root 1.1
401 root 1.7 /*
402     * destroy the stacks, the callchain etc...
403     * still there is a memleak of 128 bytes...
404     */
405 root 1.1 STATIC void
406 root 1.4 destroy_stacks(pTHX)
407 root 1.1 {
408 root 1.4 /* is this ugly, I ask? */
409     while (PL_scopestack_ix)
410     LEAVE;
411    
412 root 1.7 /* sure it is, but more important: is it correct?? :/ */
413     while (PL_tmps_ix > PL_tmps_floor) /* should only ever be one iteration */
414     FREETMPS;
415    
416 root 1.4 while (PL_curstackinfo->si_next)
417     PL_curstackinfo = PL_curstackinfo->si_next;
418    
419     while (PL_curstackinfo)
420     {
421     PERL_SI *p = PL_curstackinfo->si_prev;
422    
423 root 1.7 {
424     dSP;
425     SWITCHSTACK (PL_curstack, PL_curstackinfo->si_stack);
426     PUTBACK; /* possibly superfluous */
427     }
428    
429     dounwind(-1);
430    
431 root 1.4 SvREFCNT_dec(PL_curstackinfo->si_stack);
432     Safefree(PL_curstackinfo->si_cxstack);
433     Safefree(PL_curstackinfo);
434     PL_curstackinfo = p;
435     }
436    
437     Safefree(PL_tmps_stack);
438     Safefree(PL_markstack);
439     Safefree(PL_scopestack);
440     Safefree(PL_savestack);
441     Safefree(PL_retstack);
442 root 1.1 }
443    
444 root 1.8 STATIC void
445     transfer(pTHX_ struct coro *prev, struct coro *next, int flags)
446     {
447     dSP;
448    
449     if (prev != next)
450     {
451     /*
452     * this could be done in newprocess which would lead to
453     * extremely elegant and fast (just SAVE/LOAD)
454     * code here, but lazy allocation of stacks has also
455     * some virtues and the overhead of the if() is nil.
456     */
457     if (next->mainstack)
458     {
459     SAVE (prev, flags);
460     LOAD (next);
461     /* mark this state as in-use */
462     next->mainstack = 0;
463     next->tmps_ix = -2;
464     }
465     else if (next->tmps_ix == -2)
466     {
467     croak ("tried to transfer to running coroutine");
468     }
469     else
470     {
471     /*
472     * emulate part of the perl startup here.
473     */
474     UNOP myop;
475    
476     SAVE (prev, -1); /* first get rid of the old state */
477    
478     init_stacks (); /* from perl.c */
479     SPAGAIN;
480    
481     PL_op = (OP *)&myop;
482     /*PL_curcop = 0;*/
483     SvREFCNT_dec (GvAV (PL_defgv));
484     GvAV (PL_defgv) = next->args;
485    
486     Zero(&myop, 1, UNOP);
487     myop.op_next = Nullop;
488     myop.op_flags = OPf_WANT_VOID;
489    
490     PUSHMARK(SP);
491     XPUSHs ((SV*)get_cv(SUB_INIT, TRUE));
492     /*
493     * the next line is slightly wrong, as PL_op->op_next
494     * is actually being executed so we skip the first op.
495     * that doesn't matter, though, since it is only
496     * pp_nextstate and we never return...
497     * ah yes, and I don't care anyways ;)
498     */
499     PUTBACK;
500     PL_op = pp_entersub(aTHX);
501     SPAGAIN;
502    
503     ENTER; /* necessary e.g. for dounwind */
504     }
505     }
506     }
507 root 1.3
508     MODULE = Coro::State PACKAGE = Coro::State
509 root 1.1
510     PROTOTYPES: ENABLE
511    
512 root 1.3 BOOT:
513 root 1.7 HV * stash = gv_stashpvn("Coro::State", 10, TRUE);
514    
515     newCONSTSUB (stash, "SAVE_DEFAV", newSViv (SAVE_DEFAV));
516     newCONSTSUB (stash, "SAVE_DEFSV", newSViv (SAVE_DEFSV));
517     newCONSTSUB (stash, "SAVE_ERRSV", newSViv (SAVE_ERRSV));
518    
519 root 1.3 if (!padlist_cache)
520     padlist_cache = newHV ();
521    
522 root 1.1 Coro::State
523 root 1.3 _newprocess(args)
524     SV * args
525     PROTOTYPE: $
526 root 1.1 CODE:
527     Coro__State coro;
528 root 1.3
529     if (!SvROK (args) || SvTYPE (SvRV (args)) != SVt_PVAV)
530 root 1.7 croak ("Coro::State::_newprocess expects an arrayref");
531 root 1.1
532     New (0, coro, 1, struct coro);
533    
534     coro->mainstack = 0; /* actual work is done inside transfer */
535 root 1.3 coro->args = (AV *)SvREFCNT_inc (SvRV (args));
536 root 1.1
537     RETVAL = coro;
538     OUTPUT:
539     RETVAL
540    
541     void
542 root 1.7 transfer(prev, next, flags = SAVE_DEFAV)
543 root 1.3 Coro::State_or_hashref prev
544     Coro::State_or_hashref next
545 root 1.7 int flags
546 root 1.8 PROTOTYPE: @
547 root 1.1 CODE:
548    
549 root 1.8 transfer (aTHX_ prev, next, flags);
550 root 1.1
551     void
552     DESTROY(coro)
553 root 1.3 Coro::State coro
554 root 1.1 CODE:
555    
556     if (coro->mainstack)
557     {
558     struct coro temp;
559    
560 root 1.7 SAVE(aTHX_ (&temp), SAVE_ALL);
561 root 1.3 LOAD(aTHX_ coro);
562 root 1.1
563 root 1.4 destroy_stacks ();
564 root 1.1
565 root 1.7 LOAD((&temp)); /* this will get rid of defsv etc.. */
566 root 1.1 }
567    
568     Safefree (coro);
569 root 1.7
570     void
571     flush()
572     CODE:
573     #ifdef MAY_FLUSH
574     flush_padlist_cache ();
575     #endif
576 root 1.1
577 root 1.8 MODULE = Coro::State PACKAGE = Coro::Cont
578    
579     # this is dirty and should be in it's own .xs
580    
581     void
582     result(...)
583     PROTOTYPE: @
584     CODE:
585     static SV *returnstk;
586     SV *sv;
587     AV *defav = GvAV (PL_defgv);
588     struct coro *prev, *next;
589    
590     if (!returnstk)
591     returnstk = SvRV (get_sv ("Coro::Cont::return", FALSE));
592    
593     /* set up @_ */
594     av_clear (defav);
595     av_fill (defav, items - 1);
596     while (items--)
597     av_store (defav, items, SvREFCNT_inc (ST(items)));
598    
599     mg_get (returnstk); /* isn't documentation wrong for mg_get? */
600     sv = av_pop ((AV *)SvRV (returnstk));
601     prev = (struct coro *)SvIV ((SV*)SvRV (*av_fetch ((AV *)SvRV (sv), 0, 0)));
602     next = (struct coro *)SvIV ((SV*)SvRV (*av_fetch ((AV *)SvRV (sv), 1, 0)));
603     SvREFCNT_dec (sv);
604     transfer(prev, next, 0);
605 root 1.1