ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/State.xs
(Generate patch)

Comparing Coro/Coro/State.xs (file contents):
Revision 1.110 by root, Tue Nov 28 23:08:07 2006 UTC vs.
Revision 1.112 by root, Thu Nov 30 20:52:52 2006 UTC

119 /* cpu state */ 119 /* cpu state */
120 void *idle_sp; /* sp of top-level transfer/schedule/cede call */ 120 void *idle_sp; /* sp of top-level transfer/schedule/cede call */
121 JMPENV *top_env; 121 JMPENV *top_env;
122 coro_context cctx; 122 coro_context cctx;
123 123
124 int inuse;
125
124#if USE_VALGRIND 126#if USE_VALGRIND
125 int valgrind_id; 127 int valgrind_id;
126#endif 128#endif
127} coro_cctx; 129} coro_cctx;
130
131enum {
132 CF_RUNNING, /* coroutine is running */
133 CF_READY, /* coroutine is ready */
134};
128 135
129/* this is a structure representing a perl-level coroutine */ 136/* this is a structure representing a perl-level coroutine */
130struct coro { 137struct coro {
131 /* the c coroutine allocated to this perl coroutine, if any */ 138 /* the c coroutine allocated to this perl coroutine, if any */
132 coro_cctx *cctx; 139 coro_cctx *cctx;
133 140
134 /* data associated with this coroutine (initial args) */ 141 /* data associated with this coroutine (initial args) */
135 AV *args; 142 AV *args;
136 int refcnt; 143 int refcnt;
144 int flags;
137 145
138 /* optionally saved, might be zero */ 146 /* optionally saved, might be zero */
139 AV *defav; 147 AV *defav;
140 SV *defsv; 148 SV *defsv;
141 SV *errsv; 149 SV *errsv;
665 if (flags == TRANSFER_SET_STACKLEVEL) 673 if (flags == TRANSFER_SET_STACKLEVEL)
666 ((coro_cctx *)prev)->idle_sp = STACKLEVEL; 674 ((coro_cctx *)prev)->idle_sp = STACKLEVEL;
667 else if (prev != next) 675 else if (prev != next)
668 { 676 {
669 coro_cctx *prev__cctx; 677 coro_cctx *prev__cctx;
678
679 if (!prev->cctx)
680 {
681 /* create a new empty context */
682 Newz (0, prev->cctx, 1, coro_cctx);
683 prev->cctx->inuse = 1;
684 prev->flags |= CF_RUNNING;
685 }
686
687 if (!prev->flags & CF_RUNNING)
688 croak ("Coro::State::transfer called with non-running prev Coro::State, but can only transfer from running states");
689
690 if (next->flags & CF_RUNNING)
691 croak ("Coro::State::transfer called with running next Coro::State, but can only transfer to inactive states");
692
693 prev->flags &= ~CF_RUNNING;
694 next->flags |= CF_RUNNING;
670 695
671 LOCK; 696 LOCK;
672 697
673 if (next->mainstack) 698 if (next->mainstack)
674 { 699 {
681 /* need to start coroutine */ 706 /* need to start coroutine */
682 /* first get rid of the old state */ 707 /* first get rid of the old state */
683 SAVE (prev, -1); 708 SAVE (prev, -1);
684 /* setup coroutine call */ 709 /* setup coroutine call */
685 setup_coro (next); 710 setup_coro (next);
686 /* need a stack */ 711 /* need a new stack */
687 next->cctx = 0; 712 assert (!next->stack);
688 } 713 }
689
690 if (!prev->cctx)
691 /* create a new empty context */
692 Newz (0, prev->cctx, 1, coro_cctx);
693 714
694 prev__cctx = prev->cctx; 715 prev__cctx = prev->cctx;
695 716
696 /* possibly "free" the cctx */ 717 /* possibly "free" the cctx */
697 if (prev__cctx->idle_sp == STACKLEVEL) 718 if (prev__cctx->idle_sp == STACKLEVEL)
698 { 719 {
699 assert (PL_top_env == prev__cctx->top_env);//D 720 assert (PL_top_env == prev__cctx->top_env);
721
700 cctx_put (prev__cctx); 722 cctx_put (prev__cctx);
701 prev->cctx = 0; 723 prev->cctx = 0;
702 } 724 }
703 725
704 if (!next->cctx) 726 if (!next->cctx)
705 next->cctx = cctx_get (); 727 next->cctx = cctx_get ();
706 728
707 if (prev__cctx != next->cctx) 729 if (prev__cctx != next->cctx)
708 { 730 {
731 assert ( prev__cctx->inuse);
732 assert (!next->cctx->inuse);
733
734 prev__cctx->inuse = 0;
735 next->cctx->inuse = 1;
736
709 prev__cctx->top_env = PL_top_env; 737 prev__cctx->top_env = PL_top_env;
710 PL_top_env = next->cctx->top_env; 738 PL_top_env = next->cctx->top_env;
711 coro_transfer (&prev__cctx->cctx, &next->cctx->cctx); 739 coro_transfer (&prev__cctx->cctx, &next->cctx->cctx);
712 } 740 }
713 741
728static void 756static void
729coro_state_destroy (struct coro *coro) 757coro_state_destroy (struct coro *coro)
730{ 758{
731 if (coro->refcnt--) 759 if (coro->refcnt--)
732 return; 760 return;
761
762 if (coro->flags & CF_RUNNING)
763 croak ("FATAL: tried to destroy currently running coroutine");
733 764
734 if (coro->mainstack && coro->mainstack != main_mainstack) 765 if (coro->mainstack && coro->mainstack != main_mainstack)
735 { 766 {
736 struct coro temp; 767 struct coro temp;
737 768
835static GV *coro_current, *coro_idle; 866static GV *coro_current, *coro_idle;
836static AV *coro_ready [PRIO_MAX-PRIO_MIN+1]; 867static AV *coro_ready [PRIO_MAX-PRIO_MIN+1];
837static int coro_nready; 868static int coro_nready;
838 869
839static void 870static void
840coro_enq (SV *sv) 871coro_enq (SV *coro_sv)
841{ 872{
842 int prio;
843
844 if (SvTYPE (sv) != SVt_PVHV)
845 croak ("Coro::ready tried to enqueue something that is not a coroutine");
846
847 prio = SvSTATE (sv)->prio;
848
849 av_push (coro_ready [prio - PRIO_MIN], sv); 873 av_push (coro_ready [SvSTATE (coro_sv)->prio - PRIO_MIN], coro_sv);
850 coro_nready++; 874 coro_nready++;
851} 875}
852 876
853static SV * 877static SV *
854coro_deq (int min_prio) 878coro_deq (int min_prio)
867 } 891 }
868 892
869 return 0; 893 return 0;
870} 894}
871 895
872static void 896static int
873api_ready (SV *coro) 897api_ready (SV *coro_sv)
874{ 898{
875 dTHX; 899 struct coro *coro;
876 900
877 if (SvROK (coro)) 901 if (SvROK (coro_sv))
878 coro = SvRV (coro); 902 coro_sv = SvRV (coro_sv);
903
904 coro = SvSTATE (coro_sv);
905
906 if (coro->flags & CF_READY)
907 return 0;
908
909 if (coro->flags & CF_RUNNING)
910 croak ("Coro::ready called on currently running coroutine");
911
912 coro->flags |= CF_READY;
879 913
880 LOCK; 914 LOCK;
881 coro_enq (SvREFCNT_inc (coro)); 915 coro_enq (SvREFCNT_inc (coro_sv));
882 UNLOCK; 916 UNLOCK;
917
918 return 1;
919}
920
921static int
922api_is_ready (SV *coro_sv)
923{
924 return !!SvSTATE (coro_sv)->flags & CF_READY;
883} 925}
884 926
885static void 927static void
886prepare_schedule (struct transfer_args *ta) 928prepare_schedule (struct transfer_args *ta)
887{ 929{
923 coro_mortal = prev; 965 coro_mortal = prev;
924 966
925 ta->prev = SvSTATE (prev); 967 ta->prev = SvSTATE (prev);
926 ta->next = SvSTATE (next); 968 ta->next = SvSTATE (next);
927 ta->flags = TRANSFER_SAVE_ALL; 969 ta->flags = TRANSFER_SAVE_ALL;
970
971 ta->next->flags &= ~CF_READY;
928} 972}
929 973
930static void 974static void
931prepare_cede (struct transfer_args *ta) 975prepare_cede (struct transfer_args *ta)
932{ 976{
933 LOCK; 977 api_ready (GvSV (coro_current));
934 coro_enq (SvREFCNT_inc (SvRV (GvSV (coro_current))));
935 UNLOCK;
936 978
937 prepare_schedule (ta); 979 prepare_schedule (ta);
938} 980}
939 981
940static void 982static void
1126 SV *sv = perl_get_sv("Coro::API", 1); 1168 SV *sv = perl_get_sv("Coro::API", 1);
1127 1169
1128 coroapi.schedule = api_schedule; 1170 coroapi.schedule = api_schedule;
1129 coroapi.cede = api_cede; 1171 coroapi.cede = api_cede;
1130 coroapi.ready = api_ready; 1172 coroapi.ready = api_ready;
1173 coroapi.is_ready = api_is_ready;
1131 coroapi.nready = &coro_nready; 1174 coroapi.nready = &coro_nready;
1132 coroapi.current = coro_current; 1175 coroapi.current = coro_current;
1133 1176
1134 GCoroAPI = &coroapi; 1177 GCoroAPI = &coroapi;
1135 sv_setiv (sv, (IV)&coroapi); 1178 sv_setiv (sv, (IV)&coroapi);
1155 1198
1156 coro->prio = newprio; 1199 coro->prio = newprio;
1157 } 1200 }
1158} 1201}
1159 1202
1160void 1203SV *
1161ready (SV *self) 1204ready (SV *self)
1162 PROTOTYPE: $ 1205 PROTOTYPE: $
1163 CODE: 1206 CODE:
1164 api_ready (self); 1207 RETVAL = boolSV (api_ready (self));
1208 OUTPUT:
1209 RETVAL
1210
1211SV *
1212is_ready (SV *self)
1213 PROTOTYPE: $
1214 CODE:
1215 RETVAL = boolSV (api_is_ready (self));
1216 OUTPUT:
1217 RETVAL
1165 1218
1166int 1219int
1167nready (...) 1220nready (...)
1168 PROTOTYPE: 1221 PROTOTYPE:
1169 CODE: 1222 CODE:

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines