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.6 by root, Tue Jul 17 15:42:28 2001 UTC vs.
Revision 1.8 by root, Thu Jul 19 04:13:22 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::_newcoro"
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
162/* the next tow functions merely cache the padlists */ 181/* the next two functions merely cache the padlists */
163STATIC void 182STATIC void
164get_padlist (CV *cv) 183get_padlist (CV *cv)
165{ 184{
166 SV **he = hv_fetch (padlist_cache, (void *)&cv, sizeof (CV *), 0); 185 SV **he = hv_fetch (padlist_cache, (void *)&cv, sizeof (CV *), 0);
167 186
183 } 202 }
184 203
185 av_push ((AV *)*he, (SV *)CvPADLIST (cv)); 204 av_push ((AV *)*he, (SV *)CvPADLIST (cv));
186} 205}
187 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)))
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
188static void 241static void
189save_state(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)
190{ 303{
191 { 304 {
192 dSP; 305 dSP;
193 I32 cxix = cxstack_ix; 306 I32 cxix = cxstack_ix;
194 PERL_SI *top_si = PL_curstackinfo; 307 PERL_SI *top_si = PL_curstackinfo;
201 314
202 PUSHs (Nullsv); 315 PUSHs (Nullsv);
203 /* this loop was inspired by pp_caller */ 316 /* this loop was inspired by pp_caller */
204 for (;;) 317 for (;;)
205 { 318 {
206 while (cxix >= 0) 319 do
207 { 320 {
208 PERL_CONTEXT *cx = &ccstk[cxix--]; 321 PERL_CONTEXT *cx = &ccstk[cxix--];
209 322
210 if (CxTYPE(cx) == CXt_SUB) 323 if (CxTYPE(cx) == CXt_SUB)
211 { 324 {
212 CV *cv = cx->blk_sub.cv; 325 CV *cv = cx->blk_sub.cv;
213 if (CvDEPTH(cv)) 326 if (CvDEPTH(cv))
214 { 327 {
215#ifdef USE_THREADS 328#ifdef USE_THREADS
216 XPUSHs ((SV *)CvOWNER(cv)); 329 /*XPUSHs ((SV *)CvOWNER(cv));*/
330 /*CvOWNER(cv) = 0;*/
331 /*error must unlock this cv etc.. etc...*/
217#endif 332#endif
218 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);
219 PUSHs ((SV *)CvDEPTH(cv)); 339 PUSHs ((SV *)cv);
340 }
341
220 PUSHs ((SV *)CvPADLIST(cv)); 342 PUSHs ((SV *)CvPADLIST(cv));
221 PUSHs ((SV *)cv); 343 PUSHs ((SV *)cv);
222 344
223 get_padlist (cv); 345 get_padlist (cv); /* this is a monster */
224
225 CvDEPTH(cv) = 0;
226#ifdef USE_THREADS
227 CvOWNER(cv) = 0;
228 error must unlock this cv etc.. etc...
229 if you are here wondering about this error message then
230 the reason is that it will not work as advertised yet
231#endif
232 } 346 }
233 } 347 }
234 else if (CxTYPE(cx) == CXt_FORMAT) 348 else if (CxTYPE(cx) == CXt_FORMAT)
235 { 349 {
236 /* 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? */
237 /* my bold guess is as a simple, plain sub... */ 351 /* my bold guess is as a simple, plain sub... */
238 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");
239 } 353 }
240 } 354 }
355 while (cxix >= 0);
241 356
242 if (top_si->si_type == PERLSI_MAIN) 357 if (top_si->si_type == PERLSI_MAIN)
243 break; 358 break;
244 359
245 top_si = top_si->si_prev; 360 top_si = top_si->si_prev;
248 } 363 }
249 364
250 PUTBACK; 365 PUTBACK;
251 } 366 }
252 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
253 c->dowarn = PL_dowarn; 372 c->dowarn = PL_dowarn;
254 c->defav = GvAV (PL_defgv); 373
255 c->curstackinfo = PL_curstackinfo; 374 c->curstackinfo = PL_curstackinfo;
256 c->curstack = PL_curstack; 375 c->curstack = PL_curstack;
257 c->mainstack = PL_mainstack; 376 c->mainstack = PL_mainstack;
258 c->stack_sp = PL_stack_sp; 377 c->stack_sp = PL_stack_sp;
259 c->op = PL_op; 378 c->op = PL_op;
277 c->retstack_ix = PL_retstack_ix; 396 c->retstack_ix = PL_retstack_ix;
278 c->retstack_max = PL_retstack_max; 397 c->retstack_max = PL_retstack_max;
279 c->curcop = PL_curcop; 398 c->curcop = PL_curcop;
280} 399}
281 400
282#define LOAD(state) do { load_state(aTHX_ state); SPAGAIN; } while (0) 401/*
283#define SAVE(state) do { PUTBACK; save_state(aTHX_ state); } while (0) 402 * destroy the stacks, the callchain etc...
284 403 * still there is a memleak of 128 bytes...
285static void 404 */
286load_state(pTHX_ Coro__State c)
287{
288 PL_dowarn = c->dowarn;
289 GvAV (PL_defgv) = c->defav;
290 PL_curstackinfo = c->curstackinfo;
291 PL_curstack = c->curstack;
292 PL_mainstack = c->mainstack;
293 PL_stack_sp = c->stack_sp;
294 PL_op = c->op;
295 PL_curpad = c->curpad;
296 PL_stack_base = c->stack_base;
297 PL_stack_max = c->stack_max;
298 PL_tmps_stack = c->tmps_stack;
299 PL_tmps_floor = c->tmps_floor;
300 PL_tmps_ix = c->tmps_ix;
301 PL_tmps_max = c->tmps_max;
302 PL_markstack = c->markstack;
303 PL_markstack_ptr = c->markstack_ptr;
304 PL_markstack_max = c->markstack_max;
305 PL_scopestack = c->scopestack;
306 PL_scopestack_ix = c->scopestack_ix;
307 PL_scopestack_max = c->scopestack_max;
308 PL_savestack = c->savestack;
309 PL_savestack_ix = c->savestack_ix;
310 PL_savestack_max = c->savestack_max;
311 PL_retstack = c->retstack;
312 PL_retstack_ix = c->retstack_ix;
313 PL_retstack_max = c->retstack_max;
314 PL_curcop = c->curcop;
315
316 {
317 dSP;
318 CV *cv;
319
320 /* now do the ugly restore mess */
321 while ((cv = (CV *)POPs))
322 {
323 AV *padlist = (AV *)POPs;
324
325 put_padlist (cv);
326 CvPADLIST(cv) = padlist;
327 CvDEPTH(cv) = (I32)POPs;
328
329#ifdef USE_THREADS
330 CvOWNER(cv) = (struct perl_thread *)POPs;
331 error does not work either
332#endif
333 }
334
335 PUTBACK;
336 }
337}
338
339/* this is an EXACT copy of S_nuke_stacks in perl.c, which is unfortunately static */
340STATIC void 405STATIC void
341destroy_stacks(pTHX) 406destroy_stacks(pTHX)
342{ 407{
343 /* die does this while calling POPSTACK, but I just don't see why. */
344 /* OTOH, die does not have a memleak, but we do... */
345 dounwind(-1);
346
347 /* is this ugly, I ask? */ 408 /* is this ugly, I ask? */
348 while (PL_scopestack_ix) 409 while (PL_scopestack_ix)
349 LEAVE; 410 LEAVE;
350 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
351 while (PL_curstackinfo->si_next) 416 while (PL_curstackinfo->si_next)
352 PL_curstackinfo = PL_curstackinfo->si_next; 417 PL_curstackinfo = PL_curstackinfo->si_next;
353 418
354 while (PL_curstackinfo) 419 while (PL_curstackinfo)
355 { 420 {
356 PERL_SI *p = PL_curstackinfo->si_prev; 421 PERL_SI *p = PL_curstackinfo->si_prev;
422
423 {
424 dSP;
425 SWITCHSTACK (PL_curstack, PL_curstackinfo->si_stack);
426 PUTBACK; /* possibly superfluous */
427 }
428
429 dounwind(-1);
357 430
358 SvREFCNT_dec(PL_curstackinfo->si_stack); 431 SvREFCNT_dec(PL_curstackinfo->si_stack);
359 Safefree(PL_curstackinfo->si_cxstack); 432 Safefree(PL_curstackinfo->si_cxstack);
360 Safefree(PL_curstackinfo); 433 Safefree(PL_curstackinfo);
361 PL_curstackinfo = p; 434 PL_curstackinfo = p;
362 } 435 }
363 436
364 if (PL_scopestack_ix != 0)
365 Perl_warner(aTHX_ WARN_INTERNAL,
366 "Unbalanced scopes: %ld more ENTERs than LEAVEs\n",
367 (long)PL_scopestack_ix);
368 if (PL_savestack_ix != 0)
369 Perl_warner(aTHX_ WARN_INTERNAL,
370 "Unbalanced saves: %ld more saves than restores\n",
371 (long)PL_savestack_ix);
372 if (PL_tmps_floor != -1)
373 Perl_warner(aTHX_ WARN_INTERNAL,"Unbalanced tmps: %ld more allocs than frees\n",
374 (long)PL_tmps_floor + 1);
375 /*
376 */
377 Safefree(PL_tmps_stack); 437 Safefree(PL_tmps_stack);
378 Safefree(PL_markstack); 438 Safefree(PL_markstack);
379 Safefree(PL_scopestack); 439 Safefree(PL_scopestack);
380 Safefree(PL_savestack); 440 Safefree(PL_savestack);
381 Safefree(PL_retstack); 441 Safefree(PL_retstack);
382} 442}
383 443
384#define SUB_INIT "Coro::State::_newcoro" 444STATIC void
445transfer(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}
385 507
386MODULE = Coro::State PACKAGE = Coro::State 508MODULE = Coro::State PACKAGE = Coro::State
387 509
388PROTOTYPES: ENABLE 510PROTOTYPES: ENABLE
389 511
390BOOT: 512BOOT:
513 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
391 if (!padlist_cache) 519 if (!padlist_cache)
392 padlist_cache = newHV (); 520 padlist_cache = newHV ();
393 521
394Coro::State 522Coro::State
395_newprocess(args) 523_newprocess(args)
397 PROTOTYPE: $ 525 PROTOTYPE: $
398 CODE: 526 CODE:
399 Coro__State coro; 527 Coro__State coro;
400 528
401 if (!SvROK (args) || SvTYPE (SvRV (args)) != SVt_PVAV) 529 if (!SvROK (args) || SvTYPE (SvRV (args)) != SVt_PVAV)
402 croak ("Coro::State::newprocess expects an arrayref"); 530 croak ("Coro::State::_newprocess expects an arrayref");
403 531
404 New (0, coro, 1, struct coro); 532 New (0, coro, 1, struct coro);
405 533
406 coro->mainstack = 0; /* actual work is done inside transfer */ 534 coro->mainstack = 0; /* actual work is done inside transfer */
407 coro->args = (AV *)SvREFCNT_inc (SvRV (args)); 535 coro->args = (AV *)SvREFCNT_inc (SvRV (args));
409 RETVAL = coro; 537 RETVAL = coro;
410 OUTPUT: 538 OUTPUT:
411 RETVAL 539 RETVAL
412 540
413void 541void
414transfer(prev,next) 542transfer(prev, next, flags = SAVE_DEFAV)
415 Coro::State_or_hashref prev 543 Coro::State_or_hashref prev
416 Coro::State_or_hashref next 544 Coro::State_or_hashref next
545 int flags
546 PROTOTYPE: @
417 CODE: 547 CODE:
418 548
419 if (prev != next) 549 transfer (aTHX_ prev, next, flags);
420 {
421 /*
422 * this could be done in newprocess which would lead to
423 * extremely elegant and fast (just SAVE/LOAD)
424 * code here, but lazy allocation of stacks has also
425 * some virtues and the overhead of the if() is nil.
426 */
427 if (next->mainstack)
428 {
429 SAVE (prev);
430 LOAD (next);
431 /* mark this state as in-use */
432 next->mainstack = 0;
433 next->tmps_ix = -2;
434 }
435 else if (next->tmps_ix == -2)
436 {
437 croak ("tried to transfer to running coroutine");
438 }
439 else
440 {
441 SAVE (prev);
442
443 /*
444 * emulate part of the perl startup here.
445 */
446 UNOP myop;
447
448 init_stacks (); /* from perl.c */
449 PL_op = (OP *)&myop;
450 /*PL_curcop = 0;*/
451 GvAV (PL_defgv) = (AV *)SvREFCNT_inc ((SV *)next->args);
452
453 SPAGAIN;
454 Zero(&myop, 1, UNOP);
455 myop.op_next = Nullop;
456 myop.op_flags = OPf_WANT_VOID;
457
458 PUSHMARK(SP);
459 XPUSHs ((SV*)get_cv(SUB_INIT, TRUE));
460 PUTBACK;
461 /*
462 * the next line is slightly wrong, as PL_op->op_next
463 * is actually being executed so we skip the first op.
464 * that doesn't matter, though, since it is only
465 * pp_nextstate and we never return...
466 */
467 PL_op = Perl_pp_entersub(aTHX);
468 SPAGAIN;
469
470 ENTER;
471 }
472 }
473 550
474void 551void
475DESTROY(coro) 552DESTROY(coro)
476 Coro::State coro 553 Coro::State coro
477 CODE: 554 CODE:
478 555
479 if (coro->mainstack) 556 if (coro->mainstack)
480 { 557 {
481 struct coro temp; 558 struct coro temp;
482 559
483 SAVE(aTHX_ (&temp)); 560 SAVE(aTHX_ (&temp), SAVE_ALL);
484 LOAD(aTHX_ coro); 561 LOAD(aTHX_ coro);
485 562
486 destroy_stacks (); 563 destroy_stacks ();
487 SvREFCNT_dec ((SV *)GvAV (PL_defgv));
488 564
489 LOAD((&temp)); 565 LOAD((&temp)); /* this will get rid of defsv etc.. */
490 } 566 }
491 567
492 SvREFCNT_dec (coro->args);
493 Safefree (coro); 568 Safefree (coro);
494 569
570void
571flush()
572 CODE:
573#ifdef MAY_FLUSH
574 flush_padlist_cache ();
575#endif
495 576
577MODULE = Coro::State PACKAGE = Coro::Cont
578
579# this is dirty and should be in it's own .xs
580
581void
582result(...)
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

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines