… | |
… | |
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 |
… | |
… | |
90 | |
88 | |
91 | /* this is a structure representing a c-level coroutine */ |
89 | /* this is a structure representing a c-level coroutine */ |
92 | typedef struct coro_stack { |
90 | typedef struct coro_stack { |
93 | struct coro_stack *next; |
91 | struct coro_stack *next; |
94 | |
92 | |
95 | void *idle_sp; /* original stacklevel when coroutine was created */ |
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 */ |
|
|
98 | void *idle_sp; /* original stacklevel when coroutine was created */ |
|
|
99 | JMPENV *top_env; |
100 | coro_context cctx; |
100 | coro_context cctx; |
101 | JMPENV *top_env; |
|
|
102 | } coro_stack; |
101 | } coro_stack; |
103 | |
|
|
104 | /* the (fake) coro_stack representing the main program */ |
|
|
105 | static coro_stack *main_stack; |
|
|
106 | |
102 | |
107 | /* this is a structure representing a perl-level coroutine */ |
103 | /* this is a structure representing a perl-level coroutine */ |
108 | struct coro { |
104 | struct coro { |
109 | /* the c coroutine allocated to this perl coroutine, if any */ |
105 | /* the c coroutine allocated to this perl coroutine, if any */ |
110 | coro_stack *stack; |
106 | coro_stack *stack; |
… | |
… | |
584 | { |
580 | { |
585 | /* |
581 | /* |
586 | * this is a _very_ stripped down perl interpreter ;) |
582 | * this is a _very_ stripped down perl interpreter ;) |
587 | */ |
583 | */ |
588 | dTHX; |
584 | dTHX; |
|
|
585 | int ret; |
|
|
586 | |
|
|
587 | UNLOCK; |
|
|
588 | |
589 | PL_top_env = &PL_start_env; |
589 | PL_top_env = &PL_start_env; |
590 | |
|
|
591 | UNLOCK; |
|
|
592 | |
590 | |
593 | sv_setiv (get_sv ("Coro::State::cctx_stack", FALSE), PTR2IV ((coro_stack *)arg)); |
591 | sv_setiv (get_sv ("Coro::State::cctx_stack", FALSE), PTR2IV ((coro_stack *)arg)); |
594 | 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)); |
|
|
593 | |
|
|
594 | /* continue at cctx_init, without entersub */ |
595 | PL_restartop = CvSTART (get_cv ("Coro::State::cctx_init", FALSE)); |
595 | PL_restartop = CvSTART (get_cv ("Coro::State::cctx_init", FALSE)); |
596 | |
596 | |
597 | /* somebody will hit me for both perl_run and PL_restart_op */ |
597 | /* somebody will hit me for both perl_run and PL_restartop */ |
598 | perl_run (aTHX_ PERL_GET_CONTEXT); |
598 | ret = perl_run (aTHX_ PERL_GET_CONTEXT); |
|
|
599 | printf ("ret %d\n", ret);//D |
599 | |
600 | |
|
|
601 | fputs ("FATAL: C coroutine fell over the edge of the world, aborting.\n", stderr); |
600 | abort (); |
602 | abort (); |
601 | } |
603 | } |
602 | |
604 | |
603 | static coro_stack * |
605 | static coro_stack * |
604 | stack_new () |
606 | stack_new () |
… | |
… | |
607 | |
609 | |
608 | New (0, stack, 1, coro_stack); |
610 | New (0, stack, 1, coro_stack); |
609 | |
611 | |
610 | #if HAVE_MMAP |
612 | #if HAVE_MMAP |
611 | |
613 | |
612 | 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 */ |
613 | 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); |
614 | |
617 | |
615 | if (stack->sptr == (void *)-1) |
618 | if (stack->sptr == (void *)-1) |
616 | { |
619 | { |
617 | perror ("FATAL: unable to mmap stack for coroutine"); |
620 | perror ("FATAL: unable to mmap stack for coroutine"); |
618 | _exit (EXIT_FAILURE); |
621 | _exit (EXIT_FAILURE); |
619 | } |
622 | } |
620 | |
623 | |
|
|
624 | # if STACKGUARD |
621 | mprotect (stack->sptr, STACKGUARD * PAGESIZE, PROT_NONE); |
625 | mprotect (stack->sptr, STACKGUARD * PAGESIZE, PROT_NONE); |
|
|
626 | # endif |
622 | |
627 | |
623 | #else |
628 | #else |
624 | |
629 | |
625 | stack->ssize = STACKSIZE * (long)sizeof (long); |
630 | stack->ssize = STACKSIZE * (long)sizeof (long); |
626 | New (0, stack->sptr, STACKSIZE, long); |
631 | New (0, stack->sptr, STACKSIZE, long); |
… | |
… | |
639 | } |
644 | } |
640 | |
645 | |
641 | static void |
646 | static void |
642 | stack_free (coro_stack *stack) |
647 | stack_free (coro_stack *stack) |
643 | { |
648 | { |
644 | if (!stack || stack == main_stack) |
649 | if (!stack) |
645 | return; |
650 | return; |
646 | |
651 | |
647 | #if HAVE_MMAP |
652 | #if HAVE_MMAP |
648 | munmap (stack->sptr, stack->ssize); |
653 | munmap (stack->sptr, stack->ssize); |
649 | #else |
654 | #else |
… | |
… | |
711 | setup_coro (next); |
716 | setup_coro (next); |
712 | /* need a stack */ |
717 | /* need a stack */ |
713 | next->stack = 0; |
718 | next->stack = 0; |
714 | } |
719 | } |
715 | |
720 | |
|
|
721 | if (!prev->stack) |
|
|
722 | /* create a new empty context */ |
|
|
723 | Newz (0, prev->stack, 1, coro_stack); |
|
|
724 | |
716 | prev__stack = prev->stack; |
725 | prev__stack = prev->stack; |
717 | |
726 | |
718 | /* possibly "free" the stack */ |
727 | /* possibly "free" the stack */ |
719 | if (prev__stack->idle_sp == STACKLEVEL) |
728 | if (prev__stack->idle_sp == STACKLEVEL) |
720 | { |
729 | { |
… | |
… | |
998 | main_mainstack = PL_mainstack; |
1007 | main_mainstack = PL_mainstack; |
999 | |
1008 | |
1000 | coroapi.ver = CORO_API_VERSION; |
1009 | coroapi.ver = CORO_API_VERSION; |
1001 | coroapi.transfer = api_transfer; |
1010 | coroapi.transfer = api_transfer; |
1002 | |
1011 | |
1003 | Newz (0, main_stack, 1, coro_stack); |
|
|
1004 | main_stack->idle_sp = (void *)-1; |
|
|
1005 | |
|
|
1006 | assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); |
1012 | assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); |
1007 | } |
1013 | } |
1008 | |
1014 | |
1009 | SV * |
1015 | SV * |
1010 | new (char *klass, ...) |
1016 | new (char *klass, ...) |
… | |
… | |
1022 | RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); |
1028 | RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); |
1023 | |
1029 | |
1024 | for (i = 1; i < items; i++) |
1030 | for (i = 1; i < items; i++) |
1025 | av_push (coro->args, newSVsv (ST (i))); |
1031 | av_push (coro->args, newSVsv (ST (i))); |
1026 | |
1032 | |
1027 | coro->stack = main_stack; |
|
|
1028 | /*coro->mainstack = 0; *//*actual work is done inside transfer */ |
1033 | /*coro->mainstack = 0; *//*actual work is done inside transfer */ |
1029 | /*coro->stack = 0;*/ |
1034 | /*coro->stack = 0;*/ |
1030 | } |
1035 | } |
1031 | OUTPUT: |
1036 | OUTPUT: |
1032 | RETVAL |
1037 | RETVAL |
1033 | |
1038 | |
1034 | void |
1039 | void |
1035 | transfer (...) |
1040 | _set_stacklevel (...) |
1036 | ALIAS: |
1041 | ALIAS: |
1037 | Coro::schedule = 1 |
1042 | Coro::State::transfer = 1 |
1038 | Coro::cede = 2 |
1043 | Coro::schedule = 2 |
1039 | _set_stacklevel = 3 |
1044 | Coro::cede = 3 |
|
|
1045 | Coro::Cont::yield = 4 |
1040 | CODE: |
1046 | CODE: |
1041 | { |
1047 | { |
1042 | struct transfer_args ta; |
1048 | struct transfer_args ta; |
1043 | |
1049 | |
1044 | switch (ix) |
1050 | switch (ix) |
1045 | { |
1051 | { |
1046 | case 0: |
1052 | case 0: |
1047 | if (items != 3) |
|
|
1048 | croak ("Coro::State::transfer(prev,next,flags) expects three arguments, not %d", items); |
|
|
1049 | |
|
|
1050 | prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2))); |
|
|
1051 | break; |
|
|
1052 | |
|
|
1053 | case 1: |
|
|
1054 | prepare_schedule (&ta); |
|
|
1055 | break; |
|
|
1056 | |
|
|
1057 | case 2: |
|
|
1058 | prepare_cede (&ta); |
|
|
1059 | break; |
|
|
1060 | |
|
|
1061 | case 3: |
|
|
1062 | ta.prev = (struct coro *)INT2PTR (coro_stack *, SvIV (ST (0))); |
1053 | ta.prev = (struct coro *)INT2PTR (coro_stack *, SvIV (ST (0))); |
1063 | ta.next = 0; |
1054 | ta.next = 0; |
1064 | ta.flags = TRANSFER_SET_STACKLEVEL; |
1055 | ta.flags = TRANSFER_SET_STACKLEVEL; |
1065 | 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 | |
1066 | } |
1099 | } |
1067 | |
1100 | |
1068 | TRANSFER (ta); |
1101 | TRANSFER (ta); |
1069 | } |
1102 | } |
1070 | |
1103 | |
… | |
… | |
1090 | _exit (code) |
1123 | _exit (code) |
1091 | int code |
1124 | int code |
1092 | PROTOTYPE: $ |
1125 | PROTOTYPE: $ |
1093 | CODE: |
1126 | CODE: |
1094 | _exit (code); |
1127 | _exit (code); |
1095 | |
|
|
1096 | MODULE = Coro::State PACKAGE = Coro::Cont |
|
|
1097 | |
|
|
1098 | void |
|
|
1099 | yield (...) |
|
|
1100 | PROTOTYPE: @ |
|
|
1101 | CODE: |
|
|
1102 | { |
|
|
1103 | SV *yieldstack; |
|
|
1104 | SV *sv; |
|
|
1105 | AV *defav = GvAV (PL_defgv); |
|
|
1106 | struct coro *prev, *next; |
|
|
1107 | |
|
|
1108 | yieldstack = *hv_fetch ( |
|
|
1109 | (HV *)SvRV (GvSV (coro_current)), |
|
|
1110 | "yieldstack", sizeof ("yieldstack") - 1, |
|
|
1111 | 0 |
|
|
1112 | ); |
|
|
1113 | |
|
|
1114 | /* set up @_ -- ugly */ |
|
|
1115 | av_clear (defav); |
|
|
1116 | av_fill (defav, items - 1); |
|
|
1117 | while (items--) |
|
|
1118 | av_store (defav, items, SvREFCNT_inc (ST(items))); |
|
|
1119 | |
|
|
1120 | sv = av_pop ((AV *)SvRV (yieldstack)); |
|
|
1121 | prev = SvSTATE (*av_fetch ((AV *)SvRV (sv), 0, 0)); |
|
|
1122 | next = SvSTATE (*av_fetch ((AV *)SvRV (sv), 1, 0)); |
|
|
1123 | SvREFCNT_dec (sv); |
|
|
1124 | |
|
|
1125 | coro_state_transfer (aTHX_ prev, next, 0); |
|
|
1126 | } |
|
|
1127 | |
1128 | |
1128 | MODULE = Coro::State PACKAGE = Coro |
1129 | MODULE = Coro::State PACKAGE = Coro |
1129 | |
1130 | |
1130 | BOOT: |
1131 | BOOT: |
1131 | { |
1132 | { |