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

Comparing Coro/Coro/State.xs (file contents):
Revision 1.3 by root, Tue Jul 17 00:24:15 2001 UTC vs.
Revision 1.10 by root, Sat Jul 21 04:19:34 2001 UTC

1#include "EXTERN.h" 1#include "EXTERN.h"
2#include "perl.h" 2#include "perl.h"
3#include "XSUB.h" 3#include "XSUB.h"
4 4
5#if 0 5#if 1
6# define CHK(x) (void *)0 6# define CHK(x) (void *)0
7#else 7#else
8# define CHK(x) if (!(x)) croak("FATAL, CHK: " #x) 8# define CHK(x) if (!(x)) croak("FATAL, CHK: " #x)
9#endif 9#endif
10 10
11#define MAY_FLUSH /* increases codesize */
12
13#define SUB_INIT "Coro::State::coroutine_initialization"
14
15#define SAVE_DEFAV 0x00000001
16#define SAVE_DEFSV 0x00000002
17#define SAVE_ERRSV 0x00000004
18
19#define SAVE_ALL -1
20
11struct coro { 21struct 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 */
12 U8 dowarn; 28 U8 dowarn;
13 AV *defav; 29
14 30 /* the stacks and related info (callchain etc..) */
15 PERL_SI *curstackinfo; 31 PERL_SI *curstackinfo;
16 AV *curstack; 32 AV *curstack;
17 AV *mainstack; 33 AV *mainstack;
18 SV **stack_sp; 34 SV **stack_sp;
19 OP *op; 35 OP *op;
36 OP **retstack; 52 OP **retstack;
37 I32 retstack_ix; 53 I32 retstack_ix;
38 I32 retstack_max; 54 I32 retstack_max;
39 COP *curcop; 55 COP *curcop;
40 56
57 /* data associated with this coroutine (initial args) */
41 AV *args; 58 AV *args;
42}; 59};
43 60
44typedef struct coro *Coro__State; 61typedef struct coro *Coro__State;
45typedef struct coro *Coro__State_or_hashref; 62typedef struct coro *Coro__State_or_hashref;
115 SvPADTMP_on (sv); 132 SvPADTMP_on (sv);
116 npad[ix] = sv; 133 npad[ix] = sv;
117 } 134 }
118 } 135 }
119 136
120#if 0 /* NONOTUNDERSTOOD */ 137#if 0 /* return -ENOTUNDERSTOOD */
121 /* Now that vars are all in place, clone nested closures. */ 138 /* Now that vars are all in place, clone nested closures. */
122 139
123 for (ix = fpad; ix > 0; ix--) { 140 for (ix = fpad; ix > 0; ix--) {
124 SV* namesv = (ix <= fname) ? pname[ix] : Nullsv; 141 SV* namesv = (ix <= fname) ? pname[ix] : Nullsv;
125 if (namesv 142 if (namesv
138#endif 155#endif
139 156
140 return newpadlist; 157 return newpadlist;
141} 158}
142 159
160#ifdef MAY_FLUSH
143STATIC AV * 161STATIC AV *
144free_padlist (AV *padlist) 162free_padlist (AV *padlist)
145{ 163{
146 /* may be during global destruction */ 164 /* may be during global destruction */
147 if (SvREFCNT(padlist)) 165 if (SvREFCNT(padlist))
156 } 174 }
157 175
158 SvREFCNT_dec((SV*)padlist); 176 SvREFCNT_dec((SV*)padlist);
159 } 177 }
160} 178}
179#endif
161 180
162STATIC AV * 181/* the next two functions merely cache the padlists */
163unuse_padlist (AV *padlist) 182STATIC void
183get_padlist (CV *cv)
164{ 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
193STATIC void
194put_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
208STATIC void
209flush_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)))
165 free_padlist (padlist); 225 free_padlist (padlist);
226 }
227 }
228
229 SvREFCNT_dec (hv);
166} 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
167 240
168static void 241static void
169SAVE(pTHX_ Coro__State c) 242load_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
301static void
302save_state(pTHX_ Coro__State c, int flags)
170{ 303{
171 { 304 {
172 dSP; 305 dSP;
173 I32 cxix = cxstack_ix; 306 I32 cxix = cxstack_ix;
174 PERL_SI *top_si = PL_curstackinfo; 307 PERL_SI *top_si = PL_curstackinfo;
181 314
182 PUSHs (Nullsv); 315 PUSHs (Nullsv);
183 /* this loop was inspired by pp_caller */ 316 /* this loop was inspired by pp_caller */
184 for (;;) 317 for (;;)
185 { 318 {
186 while (cxix >= 0) 319 do
187 { 320 {
188 PERL_CONTEXT *cx = &ccstk[--cxix]; 321 PERL_CONTEXT *cx = &ccstk[cxix--];
189 322
190 if (CxTYPE(cx) == CXt_SUB) 323 if (CxTYPE(cx) == CXt_SUB)
191 { 324 {
192 CV *cv = cx->blk_sub.cv; 325 CV *cv = cx->blk_sub.cv;
193 if (CvDEPTH(cv)) 326 if (CvDEPTH(cv))
194 { 327 {
195#ifdef USE_THREADS 328#ifdef USE_THREADS
196 XPUSHs ((SV *)CvOWNER(cv)); 329 /*XPUSHs ((SV *)CvOWNER(cv));*/
330 /*CvOWNER(cv) = 0;*/
331 /*error must unlock this cv etc.. etc...*/
197#endif 332#endif
198 EXTEND (SP, 3); 333 EXTEND (SP, CvDEPTH(cv)*2);
334
335 while (--CvDEPTH(cv))
336 {
337 /* this tells the restore code to increment CvDEPTH */
338 PUSHs (Nullsv);
199 PUSHs ((SV *)CvDEPTH(cv)); 339 PUSHs ((SV *)cv);
340 }
341
200 PUSHs ((SV *)CvPADLIST(cv)); 342 PUSHs ((SV *)CvPADLIST(cv));
201 PUSHs ((SV *)cv); 343 PUSHs ((SV *)cv);
202 344
203 CvPADLIST(cv) = clone_padlist (CvPADLIST(cv)); 345 get_padlist (cv); /* this is a monster */
204
205 CvDEPTH(cv) = 0;
206#ifdef USE_THREADS
207 CvOWNER(cv) = 0;
208 error must unlock this cv etc.. etc...
209 if you are here wondering about this error message then
210 the reason is that it will not work as advertised yet
211#endif
212 } 346 }
213 } 347 }
214 else if (CxTYPE(cx) == CXt_FORMAT) 348 else if (CxTYPE(cx) == CXt_FORMAT)
215 { 349 {
216 /* I never used formats, so how should I know how these are implemented? */ 350 /* I never used formats, so how should I know how these are implemented? */
217 /* my bold guess is as a simple, plain sub... */ 351 /* my bold guess is as a simple, plain sub... */
218 croak ("CXt_FORMAT not yet handled. Don't switch coroutines from within formats"); 352 croak ("CXt_FORMAT not yet handled. Don't switch coroutines from within formats");
219 } 353 }
220 } 354 }
355 while (cxix >= 0);
221 356
222 if (top_si->si_type == PERLSI_MAIN) 357 if (top_si->si_type == PERLSI_MAIN)
223 break; 358 break;
224 359
225 top_si = top_si->si_prev; 360 top_si = top_si->si_prev;
228 } 363 }
229 364
230 PUTBACK; 365 PUTBACK;
231 } 366 }
232 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
233 c->dowarn = PL_dowarn; 372 c->dowarn = PL_dowarn;
234 c->defav = GvAV (PL_defgv); 373
235 c->curstackinfo = PL_curstackinfo; 374 c->curstackinfo = PL_curstackinfo;
236 c->curstack = PL_curstack; 375 c->curstack = PL_curstack;
237 c->mainstack = PL_mainstack; 376 c->mainstack = PL_mainstack;
238 c->stack_sp = PL_stack_sp; 377 c->stack_sp = PL_stack_sp;
239 c->op = PL_op; 378 c->op = PL_op;
257 c->retstack_ix = PL_retstack_ix; 396 c->retstack_ix = PL_retstack_ix;
258 c->retstack_max = PL_retstack_max; 397 c->retstack_max = PL_retstack_max;
259 c->curcop = PL_curcop; 398 c->curcop = PL_curcop;
260} 399}
261 400
262static void 401/*
263LOAD(pTHX_ Coro__State c) 402 * destroy the stacks, the callchain etc...
403 * still there is a memleak of 128 bytes...
404 */
405STATIC void
406destroy_stacks(pTHX)
264{ 407{
265 PL_dowarn = c->dowarn; 408 /* is this ugly, I ask? */
266 GvAV (PL_defgv) = c->defav; 409 while (PL_scopestack_ix)
410 LEAVE;
411
412 /* 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 while (PL_curstackinfo->si_next)
267 PL_curstackinfo = c->curstackinfo; 417 PL_curstackinfo = PL_curstackinfo->si_next;
268 PL_curstack = c->curstack;
269 PL_mainstack = c->mainstack;
270 PL_stack_sp = c->stack_sp;
271 PL_op = c->op;
272 PL_curpad = c->curpad;
273 PL_stack_base = c->stack_base;
274 PL_stack_max = c->stack_max;
275 PL_tmps_stack = c->tmps_stack;
276 PL_tmps_floor = c->tmps_floor;
277 PL_tmps_ix = c->tmps_ix;
278 PL_tmps_max = c->tmps_max;
279 PL_markstack = c->markstack;
280 PL_markstack_ptr = c->markstack_ptr;
281 PL_markstack_max = c->markstack_max;
282 PL_scopestack = c->scopestack;
283 PL_scopestack_ix = c->scopestack_ix;
284 PL_scopestack_max = c->scopestack_max;
285 PL_savestack = c->savestack;
286 PL_savestack_ix = c->savestack_ix;
287 PL_savestack_max = c->savestack_max;
288 PL_retstack = c->retstack;
289 PL_retstack_ix = c->retstack_ix;
290 PL_retstack_max = c->retstack_max;
291 PL_curcop = c->curcop;
292 418
419 while (PL_curstackinfo)
293 { 420 {
294 dSP; 421 PERL_SI *p = PL_curstackinfo->si_prev;
295 CV *cv;
296 422
297 /* now do the ugly restore mess */
298 while ((cv = (CV *)POPs))
299 { 423 {
300 AV *padlist = (AV *)POPs; 424 dSP;
301 425 SWITCHSTACK (PL_curstack, PL_curstackinfo->si_stack);
302 unuse_padlist (CvPADLIST(cv)); 426 PUTBACK; /* possibly superfluous */
303 CvPADLIST(cv) = padlist;
304 CvDEPTH(cv) = (I32)POPs;
305
306#ifdef USE_THREADS
307 CvOWNER(cv) = (struct perl_thread *)POPs;
308 error does not work either
309#endif
310 } 427 }
311 428
312 PUTBACK; 429 dounwind(-1);
430
431 SvREFCNT_dec(PL_curstackinfo->si_stack);
432 Safefree(PL_curstackinfo->si_cxstack);
433 Safefree(PL_curstackinfo);
434 PL_curstackinfo = p;
313 } 435 }
314}
315 436
316/* this is an EXACT copy of S_nuke_stacks in perl.c, which is unfortunately static */ 437 Safefree(PL_tmps_stack);
438 Safefree(PL_markstack);
439 Safefree(PL_scopestack);
440 Safefree(PL_savestack);
441 Safefree(PL_retstack);
442}
443
317STATIC void 444STATIC void
318S_nuke_stacks(pTHX) 445transfer(pTHX_ struct coro *prev, struct coro *next, int flags)
319{ 446{
320 while (PL_curstackinfo->si_next) 447 dSP;
321 PL_curstackinfo = PL_curstackinfo->si_next; 448
322 while (PL_curstackinfo) { 449 if (prev != next)
323 PERL_SI *p = PL_curstackinfo->si_prev; 450 {
324 /* curstackinfo->si_stack got nuked by sv_free_arenas() */ 451 /*
325 Safefree(PL_curstackinfo->si_cxstack); 452 * this could be done in newprocess which would lead to
326 Safefree(PL_curstackinfo); 453 * extremely elegant and fast (just SAVE/LOAD)
327 PL_curstackinfo = p; 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 }
328 } 505 }
329 Safefree(PL_tmps_stack);
330 Safefree(PL_markstack);
331 Safefree(PL_scopestack);
332 Safefree(PL_savestack);
333 Safefree(PL_retstack);
334} 506}
335
336#define SUB_INIT "Coro::State::_newcoro"
337 507
338MODULE = Coro::State PACKAGE = Coro::State 508MODULE = Coro::State PACKAGE = Coro::State
339 509
340PROTOTYPES: ENABLE 510PROTOTYPES: ENABLE
341 511
342BOOT: 512BOOT:
513{ /* {} necessary for stoopid perl-5.6.x */
514 HV * stash = gv_stashpvn("Coro::State", 10, TRUE);
515
516 newCONSTSUB (stash, "SAVE_DEFAV", newSViv (SAVE_DEFAV));
517 newCONSTSUB (stash, "SAVE_DEFSV", newSViv (SAVE_DEFSV));
518 newCONSTSUB (stash, "SAVE_ERRSV", newSViv (SAVE_ERRSV));
519
343 if (!padlist_cache) 520 if (!padlist_cache)
344 padlist_cache = newHV (); 521 padlist_cache = newHV ();
522}
345 523
346Coro::State 524Coro::State
347_newprocess(args) 525_newprocess(args)
348 SV * args 526 SV * args
349 PROTOTYPE: $ 527 PROTOTYPE: $
350 CODE: 528 CODE:
351 Coro__State coro; 529 Coro__State coro;
352 530
353 if (!SvROK (args) || SvTYPE (SvRV (args)) != SVt_PVAV) 531 if (!SvROK (args) || SvTYPE (SvRV (args)) != SVt_PVAV)
354 croak ("Coro::State::newprocess expects an arrayref"); 532 croak ("Coro::State::_newprocess expects an arrayref");
355 533
356 New (0, coro, 1, struct coro); 534 New (0, coro, 1, struct coro);
357 535
358 coro->mainstack = 0; /* actual work is done inside transfer */ 536 coro->mainstack = 0; /* actual work is done inside transfer */
359 coro->args = (AV *)SvREFCNT_inc (SvRV (args)); 537 coro->args = (AV *)SvREFCNT_inc (SvRV (args));
361 RETVAL = coro; 539 RETVAL = coro;
362 OUTPUT: 540 OUTPUT:
363 RETVAL 541 RETVAL
364 542
365void 543void
366transfer(prev,next) 544transfer(prev, next, flags = SAVE_DEFAV)
367 Coro::State_or_hashref prev 545 Coro::State_or_hashref prev
368 Coro::State_or_hashref next 546 Coro::State_or_hashref next
547 int flags
548 PROTOTYPE: @
369 CODE: 549 CODE:
370 550
371 if (prev != next) 551 transfer (aTHX_ prev, next, flags);
372 {
373 PUTBACK;
374 SAVE (aTHX_ prev);
375
376 /*
377 * this could be done in newprocess which would lead to
378 * extremely elegant and fast (just PUTBACK/SAVE/LOAD/SPAGAIN)
379 * code here, but lazy allocation of stacks has also
380 * some virtues and the overhead of the if() is nil.
381 */
382 if (next->mainstack)
383 {
384 LOAD (aTHX_ next);
385 next->mainstack = 0; /* unnecessary but much cleaner */
386 SPAGAIN;
387 }
388 else
389 {
390 /*
391 * emulate part of the perl startup here.
392 */
393 UNOP myop;
394
395 init_stacks ();
396 PL_op = (OP *)&myop;
397 /*PL_curcop = 0;*/
398 GvAV (PL_defgv) = (SV *)SvREFCNT_inc (next->args);
399
400 SPAGAIN;
401 Zero(&myop, 1, UNOP);
402 myop.op_next = Nullop;
403 myop.op_flags = OPf_WANT_VOID;
404
405 PUSHMARK(SP);
406 XPUSHs ((SV*)get_cv(SUB_INIT, TRUE));
407 PUTBACK;
408 /*
409 * the next line is slightly wrong, as PL_op->op_next
410 * is actually being executed so we skip the first op.
411 * that doesn't matter, though, since it is only
412 * pp_nextstate and we never return...
413 */
414 PL_op = Perl_pp_entersub(aTHX);
415 SPAGAIN;
416
417 ENTER;
418 }
419 }
420 552
421void 553void
422DESTROY(coro) 554DESTROY(coro)
423 Coro::State coro 555 Coro::State coro
424 CODE: 556 CODE:
425 557
426 if (coro->mainstack) 558 if (coro->mainstack)
427 { 559 {
428 struct coro temp; 560 struct coro temp;
429 561
430 PUTBACK;
431 SAVE(aTHX_ (&temp)); 562 SAVE(aTHX_ (&temp), SAVE_ALL);
432 LOAD(aTHX_ coro); 563 LOAD(aTHX_ coro);
433 564
434 S_nuke_stacks (); 565 destroy_stacks ();
435 SvREFCNT_dec ((SV *)GvAV (PL_defgv));
436 566
437 LOAD((&temp)); 567 LOAD((&temp)); /* this will get rid of defsv etc.. */
438 SPAGAIN;
439 } 568 }
440 569
441 SvREFCNT_dec (coro->args);
442 Safefree (coro); 570 Safefree (coro);
443 571
572void
573flush()
574 CODE:
575#ifdef MAY_FLUSH
576 flush_padlist_cache ();
577#endif
444 578
579MODULE = Coro::State PACKAGE = Coro::Cont
580
581# this is dirty and should be in it's own .xs
582
583void
584result(...)
585 PROTOTYPE: @
586 CODE:
587 static SV *returnstk;
588 SV *sv;
589 AV *defav = GvAV (PL_defgv);
590 struct coro *prev, *next;
591
592 if (!returnstk)
593 returnstk = SvRV (get_sv ("Coro::Cont::return", FALSE));
594
595 /* set up @_ */
596 av_clear (defav);
597 av_fill (defav, items - 1);
598 while (items--)
599 av_store (defav, items, SvREFCNT_inc (ST(items)));
600
601 mg_get (returnstk); /* isn't documentation wrong for mg_get? */
602 sv = av_pop ((AV *)SvRV (returnstk));
603 prev = (struct coro *)SvIV ((SV*)SvRV (*av_fetch ((AV *)SvRV (sv), 0, 0)));
604 next = (struct coro *)SvIV ((SV*)SvRV (*av_fetch ((AV *)SvRV (sv), 1, 0)));
605 SvREFCNT_dec (sv);
606 transfer(prev, next, 0);
607

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines