… | |
… | |
66 | #define dSTACKLEVEL int stacklevel |
66 | #define dSTACKLEVEL int stacklevel |
67 | #define STACKLEVEL ((void *)&stacklevel) |
67 | #define STACKLEVEL ((void *)&stacklevel) |
68 | |
68 | |
69 | #define IN_DESTRUCT (PL_main_cv == Nullcv) |
69 | #define IN_DESTRUCT (PL_main_cv == Nullcv) |
70 | |
70 | |
71 | #define labs(l) ((l) >= 0 ? (l) : -(l)) |
|
|
72 | |
|
|
73 | #include "CoroAPI.h" |
71 | #include "CoroAPI.h" |
74 | |
72 | |
75 | #define TRANSFER_SET_STACKLEVEL 0x8bfbfbfb /* magic cookie */ |
73 | #define TRANSFER_SET_STACKLEVEL 0x8bfbfbfb /* magic cookie */ |
76 | |
74 | |
77 | #ifdef USE_ITHREADS |
75 | #ifdef USE_ITHREADS |
… | |
… | |
95 | /* the stack */ |
93 | /* the stack */ |
96 | void *sptr; |
94 | void *sptr; |
97 | long ssize; /* positive == mmap, otherwise malloc */ |
95 | long ssize; /* positive == mmap, otherwise malloc */ |
98 | |
96 | |
99 | /* cpu state */ |
97 | /* cpu state */ |
100 | void *idle_sp; /* original stacklevel when coroutine was created */ |
98 | void *idle_sp; /* sp of top-level transfer/schedule/cede call */ |
101 | JMPENV *top_env; |
99 | JMPENV *top_env; |
102 | coro_context cctx; |
100 | coro_context cctx; |
103 | } coro_stack; |
101 | } coro_stack; |
104 | |
|
|
105 | /* the (fake) coro_stack representing the main program */ |
|
|
106 | static coro_stack *main_stack; |
|
|
107 | |
102 | |
108 | /* this is a structure representing a perl-level coroutine */ |
103 | /* this is a structure representing a perl-level coroutine */ |
109 | struct coro { |
104 | struct coro { |
110 | /* the c coroutine allocated to this perl coroutine, if any */ |
105 | /* the c coroutine allocated to this perl coroutine, if any */ |
111 | coro_stack *stack; |
106 | coro_stack *stack; |
… | |
… | |
234 | if (mg && AvFILLp ((AV *)mg->mg_obj) >= 0) |
229 | if (mg && AvFILLp ((AV *)mg->mg_obj) >= 0) |
235 | CvPADLIST (cv) = (AV *)av_pop ((AV *)mg->mg_obj); |
230 | CvPADLIST (cv) = (AV *)av_pop ((AV *)mg->mg_obj); |
236 | else |
231 | else |
237 | { |
232 | { |
238 | #if 0 |
233 | #if 0 |
239 | /* this should work - but it doesn't :( */ |
234 | /* this is probably cleaner, but also slower? */ |
240 | CV *cp = Perl_cv_clone (aTHX_ cv); |
235 | CV *cp = Perl_cv_clone (aTHX_ cv); |
241 | CvPADLIST (cv) = CvPADLIST (cp); |
236 | CvPADLIST (cv) = CvPADLIST (cp); |
242 | CvPADLIST (cp) = 0; |
237 | CvPADLIST (cp) = 0; |
243 | SvREFCNT_dec (cp); |
238 | SvREFCNT_dec (cp); |
244 | #else |
239 | #else |
… | |
… | |
585 | { |
580 | { |
586 | /* |
581 | /* |
587 | * this is a _very_ stripped down perl interpreter ;) |
582 | * this is a _very_ stripped down perl interpreter ;) |
588 | */ |
583 | */ |
589 | dTHX; |
584 | dTHX; |
|
|
585 | int ret; |
590 | |
586 | |
591 | UNLOCK; |
587 | UNLOCK; |
592 | |
588 | |
593 | PL_top_env = &PL_start_env; |
589 | PL_top_env = &PL_start_env; |
594 | |
590 | |
… | |
… | |
596 | sv_setiv (get_sv ("Coro::State::cctx_restartop", FALSE), PTR2IV (PL_op)); |
592 | sv_setiv (get_sv ("Coro::State::cctx_restartop", FALSE), PTR2IV (PL_op)); |
597 | |
593 | |
598 | /* continue at cctx_init, without entersub */ |
594 | /* continue at cctx_init, without entersub */ |
599 | PL_restartop = CvSTART (get_cv ("Coro::State::cctx_init", FALSE)); |
595 | PL_restartop = CvSTART (get_cv ("Coro::State::cctx_init", FALSE)); |
600 | |
596 | |
601 | /* somebody will hit me for both perl_run and PL_restart_op */ |
597 | /* somebody will hit me for both perl_run and PL_restartop */ |
602 | perl_run (aTHX_ PERL_GET_CONTEXT); |
598 | ret = perl_run (aTHX_ PERL_GET_CONTEXT); |
|
|
599 | printf ("ret %d\n", ret);//D |
603 | |
600 | |
|
|
601 | fputs ("FATAL: C coroutine fell over the edge of the world, aborting.\n", stderr); |
604 | abort (); |
602 | abort (); |
605 | } |
603 | } |
606 | |
604 | |
607 | static coro_stack * |
605 | static coro_stack * |
608 | stack_new () |
606 | stack_new () |
… | |
… | |
611 | |
609 | |
612 | New (0, stack, 1, coro_stack); |
610 | New (0, stack, 1, coro_stack); |
613 | |
611 | |
614 | #if HAVE_MMAP |
612 | #if HAVE_MMAP |
615 | |
613 | |
616 | stack->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE; /* mmap should do allocate-on-write for us */ |
614 | stack->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE; |
|
|
615 | /* mmap suppsedly does allocate-on-write for us */ |
617 | stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); |
616 | stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); |
618 | |
617 | |
619 | if (stack->sptr == (void *)-1) |
618 | if (stack->sptr == (void *)-1) |
620 | { |
619 | { |
621 | perror ("FATAL: unable to mmap stack for coroutine"); |
620 | perror ("FATAL: unable to mmap stack for coroutine"); |
622 | _exit (EXIT_FAILURE); |
621 | _exit (EXIT_FAILURE); |
623 | } |
622 | } |
624 | |
623 | |
|
|
624 | # if STACKGUARD |
625 | mprotect (stack->sptr, STACKGUARD * PAGESIZE, PROT_NONE); |
625 | mprotect (stack->sptr, STACKGUARD * PAGESIZE, PROT_NONE); |
|
|
626 | # endif |
626 | |
627 | |
627 | #else |
628 | #else |
628 | |
629 | |
629 | stack->ssize = STACKSIZE * (long)sizeof (long); |
630 | stack->ssize = STACKSIZE * (long)sizeof (long); |
630 | New (0, stack->sptr, STACKSIZE, long); |
631 | New (0, stack->sptr, STACKSIZE, long); |
… | |
… | |
643 | } |
644 | } |
644 | |
645 | |
645 | static void |
646 | static void |
646 | stack_free (coro_stack *stack) |
647 | stack_free (coro_stack *stack) |
647 | { |
648 | { |
648 | if (!stack || stack == main_stack) |
649 | if (!stack) |
649 | return; |
650 | return; |
650 | |
651 | |
651 | #if HAVE_MMAP |
652 | #if HAVE_MMAP |
652 | munmap (stack->sptr, stack->ssize); |
653 | munmap (stack->sptr, stack->ssize); |
653 | #else |
654 | #else |
… | |
… | |
715 | setup_coro (next); |
716 | setup_coro (next); |
716 | /* need a stack */ |
717 | /* need a stack */ |
717 | next->stack = 0; |
718 | next->stack = 0; |
718 | } |
719 | } |
719 | |
720 | |
|
|
721 | if (!prev->stack) |
|
|
722 | /* create a new empty context */ |
|
|
723 | Newz (0, prev->stack, 1, coro_stack); |
|
|
724 | |
720 | prev__stack = prev->stack; |
725 | prev__stack = prev->stack; |
721 | |
726 | |
722 | /* possibly "free" the stack */ |
727 | /* possibly "free" the stack */ |
723 | if (prev__stack->idle_sp == STACKLEVEL) |
728 | if (prev__stack->idle_sp == STACKLEVEL) |
724 | { |
729 | { |
… | |
… | |
1002 | main_mainstack = PL_mainstack; |
1007 | main_mainstack = PL_mainstack; |
1003 | |
1008 | |
1004 | coroapi.ver = CORO_API_VERSION; |
1009 | coroapi.ver = CORO_API_VERSION; |
1005 | coroapi.transfer = api_transfer; |
1010 | coroapi.transfer = api_transfer; |
1006 | |
1011 | |
1007 | Newz (0, main_stack, 1, coro_stack); |
|
|
1008 | main_stack->idle_sp = (void *)-1; |
|
|
1009 | |
|
|
1010 | assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); |
1012 | assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); |
1011 | } |
1013 | } |
1012 | |
1014 | |
1013 | SV * |
1015 | SV * |
1014 | new (char *klass, ...) |
1016 | new (char *klass, ...) |
… | |
… | |
1026 | RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); |
1028 | RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); |
1027 | |
1029 | |
1028 | for (i = 1; i < items; i++) |
1030 | for (i = 1; i < items; i++) |
1029 | av_push (coro->args, newSVsv (ST (i))); |
1031 | av_push (coro->args, newSVsv (ST (i))); |
1030 | |
1032 | |
1031 | coro->stack = main_stack; |
|
|
1032 | /*coro->mainstack = 0; *//*actual work is done inside transfer */ |
1033 | /*coro->mainstack = 0; *//*actual work is done inside transfer */ |
1033 | /*coro->stack = 0;*/ |
1034 | /*coro->stack = 0;*/ |
1034 | } |
1035 | } |
1035 | OUTPUT: |
1036 | OUTPUT: |
1036 | RETVAL |
1037 | RETVAL |
1037 | |
1038 | |
1038 | void |
1039 | void |
1039 | transfer (...) |
1040 | _set_stacklevel (...) |
1040 | ALIAS: |
1041 | ALIAS: |
1041 | Coro::schedule = 1 |
1042 | Coro::State::transfer = 1 |
1042 | Coro::cede = 2 |
1043 | Coro::schedule = 2 |
1043 | _set_stacklevel = 3 |
1044 | Coro::cede = 3 |
|
|
1045 | Coro::Cont::yield = 4 |
1044 | CODE: |
1046 | CODE: |
1045 | { |
1047 | { |
1046 | struct transfer_args ta; |
1048 | struct transfer_args ta; |
1047 | |
1049 | |
1048 | switch (ix) |
1050 | switch (ix) |
1049 | { |
1051 | { |
1050 | case 0: |
1052 | case 0: |
1051 | if (items != 3) |
|
|
1052 | croak ("Coro::State::transfer(prev,next,flags) expects three arguments, not %d", items); |
|
|
1053 | |
|
|
1054 | prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2))); |
|
|
1055 | break; |
|
|
1056 | |
|
|
1057 | case 1: |
|
|
1058 | prepare_schedule (&ta); |
|
|
1059 | break; |
|
|
1060 | |
|
|
1061 | case 2: |
|
|
1062 | prepare_cede (&ta); |
|
|
1063 | break; |
|
|
1064 | |
|
|
1065 | case 3: |
|
|
1066 | ta.prev = (struct coro *)INT2PTR (coro_stack *, SvIV (ST (0))); |
1053 | ta.prev = (struct coro *)INT2PTR (coro_stack *, SvIV (ST (0))); |
1067 | ta.next = 0; |
1054 | ta.next = 0; |
1068 | ta.flags = TRANSFER_SET_STACKLEVEL; |
1055 | ta.flags = TRANSFER_SET_STACKLEVEL; |
1069 | break; |
1056 | break; |
|
|
1057 | |
|
|
1058 | case 1: |
|
|
1059 | if (items != 3) |
|
|
1060 | croak ("Coro::State::transfer(prev,next,flags) expects three arguments, not %d", items); |
|
|
1061 | |
|
|
1062 | prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2))); |
|
|
1063 | break; |
|
|
1064 | |
|
|
1065 | case 2: |
|
|
1066 | prepare_schedule (&ta); |
|
|
1067 | break; |
|
|
1068 | |
|
|
1069 | case 3: |
|
|
1070 | prepare_cede (&ta); |
|
|
1071 | break; |
|
|
1072 | |
|
|
1073 | case 4: |
|
|
1074 | { |
|
|
1075 | SV *yieldstack; |
|
|
1076 | SV *sv; |
|
|
1077 | AV *defav = GvAV (PL_defgv); |
|
|
1078 | |
|
|
1079 | yieldstack = *hv_fetch ( |
|
|
1080 | (HV *)SvRV (GvSV (coro_current)), |
|
|
1081 | "yieldstack", sizeof ("yieldstack") - 1, |
|
|
1082 | 0 |
|
|
1083 | ); |
|
|
1084 | |
|
|
1085 | /* set up @_ -- ugly */ |
|
|
1086 | av_clear (defav); |
|
|
1087 | av_fill (defav, items - 1); |
|
|
1088 | while (items--) |
|
|
1089 | av_store (defav, items, SvREFCNT_inc (ST(items))); |
|
|
1090 | |
|
|
1091 | sv = av_pop ((AV *)SvRV (yieldstack)); |
|
|
1092 | ta.prev = SvSTATE (*av_fetch ((AV *)SvRV (sv), 0, 0)); |
|
|
1093 | ta.next = SvSTATE (*av_fetch ((AV *)SvRV (sv), 1, 0)); |
|
|
1094 | ta.flags = 0; |
|
|
1095 | SvREFCNT_dec (sv); |
|
|
1096 | } |
|
|
1097 | break; |
|
|
1098 | |
1070 | } |
1099 | } |
1071 | |
1100 | |
1072 | TRANSFER (ta); |
1101 | TRANSFER (ta); |
1073 | } |
1102 | } |
1074 | |
1103 | |
… | |
… | |
1094 | _exit (code) |
1123 | _exit (code) |
1095 | int code |
1124 | int code |
1096 | PROTOTYPE: $ |
1125 | PROTOTYPE: $ |
1097 | CODE: |
1126 | CODE: |
1098 | _exit (code); |
1127 | _exit (code); |
1099 | |
|
|
1100 | MODULE = Coro::State PACKAGE = Coro::Cont |
|
|
1101 | |
|
|
1102 | void |
|
|
1103 | yield (...) |
|
|
1104 | PROTOTYPE: @ |
|
|
1105 | CODE: |
|
|
1106 | { |
|
|
1107 | SV *yieldstack; |
|
|
1108 | SV *sv; |
|
|
1109 | AV *defav = GvAV (PL_defgv); |
|
|
1110 | struct coro *prev, *next; |
|
|
1111 | |
|
|
1112 | yieldstack = *hv_fetch ( |
|
|
1113 | (HV *)SvRV (GvSV (coro_current)), |
|
|
1114 | "yieldstack", sizeof ("yieldstack") - 1, |
|
|
1115 | 0 |
|
|
1116 | ); |
|
|
1117 | |
|
|
1118 | /* set up @_ -- ugly */ |
|
|
1119 | av_clear (defav); |
|
|
1120 | av_fill (defav, items - 1); |
|
|
1121 | while (items--) |
|
|
1122 | av_store (defav, items, SvREFCNT_inc (ST(items))); |
|
|
1123 | |
|
|
1124 | sv = av_pop ((AV *)SvRV (yieldstack)); |
|
|
1125 | prev = SvSTATE (*av_fetch ((AV *)SvRV (sv), 0, 0)); |
|
|
1126 | next = SvSTATE (*av_fetch ((AV *)SvRV (sv), 1, 0)); |
|
|
1127 | SvREFCNT_dec (sv); |
|
|
1128 | |
|
|
1129 | coro_state_transfer (aTHX_ prev, next, 0); |
|
|
1130 | } |
|
|
1131 | |
1128 | |
1132 | MODULE = Coro::State PACKAGE = Coro |
1129 | MODULE = Coro::State PACKAGE = Coro |
1133 | |
1130 | |
1134 | BOOT: |
1131 | BOOT: |
1135 | { |
1132 | { |