|
|
1 | #define PERL_NO_GET_CONTEXT |
|
|
2 | |
1 | #include "EXTERN.h" |
3 | #include "EXTERN.h" |
2 | #include "perl.h" |
4 | #include "perl.h" |
3 | #include "XSUB.h" |
5 | #include "XSUB.h" |
4 | |
6 | |
5 | #include "patchlevel.h" |
7 | #include "patchlevel.h" |
… | |
… | |
63 | # define LOCK 0 |
65 | # define LOCK 0 |
64 | # define UNLOCK 0 |
66 | # define UNLOCK 0 |
65 | #endif |
67 | #endif |
66 | |
68 | |
67 | static struct CoroAPI coroapi; |
69 | static struct CoroAPI coroapi; |
|
|
70 | static AV *main_mainstack; /* used to differentiate between $main and others */ |
|
|
71 | static HV *coro_state_stash; |
|
|
72 | static SV *ucoro_state_sv; |
|
|
73 | static U32 ucoro_state_hash; |
|
|
74 | static __thread SV *coro_mortal; /* will be freed after next transfer */ |
68 | |
75 | |
69 | /* this is actually not only the c stack but also c registers etc... */ |
76 | /* this is actually not only the c stack but also c registers etc... */ |
70 | typedef struct { |
77 | typedef struct { |
71 | int refcnt; /* pointer reference counter */ |
78 | int refcnt; /* pointer reference counter */ |
72 | int usecnt; /* shared by how many coroutines */ |
79 | int usecnt; /* shared by how many coroutines */ |
… | |
… | |
130 | }; |
137 | }; |
131 | |
138 | |
132 | typedef struct coro *Coro__State; |
139 | typedef struct coro *Coro__State; |
133 | typedef struct coro *Coro__State_or_hashref; |
140 | typedef struct coro *Coro__State_or_hashref; |
134 | |
141 | |
135 | static AV *main_mainstack; /* used to differentiate between $main and others */ |
|
|
136 | static HV *coro_state_stash; |
|
|
137 | static SV *ucoro_state_sv; |
|
|
138 | static U32 ucoro_state_hash; |
|
|
139 | static SV *coro_mortal; /* will be freed after next transfer */ |
|
|
140 | |
|
|
141 | /* mostly copied from op.c:cv_clone2 */ |
142 | /* mostly copied from op.c:cv_clone2 */ |
142 | STATIC AV * |
143 | STATIC AV * |
143 | clone_padlist (AV *protopadlist) |
144 | clone_padlist (pTHX_ AV *protopadlist) |
144 | { |
145 | { |
145 | AV *av; |
146 | AV *av; |
146 | I32 ix; |
147 | I32 ix; |
147 | AV *protopad_name = (AV *) * av_fetch (protopadlist, 0, FALSE); |
148 | AV *protopad_name = (AV *) * av_fetch (protopadlist, 0, FALSE); |
148 | AV *protopad = (AV *) * av_fetch (protopadlist, 1, FALSE); |
149 | AV *protopad = (AV *) * av_fetch (protopadlist, 1, FALSE); |
… | |
… | |
237 | |
238 | |
238 | return newpadlist; |
239 | return newpadlist; |
239 | } |
240 | } |
240 | |
241 | |
241 | STATIC void |
242 | STATIC void |
242 | free_padlist (AV *padlist) |
243 | free_padlist (pTHX_ AV *padlist) |
243 | { |
244 | { |
244 | /* may be during global destruction */ |
245 | /* may be during global destruction */ |
245 | if (SvREFCNT (padlist)) |
246 | if (SvREFCNT (padlist)) |
246 | { |
247 | { |
247 | I32 i = AvFILLp (padlist); |
248 | I32 i = AvFILLp (padlist); |
… | |
… | |
268 | AV *padlist; |
269 | AV *padlist; |
269 | AV *av = (AV *)mg->mg_obj; |
270 | AV *av = (AV *)mg->mg_obj; |
270 | |
271 | |
271 | /* casting is fun. */ |
272 | /* casting is fun. */ |
272 | while (&PL_sv_undef != (SV *)(padlist = (AV *)av_pop (av))) |
273 | while (&PL_sv_undef != (SV *)(padlist = (AV *)av_pop (av))) |
273 | free_padlist (padlist); |
274 | free_padlist (aTHX_ padlist); |
274 | } |
275 | } |
275 | |
276 | |
276 | #define PERL_MAGIC_coro PERL_MAGIC_ext |
277 | #define PERL_MAGIC_coro PERL_MAGIC_ext |
277 | |
278 | |
278 | static MGVTBL vtbl_coro = {0, 0, 0, 0, coro_cv_free}; |
279 | static MGVTBL vtbl_coro = {0, 0, 0, 0, coro_cv_free}; |
279 | |
280 | |
280 | /* the next two functions merely cache the padlists */ |
281 | /* the next two functions merely cache the padlists */ |
281 | STATIC void |
282 | STATIC void |
282 | get_padlist (CV *cv) |
283 | get_padlist (pTHX_ CV *cv) |
283 | { |
284 | { |
284 | MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro); |
285 | MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro); |
285 | |
286 | |
286 | if (mg && AvFILLp ((AV *)mg->mg_obj) >= 0) |
287 | if (mg && AvFILLp ((AV *)mg->mg_obj) >= 0) |
287 | CvPADLIST (cv) = (AV *)av_pop ((AV *)mg->mg_obj); |
288 | CvPADLIST (cv) = (AV *)av_pop ((AV *)mg->mg_obj); |
288 | else |
289 | else |
289 | CvPADLIST (cv) = clone_padlist (CvPADLIST (cv)); |
290 | CvPADLIST (cv) = clone_padlist (aTHX_ CvPADLIST (cv)); |
290 | } |
291 | } |
291 | |
292 | |
292 | STATIC void |
293 | STATIC void |
293 | put_padlist (CV *cv) |
294 | put_padlist (pTHX_ CV *cv) |
294 | { |
295 | { |
295 | MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro); |
296 | MAGIC *mg = mg_find ((SV *)cv, PERL_MAGIC_coro); |
296 | |
297 | |
297 | if (!mg) |
298 | if (!mg) |
298 | { |
299 | { |
… | |
… | |
360 | { |
361 | { |
361 | AV *padlist = (AV *)POPs; |
362 | AV *padlist = (AV *)POPs; |
362 | |
363 | |
363 | if (padlist) |
364 | if (padlist) |
364 | { |
365 | { |
365 | put_padlist (cv); /* mark this padlist as available */ |
366 | put_padlist (aTHX_ cv); /* mark this padlist as available */ |
366 | CvPADLIST(cv) = padlist; |
367 | CvPADLIST(cv) = padlist; |
367 | } |
368 | } |
368 | |
369 | |
369 | ++CvDEPTH(cv); |
370 | ++CvDEPTH(cv); |
370 | } |
371 | } |
… | |
… | |
410 | } |
411 | } |
411 | |
412 | |
412 | PUSHs ((SV *)CvPADLIST(cv)); |
413 | PUSHs ((SV *)CvPADLIST(cv)); |
413 | PUSHs ((SV *)cv); |
414 | PUSHs ((SV *)cv); |
414 | |
415 | |
415 | get_padlist (cv); /* this is a monster */ |
416 | get_padlist (aTHX_ cv); /* this is a monster */ |
416 | } |
417 | } |
417 | } |
418 | } |
418 | #ifdef CXt_FORMAT |
419 | #ifdef CXt_FORMAT |
419 | else if (CxTYPE(cx) == CXt_FORMAT) |
420 | else if (CxTYPE(cx) == CXt_FORMAT) |
420 | { |
421 | { |
… | |
… | |
625 | setup_coro (void *arg) |
626 | setup_coro (void *arg) |
626 | { |
627 | { |
627 | /* |
628 | /* |
628 | * emulate part of the perl startup here. |
629 | * emulate part of the perl startup here. |
629 | */ |
630 | */ |
|
|
631 | dTHX; |
630 | dSP; |
632 | dSP; |
631 | Coro__State ctx = (Coro__State)arg; |
633 | Coro__State ctx = (Coro__State)arg; |
632 | SV *sub_init = (SV *)get_cv (SUB_INIT, FALSE); |
634 | SV *sub_init = (SV *)get_cv (SUB_INIT, FALSE); |
633 | |
635 | |
634 | coro_init_stacks (aTHX); |
636 | coro_init_stacks (aTHX); |
… | |
… | |
683 | continue_coro (void *arg) |
685 | continue_coro (void *arg) |
684 | { |
686 | { |
685 | /* |
687 | /* |
686 | * this is a _very_ stripped down perl interpreter ;) |
688 | * this is a _very_ stripped down perl interpreter ;) |
687 | */ |
689 | */ |
|
|
690 | dTHX; |
688 | Coro__State ctx = (Coro__State)arg; |
691 | Coro__State ctx = (Coro__State)arg; |
689 | JMPENV coro_start_env; |
692 | JMPENV coro_start_env; |
690 | |
693 | |
691 | PL_top_env = &ctx->start_env; |
694 | PL_top_env = &ctx->start_env; |
692 | |
695 | |
… | |
… | |
825 | api_transfer(pTHX_ SV *prev, SV *next, int flags) |
828 | api_transfer(pTHX_ SV *prev, SV *next, int flags) |
826 | { |
829 | { |
827 | SV_CORO (prev, "Coro::transfer"); |
830 | SV_CORO (prev, "Coro::transfer"); |
828 | SV_CORO (next, "Coro::transfer"); |
831 | SV_CORO (next, "Coro::transfer"); |
829 | |
832 | |
830 | transfer(aTHX_ SvSTATE(prev), SvSTATE(next), flags); |
833 | transfer (aTHX_ SvSTATE (prev), SvSTATE (next), flags); |
831 | } |
834 | } |
832 | |
835 | |
833 | /** Coro ********************************************************************/ |
836 | /** Coro ********************************************************************/ |
834 | |
837 | |
835 | #define PRIO_MAX 3 |
838 | #define PRIO_MAX 3 |
… | |
… | |
843 | static GV *coro_current, *coro_idle; |
846 | static GV *coro_current, *coro_idle; |
844 | static AV *coro_ready[PRIO_MAX-PRIO_MIN+1]; |
847 | static AV *coro_ready[PRIO_MAX-PRIO_MIN+1]; |
845 | static int coro_nready; |
848 | static int coro_nready; |
846 | |
849 | |
847 | static void |
850 | static void |
848 | coro_enq (SV *sv) |
851 | coro_enq (pTHX_ SV *sv) |
849 | { |
852 | { |
850 | if (SvTYPE (sv) == SVt_PVHV) |
853 | if (SvTYPE (sv) == SVt_PVHV) |
851 | { |
854 | { |
852 | SV **xprio = hv_fetch ((HV *)sv, "prio", 4, 0); |
855 | SV **xprio = hv_fetch ((HV *)sv, "prio", 4, 0); |
853 | int prio = xprio ? SvIV (*xprio) : PRIO_NORMAL; |
856 | int prio = xprio ? SvIV (*xprio) : PRIO_NORMAL; |
… | |
… | |
864 | |
867 | |
865 | croak ("Coro::ready tried to enqueue something that is not a coroutine"); |
868 | croak ("Coro::ready tried to enqueue something that is not a coroutine"); |
866 | } |
869 | } |
867 | |
870 | |
868 | static SV * |
871 | static SV * |
869 | coro_deq (int min_prio) |
872 | coro_deq (pTHX_ int min_prio) |
870 | { |
873 | { |
871 | int prio = PRIO_MAX - PRIO_MIN; |
874 | int prio = PRIO_MAX - PRIO_MIN; |
872 | |
875 | |
873 | min_prio -= PRIO_MIN; |
876 | min_prio -= PRIO_MIN; |
874 | if (min_prio < 0) |
877 | if (min_prio < 0) |
… | |
… | |
885 | } |
888 | } |
886 | |
889 | |
887 | static void |
890 | static void |
888 | api_ready (SV *coro) |
891 | api_ready (SV *coro) |
889 | { |
892 | { |
|
|
893 | dTHX; |
|
|
894 | |
890 | if (SvROK (coro)) |
895 | if (SvROK (coro)) |
891 | coro = SvRV (coro); |
896 | coro = SvRV (coro); |
892 | |
897 | |
893 | LOCK; |
898 | LOCK; |
894 | coro_enq (SvREFCNT_inc (coro)); |
899 | coro_enq (aTHX_ SvREFCNT_inc (coro)); |
895 | UNLOCK; |
900 | UNLOCK; |
896 | } |
901 | } |
897 | |
902 | |
898 | static void |
903 | static void |
899 | api_schedule (void) |
904 | api_schedule (void) |
900 | { |
905 | { |
|
|
906 | dTHX; |
|
|
907 | |
901 | SV *prev, *next; |
908 | SV *prev, *next; |
902 | |
909 | |
903 | LOCK; |
910 | LOCK; |
904 | |
911 | |
905 | prev = SvRV (GvSV (coro_current)); |
912 | prev = SvRV (GvSV (coro_current)); |
906 | next = coro_deq (PRIO_MIN); |
913 | next = coro_deq (aTHX_ PRIO_MIN); |
907 | |
914 | |
908 | if (!next) |
915 | if (!next) |
909 | next = SvREFCNT_inc (SvRV (GvSV (coro_idle))); |
916 | next = SvREFCNT_inc (SvRV (GvSV (coro_idle))); |
910 | |
917 | |
911 | /* free this only after the transfer */ |
918 | /* free this only after the transfer */ |
… | |
… | |
923 | } |
930 | } |
924 | |
931 | |
925 | static void |
932 | static void |
926 | api_cede (void) |
933 | api_cede (void) |
927 | { |
934 | { |
|
|
935 | dTHX; |
|
|
936 | |
928 | LOCK; |
937 | LOCK; |
929 | coro_enq (SvREFCNT_inc (SvRV (GvSV (coro_current)))); |
938 | coro_enq (aTHX_ SvREFCNT_inc (SvRV (GvSV (coro_current)))); |
930 | UNLOCK; |
939 | UNLOCK; |
931 | |
940 | |
932 | api_schedule (); |
941 | api_schedule (); |
933 | } |
942 | } |
934 | |
943 | |