… | |
… | |
18 | # endif |
18 | # endif |
19 | #endif |
19 | #endif |
20 | |
20 | |
21 | #define MAY_FLUSH /* increases codesize */ |
21 | #define MAY_FLUSH /* increases codesize */ |
22 | |
22 | |
23 | /* perl-related */ |
|
|
24 | #define TRANSFER_SAVE_DEFAV 0x00000001 |
|
|
25 | #define TRANSFER_SAVE_DEFSV 0x00000002 |
|
|
26 | #define TRANSFER_SAVE_ERRSV 0x00000004 |
|
|
27 | /* c-related */ |
|
|
28 | #define TRANSFER_SAVE_CCTXT 0x00000008 |
|
|
29 | #ifdef CORO_LAZY_STACK |
|
|
30 | # define TRANSFER_LAZY_STACK 0x00000010 |
|
|
31 | #else |
|
|
32 | # define TRANSFER_LAZY_STACK 0x00000000 |
|
|
33 | #endif |
|
|
34 | |
|
|
35 | #define TRANSFER_SAVE_ALL (TRANSFER_SAVE_DEFAV|TRANSFER_SAVE_DEFSV \ |
|
|
36 | |TRANSFER_SAVE_ERRSV|TRANSFER_SAVE_CCTXT) |
|
|
37 | |
|
|
38 | #define SUB_INIT "Coro::State::initialize" |
23 | #define SUB_INIT "Coro::State::initialize" |
39 | #define UCORO_STATE "_coro_state" |
24 | #define UCORO_STATE "_coro_state" |
40 | |
25 | |
41 | /* The next macro should delcare a variable stacklevel that contains and approximation |
26 | /* The next macro should delcare a variable stacklevel that contains and approximation |
42 | * to the current C stack pointer. It's property is that it changes with each call |
27 | * to the current C stack pointer. Its property is that it changes with each call |
43 | * and should be unique. */ |
28 | * and should be unique. */ |
44 | #define dSTACKLEVEL void *stacklevel = &stacklevel |
29 | #define dSTACKLEVEL void *stacklevel = &stacklevel |
45 | |
30 | |
46 | #define labs(l) ((l) >= 0 ? (l) : -(l)) |
31 | #define labs(l) ((l) >= 0 ? (l) : -(l)) |
|
|
32 | |
|
|
33 | #include "CoroAPI.h" |
|
|
34 | |
|
|
35 | static struct CoroAPI coroapi; |
47 | |
36 | |
48 | /* this is actually not only the c stack but also c registers etc... */ |
37 | /* this is actually not only the c stack but also c registers etc... */ |
49 | typedef struct { |
38 | typedef struct { |
50 | int refcnt; /* pointer reference counter */ |
39 | int refcnt; /* pointer reference counter */ |
51 | int usecnt; /* shared by how many coroutines */ |
40 | int usecnt; /* shared by how many coroutines */ |
… | |
… | |
751 | } |
740 | } |
752 | |
741 | |
753 | static struct coro * |
742 | static struct coro * |
754 | sv_to_coro (SV *arg, const char *funcname, const char *varname) |
743 | sv_to_coro (SV *arg, const char *funcname, const char *varname) |
755 | { |
744 | { |
756 | if (SvROK(arg) && SvTYPE(SvRV(arg)) == SVt_PVHV) |
745 | if (SvROK(arg) && SvTYPE(SvRV(arg)) == SVt_PVHV) |
757 | { |
746 | { |
758 | HE *he = hv_fetch_ent((HV *)SvRV(arg), ucoro_state_sv, 0, ucoro_state_hash); |
747 | HE *he = hv_fetch_ent((HV *)SvRV(arg), ucoro_state_sv, 0, ucoro_state_hash); |
759 | |
748 | |
760 | if (!he) |
749 | if (!he) |
761 | croak ("%s() -- %s is a hashref but lacks the " UCORO_STATE " key", funcname, varname); |
750 | croak ("%s() -- %s is a hashref but lacks the " UCORO_STATE " key", funcname, varname); |
762 | |
751 | |
763 | arg = HeVAL(he); |
752 | arg = HeVAL(he); |
764 | } |
753 | } |
765 | |
754 | |
766 | /* must also be changed inside Coro::Cont::yield */ |
755 | /* must also be changed inside Coro::Cont::yield */ |
767 | if (SvROK(arg) && SvSTASH(SvRV(arg)) == coro_state_stash) |
756 | if (SvROK(arg) && SvSTASH(SvRV(arg)) == coro_state_stash) |
768 | return (struct coro *) SvIV((SV*)SvRV(arg)); |
757 | return (struct coro *) SvIV((SV*)SvRV(arg)); |
769 | else |
758 | else |
770 | croak ("%s() -- %s is not (and contains not) a Coro::State object", funcname, varname); |
759 | croak ("%s() -- %s is not (and contains not) a Coro::State object", funcname, varname); |
|
|
760 | } |
|
|
761 | |
|
|
762 | static void |
|
|
763 | api_transfer(pTHX_ SV *prev, SV *next, int flags) |
|
|
764 | { |
|
|
765 | transfer(aTHX_ sv_to_coro (prev, "Coro::transfer", "prev"), |
|
|
766 | sv_to_coro (next, "Coro::transfer", "next"), |
|
|
767 | flags); |
771 | } |
768 | } |
772 | |
769 | |
773 | /** Coro ********************************************************************/ |
770 | /** Coro ********************************************************************/ |
774 | |
771 | |
775 | #define PRIO_MAX 3 |
772 | #define PRIO_MAX 3 |
… | |
… | |
821 | return av_shift (coro_ready[prio]); |
818 | return av_shift (coro_ready[prio]); |
822 | |
819 | |
823 | return 0; |
820 | return 0; |
824 | } |
821 | } |
825 | |
822 | |
|
|
823 | static void |
|
|
824 | api_ready (SV *coro) |
|
|
825 | { |
|
|
826 | coro_enq (SvREFCNT_inc (coro)); |
|
|
827 | } |
|
|
828 | |
|
|
829 | static void |
|
|
830 | api_schedule (int cede) |
|
|
831 | { |
|
|
832 | SV *prev, *next; |
|
|
833 | |
|
|
834 | prev = GvSV (coro_current); |
|
|
835 | |
|
|
836 | if (cede) |
|
|
837 | coro_enq (SvREFCNT_inc (prev)); |
|
|
838 | |
|
|
839 | next = coro_deq (PRIO_MIN); |
|
|
840 | |
|
|
841 | if (!next) |
|
|
842 | next = SvREFCNT_inc (GvSV (coro_idle)); |
|
|
843 | |
|
|
844 | GvSV (coro_current) = SvREFCNT_inc (next); |
|
|
845 | transfer (sv_to_coro (prev, "Coro::schedule", "current coroutine"), |
|
|
846 | sv_to_coro (next, "Coro::schedule", "next coroutine"), |
|
|
847 | TRANSFER_SAVE_ALL | TRANSFER_LAZY_STACK); |
|
|
848 | SvREFCNT_dec (next); |
|
|
849 | SvREFCNT_dec (prev); |
|
|
850 | } |
|
|
851 | |
826 | MODULE = Coro::State PACKAGE = Coro::State |
852 | MODULE = Coro::State PACKAGE = Coro::State |
827 | |
853 | |
828 | PROTOTYPES: ENABLE |
854 | PROTOTYPES: ENABLE |
829 | |
855 | |
830 | BOOT: |
856 | BOOT: |
… | |
… | |
840 | |
866 | |
841 | if (!padlist_cache) |
867 | if (!padlist_cache) |
842 | padlist_cache = newHV (); |
868 | padlist_cache = newHV (); |
843 | |
869 | |
844 | main_mainstack = PL_mainstack; |
870 | main_mainstack = PL_mainstack; |
|
|
871 | |
|
|
872 | { |
|
|
873 | SV *sv = perl_get_sv("Coro::API", 1); |
|
|
874 | |
|
|
875 | coroapi.ver = CORO_API_VERSION - 1; |
|
|
876 | coroapi.transfer = api_transfer; |
|
|
877 | coroapi.schedule = api_schedule; |
|
|
878 | coroapi.ready = api_ready; |
|
|
879 | |
|
|
880 | GCoroAPI = &coroapi; |
|
|
881 | sv_setiv(sv, (IV)&coroapi); |
|
|
882 | SvREADONLY_on(sv); |
|
|
883 | } |
845 | } |
884 | } |
846 | |
885 | |
847 | Coro::State |
886 | Coro::State |
848 | _newprocess(args) |
887 | _newprocess(args) |
849 | SV * args |
888 | SV * args |
… | |
… | |
973 | |
1012 | |
974 | void |
1013 | void |
975 | ready(self) |
1014 | ready(self) |
976 | SV * self |
1015 | SV * self |
977 | CODE: |
1016 | CODE: |
978 | coro_enq (SvREFCNT_inc (self)); |
1017 | api_ready (self); |
979 | |
1018 | |
980 | void |
1019 | void |
981 | schedule(...) |
1020 | schedule(...) |
982 | ALIAS: |
1021 | ALIAS: |
983 | cede = 1 |
1022 | cede = 1 |
984 | CODE: |
1023 | CODE: |
985 | SV *prev, *next; |
1024 | api_schedule (ix); |
986 | |
1025 | |
987 | prev = GvSV (coro_current); |
|
|
988 | |
|
|
989 | if (ix) |
|
|
990 | coro_enq (SvREFCNT_inc (prev)); |
|
|
991 | |
|
|
992 | next = coro_deq (PRIO_MIN); |
|
|
993 | |
|
|
994 | if (!next) |
|
|
995 | next = SvREFCNT_inc (GvSV (coro_idle)); |
|
|
996 | |
|
|
997 | GvSV (coro_current) = SvREFCNT_inc (next); |
|
|
998 | transfer (sv_to_coro (prev, "Coro::schedule", "current coroutine"), |
|
|
999 | sv_to_coro (next, "Coro::schedule", "next coroutine"), |
|
|
1000 | TRANSFER_SAVE_ALL | TRANSFER_LAZY_STACK); |
|
|
1001 | SvREFCNT_dec (next); |
|
|
1002 | SvREFCNT_dec (prev); |
|
|
1003 | |
|
|