… | |
… | |
101 | #else |
101 | #else |
102 | # define LOCK (void)0 |
102 | # define LOCK (void)0 |
103 | # define UNLOCK (void)0 |
103 | # define UNLOCK (void)0 |
104 | #endif |
104 | #endif |
105 | |
105 | |
|
|
106 | struct io_state |
|
|
107 | { |
|
|
108 | int errorno; |
|
|
109 | I32 laststype; |
|
|
110 | int laststatval; |
|
|
111 | Stat_t statcache; |
|
|
112 | }; |
|
|
113 | |
106 | static struct CoroAPI coroapi; |
114 | static struct CoroAPI coroapi; |
107 | static AV *main_mainstack; /* used to differentiate between $main and others */ |
115 | static AV *main_mainstack; /* used to differentiate between $main and others */ |
108 | static HV *coro_state_stash, *coro_stash; |
116 | static HV *coro_state_stash, *coro_stash; |
109 | static SV *coro_mortal; /* will be freed after next transfer */ |
117 | static SV *coro_mortal; /* will be freed after next transfer */ |
110 | |
118 | |
… | |
… | |
497 | |
505 | |
498 | { |
506 | { |
499 | dSP; |
507 | dSP; |
500 | LOGOP myop; |
508 | LOGOP myop; |
501 | |
509 | |
502 | /* I have no idea why this is needed, but it is */ |
|
|
503 | PUSHMARK (SP); |
|
|
504 | |
|
|
505 | SvREFCNT_dec (GvAV (PL_defgv)); |
510 | SvREFCNT_dec (GvAV (PL_defgv)); |
506 | GvAV (PL_defgv) = coro->args; coro->args = 0; |
511 | GvAV (PL_defgv) = coro->args; coro->args = 0; |
507 | |
512 | |
508 | Zero (&myop, 1, LOGOP); |
513 | Zero (&myop, 1, LOGOP); |
509 | myop.op_next = Nullop; |
514 | myop.op_next = Nullop; |
510 | myop.op_flags = OPf_WANT_VOID; |
515 | myop.op_flags = OPf_WANT_VOID; |
511 | |
516 | |
512 | PL_op = (OP *)&myop; |
|
|
513 | |
|
|
514 | PUSHMARK (SP); |
517 | PUSHMARK (SP); |
515 | XPUSHs ((SV *)get_cv ("Coro::State::_coro_init", FALSE)); |
518 | XPUSHs ((SV *)get_cv ("Coro::State::_coro_init", FALSE)); |
516 | PUTBACK; |
519 | PUTBACK; |
|
|
520 | PL_op = (OP *)&myop; |
517 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
521 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
518 | SPAGAIN; |
522 | SPAGAIN; |
519 | } |
523 | } |
520 | |
524 | |
521 | ENTER; /* necessary e.g. for dounwind */ |
525 | ENTER; /* necessary e.g. for dounwind */ |
… | |
… | |
529 | SvREFCNT_dec (coro_mortal); |
533 | SvREFCNT_dec (coro_mortal); |
530 | coro_mortal = 0; |
534 | coro_mortal = 0; |
531 | } |
535 | } |
532 | } |
536 | } |
533 | |
537 | |
|
|
538 | /* inject a fake call to Coro::State::_cctx_init into the execution */ |
534 | static void NOINLINE |
539 | static void NOINLINE |
535 | prepare_cctx (coro_cctx *cctx) |
540 | prepare_cctx (coro_cctx *cctx) |
536 | { |
541 | { |
537 | dSP; |
542 | dSP; |
538 | LOGOP myop; |
543 | LOGOP myop; |
539 | |
544 | |
540 | Zero (&myop, 1, LOGOP); |
545 | Zero (&myop, 1, LOGOP); |
541 | myop.op_next = PL_op; |
546 | myop.op_next = PL_op; |
542 | myop.op_flags = OPf_WANT_VOID; |
547 | myop.op_flags = OPf_WANT_VOID | OPf_STACKED; |
543 | |
|
|
544 | sv_setiv (get_sv ("Coro::State::_cctx", FALSE), PTR2IV (cctx)); |
|
|
545 | |
548 | |
546 | PUSHMARK (SP); |
549 | PUSHMARK (SP); |
|
|
550 | EXTEND (SP, 2); |
|
|
551 | PUSHs (sv_2mortal (newSViv (PTR2IV (cctx)))); |
547 | XPUSHs ((SV *)get_cv ("Coro::State::_cctx_init", FALSE)); |
552 | PUSHs ((SV *)get_cv ("Coro::State::_cctx_init", FALSE)); |
548 | PUTBACK; |
553 | PUTBACK; |
|
|
554 | PL_op = (OP *)&myop; |
549 | PL_restartop = PL_ppaddr[OP_ENTERSUB](aTHX); |
555 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
550 | SPAGAIN; |
556 | SPAGAIN; |
551 | } |
557 | } |
552 | |
558 | |
553 | static void |
559 | static void |
554 | coro_run (void *arg) |
560 | coro_run (void *arg) |
555 | { |
561 | { |
556 | /* coro_run is the alternative epilogue of transfer() */ |
562 | /* coro_run is the alternative tail of transfer(), so unlock here. */ |
557 | UNLOCK; |
563 | UNLOCK; |
558 | |
564 | |
559 | /* |
565 | /* |
560 | * this is a _very_ stripped down perl interpreter ;) |
566 | * this is a _very_ stripped down perl interpreter ;) |
561 | */ |
567 | */ |
… | |
… | |
563 | |
569 | |
564 | /* inject call to cctx_init */ |
570 | /* inject call to cctx_init */ |
565 | prepare_cctx ((coro_cctx *)arg); |
571 | prepare_cctx ((coro_cctx *)arg); |
566 | |
572 | |
567 | /* somebody will hit me for both perl_run and PL_restartop */ |
573 | /* somebody will hit me for both perl_run and PL_restartop */ |
|
|
574 | PL_restartop = PL_op; |
568 | perl_run (PL_curinterp); |
575 | perl_run (PL_curinterp); |
569 | |
576 | |
570 | fputs ("FATAL: C coroutine fell over the edge of the world, aborting. Did you call exit in a coroutine?\n", stderr); |
577 | fputs ("FATAL: C coroutine fell over the edge of the world, aborting. Did you call exit in a coroutine?\n", stderr); |
571 | abort (); |
578 | abort (); |
572 | } |
579 | } |
… | |
… | |
581 | New (0, cctx, 1, coro_cctx); |
588 | New (0, cctx, 1, coro_cctx); |
582 | |
589 | |
583 | #if HAVE_MMAP |
590 | #if HAVE_MMAP |
584 | |
591 | |
585 | cctx->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE; |
592 | cctx->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE; |
586 | /* mmap suppsedly does allocate-on-write for us */ |
593 | /* mmap supposedly does allocate-on-write for us */ |
587 | cctx->sptr = mmap (0, cctx->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); |
594 | cctx->sptr = mmap (0, cctx->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); |
588 | |
595 | |
589 | if (cctx->sptr == (void *)-1) |
596 | if (cctx->sptr == (void *)-1) |
590 | { |
597 | { |
591 | perror ("FATAL: unable to mmap stack for coroutine"); |
598 | perror ("FATAL: unable to mmap stack for coroutine"); |
… | |
… | |
1231 | |
1238 | |
1232 | SV * |
1239 | SV * |
1233 | _get_state () |
1240 | _get_state () |
1234 | CODE: |
1241 | CODE: |
1235 | { |
1242 | { |
1236 | struct { |
1243 | RETVAL = newSV (sizeof (struct io_state)); |
1237 | int errorno; |
1244 | struct io_state *data = (struct io_state *)SvPVX (RETVAL); |
1238 | int laststype; |
1245 | SvCUR_set (RETVAL, sizeof (struct io_state)); |
1239 | int laststatval; |
1246 | SvPOK_only (RETVAL); |
1240 | Stat_t statcache; |
|
|
1241 | } data; |
|
|
1242 | |
1247 | |
1243 | data.errorno = errno; |
1248 | data->errorno = errno; |
1244 | data.laststype = PL_laststype; |
1249 | data->laststype = PL_laststype; |
1245 | data.laststatval = PL_laststatval; |
1250 | data->laststatval = PL_laststatval; |
1246 | data.statcache = PL_statcache; |
1251 | data->statcache = PL_statcache; |
1247 | |
|
|
1248 | RETVAL = newSVpvn ((char *)&data, sizeof data); |
|
|
1249 | } |
1252 | } |
1250 | OUTPUT: |
1253 | OUTPUT: |
1251 | RETVAL |
1254 | RETVAL |
1252 | |
1255 | |
1253 | void |
1256 | void |
1254 | _set_state (char *data_) |
1257 | _set_state (char *data_) |
1255 | PROTOTYPE: $ |
1258 | PROTOTYPE: $ |
1256 | CODE: |
1259 | CODE: |
1257 | { |
1260 | { |
1258 | struct { |
1261 | struct io_state *data = (void *)data_; |
1259 | int errorno; |
|
|
1260 | int laststype; |
|
|
1261 | int laststatval; |
|
|
1262 | Stat_t statcache; |
|
|
1263 | } *data = (void *)data_; |
|
|
1264 | |
1262 | |
1265 | errno = data->errorno; |
1263 | errno = data->errorno; |
1266 | PL_laststype = data->laststype; |
1264 | PL_laststype = data->laststype; |
1267 | PL_laststatval = data->laststatval; |
1265 | PL_laststatval = data->laststatval; |
1268 | PL_statcache = data->statcache; |
1266 | PL_statcache = data->statcache; |
1269 | } |
1267 | } |
|
|
1268 | |