… | |
… | |
110 | static AV *main_mainstack; /* used to differentiate between $main and others */ |
110 | static AV *main_mainstack; /* used to differentiate between $main and others */ |
111 | static HV *coro_state_stash; |
111 | static HV *coro_state_stash; |
112 | static SV *ucoro_state_sv; |
112 | static SV *ucoro_state_sv; |
113 | static U32 ucoro_state_hash; |
113 | static U32 ucoro_state_hash; |
114 | static HV *padlist_cache; |
114 | static HV *padlist_cache; |
115 | |
|
|
116 | /* for Coro.pm */ |
|
|
117 | static GV *coro_current, *coro_idle; |
|
|
118 | static AV *coro_ready; |
|
|
119 | |
115 | |
120 | /* mostly copied from op.c:cv_clone2 */ |
116 | /* mostly copied from op.c:cv_clone2 */ |
121 | STATIC AV * |
117 | STATIC AV * |
122 | clone_padlist (AV *protopadlist) |
118 | clone_padlist (AV *protopadlist) |
123 | { |
119 | { |
… | |
… | |
772 | return (struct coro *) SvIV((SV*)SvRV(arg)); |
768 | return (struct coro *) SvIV((SV*)SvRV(arg)); |
773 | else |
769 | else |
774 | croak ("%s() -- %s is not (and contains not) a Coro::State object", funcname, varname); |
770 | croak ("%s() -- %s is not (and contains not) a Coro::State object", funcname, varname); |
775 | } |
771 | } |
776 | |
772 | |
|
|
773 | /** Coro ********************************************************************/ |
|
|
774 | |
|
|
775 | #define PRIO_MAX 3 |
|
|
776 | #define PRIO_HIGH 1 |
|
|
777 | #define PRIO_NORMAL 0 |
|
|
778 | #define PRIO_LOW -1 |
|
|
779 | #define PRIO_IDLE -3 |
|
|
780 | #define PRIO_MIN -4 |
|
|
781 | |
|
|
782 | /* for Coro.pm */ |
|
|
783 | static GV *coro_current, *coro_idle; |
|
|
784 | static AV *coro_ready[PRIO_MAX-PRIO_MIN+1]; |
|
|
785 | |
|
|
786 | static void |
|
|
787 | coro_enq (SV *sv) |
|
|
788 | { |
|
|
789 | if (SvROK (sv)) |
|
|
790 | { |
|
|
791 | SV *hv = SvRV (sv); |
|
|
792 | if (SvTYPE (hv) == SVt_PVHV) |
|
|
793 | { |
|
|
794 | SV **xprio = hv_fetch ((HV *)hv, "prio", 4, 0); |
|
|
795 | int prio = xprio ? SvIV (*xprio) : PRIO_NORMAL; |
|
|
796 | |
|
|
797 | prio = prio > PRIO_MAX ? PRIO_MAX |
|
|
798 | : prio < PRIO_MIN ? PRIO_MIN |
|
|
799 | : prio; |
|
|
800 | |
|
|
801 | av_push (coro_ready [prio - PRIO_MIN], sv); |
|
|
802 | |
|
|
803 | return; |
|
|
804 | } |
|
|
805 | } |
|
|
806 | |
|
|
807 | croak ("Coro::ready tried to enqueue something that is not a coroutine"); |
|
|
808 | } |
|
|
809 | |
|
|
810 | static SV * |
|
|
811 | coro_deq (int min_prio) |
|
|
812 | { |
|
|
813 | int prio = PRIO_MAX - PRIO_MIN; |
|
|
814 | |
|
|
815 | min_prio -= PRIO_MIN; |
|
|
816 | if (min_prio < 0) |
|
|
817 | min_prio = 0; |
|
|
818 | |
|
|
819 | for (prio = PRIO_MAX - PRIO_MIN + 1; --prio >= min_prio; ) |
|
|
820 | if (av_len (coro_ready[prio]) >= 0) |
|
|
821 | return av_shift (coro_ready[prio]); |
|
|
822 | |
|
|
823 | return 0; |
|
|
824 | } |
|
|
825 | |
777 | MODULE = Coro::State PACKAGE = Coro::State |
826 | MODULE = Coro::State PACKAGE = Coro::State |
778 | |
827 | |
779 | PROTOTYPES: ENABLE |
828 | PROTOTYPES: ENABLE |
780 | |
829 | |
781 | BOOT: |
830 | BOOT: |
… | |
… | |
903 | |
952 | |
904 | # this is slightly dirty (should expose a c-level api) |
953 | # this is slightly dirty (should expose a c-level api) |
905 | |
954 | |
906 | BOOT: |
955 | BOOT: |
907 | { |
956 | { |
|
|
957 | int i; |
|
|
958 | HV *stash = gv_stashpv ("Coro", TRUE); |
|
|
959 | |
|
|
960 | newCONSTSUB (stash, "PRIO_MAX", newSViv (PRIO_MAX)); |
|
|
961 | newCONSTSUB (stash, "PRIO_HIGH", newSViv (PRIO_HIGH)); |
|
|
962 | newCONSTSUB (stash, "PRIO_NORMAL", newSViv (PRIO_NORMAL)); |
|
|
963 | newCONSTSUB (stash, "PRIO_LOW", newSViv (PRIO_LOW)); |
|
|
964 | newCONSTSUB (stash, "PRIO_IDLE", newSViv (PRIO_IDLE)); |
|
|
965 | newCONSTSUB (stash, "PRIO_MIN", newSViv (PRIO_MIN)); |
|
|
966 | |
908 | coro_current = gv_fetchpv ("Coro::current", TRUE, SVt_PV); |
967 | coro_current = gv_fetchpv ("Coro::current", TRUE, SVt_PV); |
909 | coro_ready = newAV (); |
|
|
910 | coro_idle = gv_fetchpv ("Coro::idle" , TRUE, SVt_PV); |
968 | coro_idle = gv_fetchpv ("Coro::idle" , TRUE, SVt_PV); |
|
|
969 | |
|
|
970 | for (i = PRIO_MAX - PRIO_MIN + 1; i--; ) |
|
|
971 | coro_ready[i] = newAV (); |
911 | } |
972 | } |
912 | |
973 | |
913 | void |
974 | void |
914 | ready(self) |
975 | ready(self) |
915 | SV * self |
976 | SV * self |
916 | CODE: |
977 | CODE: |
917 | av_push (coro_ready, SvREFCNT_inc (self)); |
978 | coro_enq (SvREFCNT_inc (self)); |
918 | |
979 | |
919 | void |
980 | void |
920 | schedule(...) |
981 | schedule(...) |
921 | ALIAS: |
982 | ALIAS: |
922 | cede = 1 |
983 | cede = 1 |
923 | CODE: |
984 | CODE: |
|
|
985 | SV *prev, *next; |
|
|
986 | |
924 | SV *prev = GvSV (coro_current); |
987 | prev = GvSV (coro_current); |
925 | SV *next = av_shift (coro_ready); |
|
|
926 | |
988 | |
927 | if (next == &PL_sv_undef) |
989 | if (ix) |
|
|
990 | coro_enq (SvREFCNT_inc (prev)); |
|
|
991 | |
|
|
992 | next = coro_deq (PRIO_MIN); |
|
|
993 | |
|
|
994 | if (!next) |
928 | next = SvREFCNT_inc (GvSV (coro_idle)); |
995 | next = SvREFCNT_inc (GvSV (coro_idle)); |
929 | |
|
|
930 | if (ix) |
|
|
931 | av_push (coro_ready, SvREFCNT_inc (prev)); |
|
|
932 | |
996 | |
933 | GvSV (coro_current) = SvREFCNT_inc (next); |
997 | GvSV (coro_current) = SvREFCNT_inc (next); |
934 | transfer (sv_to_coro (prev, "Coro::schedule", "current coroutine"), |
998 | transfer (sv_to_coro (prev, "Coro::schedule", "current coroutine"), |
935 | sv_to_coro (next, "Coro::schedule", "next coroutine"), |
999 | sv_to_coro (next, "Coro::schedule", "next coroutine"), |
936 | TRANSFER_SAVE_ALL | TRANSFER_LAZY_STACK); |
1000 | TRANSFER_SAVE_ALL | TRANSFER_LAZY_STACK); |