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.116 by root, Fri Dec 1 14:01:43 2006 UTC

7#include "patchlevel.h" 7#include "patchlevel.h"
8 8
9#if USE_VALGRIND 9#if USE_VALGRIND
10# include <valgrind/valgrind.h> 10# include <valgrind/valgrind.h>
11#endif 11#endif
12
13/* the maximum number of idle cctx that will be pooled */
14#define MAX_IDLE_CCTX 8
12 15
13#define PERL_VERSION_ATLEAST(a,b,c) \ 16#define PERL_VERSION_ATLEAST(a,b,c) \
14 (PERL_REVISION > (a) \ 17 (PERL_REVISION > (a) \
15 || (PERL_REVISION == (a) \ 18 || (PERL_REVISION == (a) \
16 && (PERL_VERSION > (b) \ 19 && (PERL_VERSION > (b) \
119 /* cpu state */ 122 /* cpu state */
120 void *idle_sp; /* sp of top-level transfer/schedule/cede call */ 123 void *idle_sp; /* sp of top-level transfer/schedule/cede call */
121 JMPENV *top_env; 124 JMPENV *top_env;
122 coro_context cctx; 125 coro_context cctx;
123 126
127 int inuse;
128
124#if USE_VALGRIND 129#if USE_VALGRIND
125 int valgrind_id; 130 int valgrind_id;
126#endif 131#endif
127} coro_cctx; 132} coro_cctx;
133
134enum {
135 CF_RUNNING, /* coroutine is running */
136 CF_READY, /* coroutine is ready */
137};
128 138
129/* this is a structure representing a perl-level coroutine */ 139/* this is a structure representing a perl-level coroutine */
130struct coro { 140struct coro {
131 /* the c coroutine allocated to this perl coroutine, if any */ 141 /* the c coroutine allocated to this perl coroutine, if any */
132 coro_cctx *cctx; 142 coro_cctx *cctx;
133 143
134 /* data associated with this coroutine (initial args) */ 144 /* data associated with this coroutine (initial args) */
135 AV *args; 145 AV *args;
136 int refcnt; 146 int refcnt;
147 int flags;
137 148
138 /* optionally saved, might be zero */ 149 /* optionally saved, might be zero */
139 AV *defav; 150 AV *defav;
140 SV *defsv; 151 SV *defsv;
141 SV *errsv; 152 SV *errsv;
378 * not usually need a lot of stackspace. 389 * not usually need a lot of stackspace.
379 */ 390 */
380static void 391static void
381coro_init_stacks () 392coro_init_stacks ()
382{ 393{
383 PL_curstackinfo = new_stackinfo(96, 1024/sizeof(PERL_CONTEXT) - 1); 394 PL_curstackinfo = new_stackinfo(128, 1024/sizeof(PERL_CONTEXT));
384 PL_curstackinfo->si_type = PERLSI_MAIN; 395 PL_curstackinfo->si_type = PERLSI_MAIN;
385 PL_curstack = PL_curstackinfo->si_stack; 396 PL_curstack = PL_curstackinfo->si_stack;
386 PL_mainstack = PL_curstack; /* remember in case we switch stacks */ 397 PL_mainstack = PL_curstack; /* remember in case we switch stacks */
387 398
388 PL_stack_base = AvARRAY(PL_curstack); 399 PL_stack_base = AvARRAY(PL_curstack);
389 PL_stack_sp = PL_stack_base; 400 PL_stack_sp = PL_stack_base;
390 PL_stack_max = PL_stack_base + AvMAX(PL_curstack); 401 PL_stack_max = PL_stack_base + AvMAX(PL_curstack);
391 402
392 New(50,PL_tmps_stack,96,SV*); 403 New(50,PL_tmps_stack,128,SV*);
393 PL_tmps_floor = -1; 404 PL_tmps_floor = -1;
394 PL_tmps_ix = -1; 405 PL_tmps_ix = -1;
395 PL_tmps_max = 96; 406 PL_tmps_max = 128;
396 407
397 New(54,PL_markstack,16,I32); 408 New(54,PL_markstack,32,I32);
398 PL_markstack_ptr = PL_markstack; 409 PL_markstack_ptr = PL_markstack;
399 PL_markstack_max = PL_markstack + 16; 410 PL_markstack_max = PL_markstack + 32;
400 411
401#ifdef SET_MARK_OFFSET 412#ifdef SET_MARK_OFFSET
402 SET_MARK_OFFSET; 413 SET_MARK_OFFSET;
403#endif 414#endif
404 415
405 New(54,PL_scopestack,16,I32); 416 New(54,PL_scopestack,32,I32);
406 PL_scopestack_ix = 0; 417 PL_scopestack_ix = 0;
407 PL_scopestack_max = 16; 418 PL_scopestack_max = 32;
408 419
409 New(54,PL_savestack,96,ANY); 420 New(54,PL_savestack,64,ANY);
410 PL_savestack_ix = 0; 421 PL_savestack_ix = 0;
411 PL_savestack_max = 96; 422 PL_savestack_max = 64;
412 423
413#if !PERL_VERSION_ATLEAST (5,9,0) 424#if !PERL_VERSION_ATLEAST (5,9,0)
414 New(54,PL_retstack,8,OP*); 425 New(54,PL_retstack,16,OP*);
415 PL_retstack_ix = 0; 426 PL_retstack_ix = 0;
416 PL_retstack_max = 8; 427 PL_retstack_max = 16;
417#endif 428#endif
418} 429}
419 430
420/* 431/*
421 * destroy the stacks, the callchain etc... 432 * destroy the stacks, the callchain etc...
605 616
606 return cctx; 617 return cctx;
607} 618}
608 619
609static void 620static void
610cctx_free (coro_cctx *cctx) 621cctx_destroy (coro_cctx *cctx)
611{ 622{
612 if (!cctx) 623 if (!cctx)
613 return; 624 return;
614 625
615 --cctx_count; 626 --cctx_count;
632{ 643{
633 coro_cctx *cctx; 644 coro_cctx *cctx;
634 645
635 if (cctx_first) 646 if (cctx_first)
636 { 647 {
637 --cctx_idle;
638 cctx = cctx_first; 648 cctx = cctx_first;
639 cctx_first = cctx->next; 649 cctx_first = cctx->next;
650 --cctx_idle;
640 } 651 }
641 else 652 else
642 { 653 {
643 cctx = cctx_new (); 654 cctx = cctx_new ();
644 PL_op = PL_op->op_next; 655 PL_op = PL_op->op_next;
648} 659}
649 660
650static void 661static void
651cctx_put (coro_cctx *cctx) 662cctx_put (coro_cctx *cctx)
652{ 663{
664 /* free another cctx if overlimit */
665 if (cctx_idle >= MAX_IDLE_CCTX)
666 {
667 coro_cctx *first = cctx_first;
668 cctx_first = first->next;
669 --cctx_idle;
670
671 assert (!first->inuse);
672 cctx_destroy (first);
673 }
674
653 ++cctx_idle; 675 ++cctx_idle;
654 cctx->next = cctx_first; 676 cctx->next = cctx_first;
655 cctx_first = cctx; 677 cctx_first = cctx;
656} 678}
657 679
665 if (flags == TRANSFER_SET_STACKLEVEL) 687 if (flags == TRANSFER_SET_STACKLEVEL)
666 ((coro_cctx *)prev)->idle_sp = STACKLEVEL; 688 ((coro_cctx *)prev)->idle_sp = STACKLEVEL;
667 else if (prev != next) 689 else if (prev != next)
668 { 690 {
669 coro_cctx *prev__cctx; 691 coro_cctx *prev__cctx;
692
693 if (!prev->cctx)
694 {
695 /* create a new empty context */
696 Newz (0, prev->cctx, 1, coro_cctx);
697 prev->cctx->inuse = 1;
698 prev->flags |= CF_RUNNING;
699 }
700
701 if (!prev->flags & CF_RUNNING)
702 croak ("Coro::State::transfer called with non-running prev Coro::State, but can only transfer from running states");
703
704 if (next->flags & CF_RUNNING)
705 croak ("Coro::State::transfer called with running next Coro::State, but can only transfer to inactive states");
706
707 prev->flags &= ~CF_RUNNING;
708 next->flags |= CF_RUNNING;
670 709
671 LOCK; 710 LOCK;
672 711
673 if (next->mainstack) 712 if (next->mainstack)
674 { 713 {
681 /* need to start coroutine */ 720 /* need to start coroutine */
682 /* first get rid of the old state */ 721 /* first get rid of the old state */
683 SAVE (prev, -1); 722 SAVE (prev, -1);
684 /* setup coroutine call */ 723 /* setup coroutine call */
685 setup_coro (next); 724 setup_coro (next);
686 /* need a stack */ 725 /* need a new stack */
687 next->cctx = 0; 726 assert (!next->stack);
688 } 727 }
689
690 if (!prev->cctx)
691 /* create a new empty context */
692 Newz (0, prev->cctx, 1, coro_cctx);
693 728
694 prev__cctx = prev->cctx; 729 prev__cctx = prev->cctx;
695 730
696 /* possibly "free" the cctx */ 731 /* possibly "free" the cctx */
697 if (prev__cctx->idle_sp == STACKLEVEL) 732 if (prev__cctx->idle_sp == STACKLEVEL)
698 { 733 {
734 /* I assume that STACKLEVEL is a stronger indicator than PL_top_env changes */
699 assert (PL_top_env == prev__cctx->top_env);//D 735 assert (PL_top_env == prev__cctx->top_env);
736
700 cctx_put (prev__cctx); 737 cctx_put (prev__cctx);
701 prev->cctx = 0; 738 prev->cctx = 0;
702 } 739 }
703 740
704 if (!next->cctx) 741 if (!next->cctx)
705 next->cctx = cctx_get (); 742 next->cctx = cctx_get ();
706 743
707 if (prev__cctx != next->cctx) 744 if (prev__cctx != next->cctx)
708 { 745 {
746 assert ( prev__cctx->inuse);
747 assert (!next->cctx->inuse);
748
749 prev__cctx->inuse = 0;
750 next->cctx->inuse = 1;
751
709 prev__cctx->top_env = PL_top_env; 752 prev__cctx->top_env = PL_top_env;
710 PL_top_env = next->cctx->top_env; 753 PL_top_env = next->cctx->top_env;
711 coro_transfer (&prev__cctx->cctx, &next->cctx->cctx); 754 coro_transfer (&prev__cctx->cctx, &next->cctx->cctx);
712 } 755 }
713 756
729coro_state_destroy (struct coro *coro) 772coro_state_destroy (struct coro *coro)
730{ 773{
731 if (coro->refcnt--) 774 if (coro->refcnt--)
732 return; 775 return;
733 776
777 if (coro->flags & CF_RUNNING)
778 croak ("FATAL: tried to destroy currently running coroutine");
779
734 if (coro->mainstack && coro->mainstack != main_mainstack) 780 if (coro->mainstack && coro->mainstack != main_mainstack)
735 { 781 {
736 struct coro temp; 782 struct coro temp;
737 783
738 SAVE ((&temp), TRANSFER_SAVE_ALL); 784 SAVE ((&temp), TRANSFER_SAVE_ALL);
743 LOAD ((&temp)); /* this will get rid of defsv etc.. */ 789 LOAD ((&temp)); /* this will get rid of defsv etc.. */
744 790
745 coro->mainstack = 0; 791 coro->mainstack = 0;
746 } 792 }
747 793
748 cctx_free (coro->cctx); 794 cctx_destroy (coro->cctx);
749 SvREFCNT_dec (coro->args); 795 SvREFCNT_dec (coro->args);
750 Safefree (coro); 796 Safefree (coro);
751} 797}
752 798
753static int 799static int
835static GV *coro_current, *coro_idle; 881static GV *coro_current, *coro_idle;
836static AV *coro_ready [PRIO_MAX-PRIO_MIN+1]; 882static AV *coro_ready [PRIO_MAX-PRIO_MIN+1];
837static int coro_nready; 883static int coro_nready;
838 884
839static void 885static void
840coro_enq (SV *sv) 886coro_enq (SV *coro_sv)
841{ 887{
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); 888 av_push (coro_ready [SvSTATE (coro_sv)->prio - PRIO_MIN], coro_sv);
850 coro_nready++; 889 coro_nready++;
851} 890}
852 891
853static SV * 892static SV *
854coro_deq (int min_prio) 893coro_deq (int min_prio)
867 } 906 }
868 907
869 return 0; 908 return 0;
870} 909}
871 910
872static void 911static int
873api_ready (SV *coro) 912api_ready (SV *coro_sv)
874{ 913{
875 dTHX; 914 struct coro *coro;
876 915
877 if (SvROK (coro)) 916 if (SvROK (coro_sv))
878 coro = SvRV (coro); 917 coro_sv = SvRV (coro_sv);
918
919 coro = SvSTATE (coro_sv);
920
921 if (coro->flags & CF_READY)
922 return 0;
923
924 if (coro->flags & CF_RUNNING)
925 croak ("Coro::ready called on currently running coroutine");
926
927 coro->flags |= CF_READY;
879 928
880 LOCK; 929 LOCK;
881 coro_enq (SvREFCNT_inc (coro)); 930 coro_enq (SvREFCNT_inc (coro_sv));
882 UNLOCK; 931 UNLOCK;
932
933 return 1;
934}
935
936static int
937api_is_ready (SV *coro_sv)
938{
939 return !!SvSTATE (coro_sv)->flags & CF_READY;
883} 940}
884 941
885static void 942static void
886prepare_schedule (struct transfer_args *ta) 943prepare_schedule (struct transfer_args *ta)
887{ 944{
923 coro_mortal = prev; 980 coro_mortal = prev;
924 981
925 ta->prev = SvSTATE (prev); 982 ta->prev = SvSTATE (prev);
926 ta->next = SvSTATE (next); 983 ta->next = SvSTATE (next);
927 ta->flags = TRANSFER_SAVE_ALL; 984 ta->flags = TRANSFER_SAVE_ALL;
985
986 ta->next->flags &= ~CF_READY;
928} 987}
929 988
930static void 989static void
931prepare_cede (struct transfer_args *ta) 990prepare_cede (struct transfer_args *ta)
932{ 991{
933 LOCK; 992 api_ready (GvSV (coro_current));
934 coro_enq (SvREFCNT_inc (SvRV (GvSV (coro_current))));
935 UNLOCK;
936 993
937 prepare_schedule (ta); 994 prepare_schedule (ta);
938} 995}
939 996
940static void 997static void
1126 SV *sv = perl_get_sv("Coro::API", 1); 1183 SV *sv = perl_get_sv("Coro::API", 1);
1127 1184
1128 coroapi.schedule = api_schedule; 1185 coroapi.schedule = api_schedule;
1129 coroapi.cede = api_cede; 1186 coroapi.cede = api_cede;
1130 coroapi.ready = api_ready; 1187 coroapi.ready = api_ready;
1188 coroapi.is_ready = api_is_ready;
1131 coroapi.nready = &coro_nready; 1189 coroapi.nready = &coro_nready;
1132 coroapi.current = coro_current; 1190 coroapi.current = coro_current;
1133 1191
1134 GCoroAPI = &coroapi; 1192 GCoroAPI = &coroapi;
1135 sv_setiv (sv, (IV)&coroapi); 1193 sv_setiv (sv, (IV)&coroapi);
1155 1213
1156 coro->prio = newprio; 1214 coro->prio = newprio;
1157 } 1215 }
1158} 1216}
1159 1217
1160void 1218SV *
1161ready (SV *self) 1219ready (SV *self)
1162 PROTOTYPE: $ 1220 PROTOTYPE: $
1163 CODE: 1221 CODE:
1164 api_ready (self); 1222 RETVAL = boolSV (api_ready (self));
1223 OUTPUT:
1224 RETVAL
1225
1226SV *
1227is_ready (SV *self)
1228 PROTOTYPE: $
1229 CODE:
1230 RETVAL = boolSV (api_is_ready (self));
1231 OUTPUT:
1232 RETVAL
1165 1233
1166int 1234int
1167nready (...) 1235nready (...)
1168 PROTOTYPE: 1236 PROTOTYPE:
1169 CODE: 1237 CODE:

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines