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.54 by pcg, Sat Mar 13 06:45:04 2004 UTC vs.
Revision 1.55 by pcg, Thu Apr 1 02:29:05 2004 UTC

52#define IN_DESTRUCT (PL_main_cv == Nullcv) 52#define IN_DESTRUCT (PL_main_cv == Nullcv)
53 53
54#define labs(l) ((l) >= 0 ? (l) : -(l)) 54#define labs(l) ((l) >= 0 ? (l) : -(l))
55 55
56#include "CoroAPI.h" 56#include "CoroAPI.h"
57
58#ifdef USE_ITHREADS
59static perl_mutex coro_mutex;
60# define LOCK do { MUTEX_LOCK (&coro_mutex); } while (0)
61# define UNLOCK do { MUTEX_UNLOCK (&coro_mutex); } while (0)
62#else
63# define LOCK 0
64# define UNLOCK 0
65#endif
57 66
58static struct CoroAPI coroapi; 67static struct CoroAPI coroapi;
59 68
60/* this is actually not only the c stack but also c registers etc... */ 69/* this is actually not only the c stack but also c registers etc... */
61typedef struct { 70typedef struct {
125 134
126static AV *main_mainstack; /* used to differentiate between $main and others */ 135static AV *main_mainstack; /* used to differentiate between $main and others */
127static HV *coro_state_stash; 136static HV *coro_state_stash;
128static SV *ucoro_state_sv; 137static SV *ucoro_state_sv;
129static U32 ucoro_state_hash; 138static U32 ucoro_state_hash;
130static HV *padlist_cache;
131static SV *coro_mortal; /* will be freed after next transfer */ 139static SV *coro_mortal; /* will be freed after next transfer */
132 140
133/* mostly copied from op.c:cv_clone2 */ 141/* mostly copied from op.c:cv_clone2 */
134STATIC AV * 142STATIC AV *
135clone_padlist (AV *protopadlist) 143clone_padlist (AV *protopadlist)
164 AvFLAGS (av) = AVf_REIFY; 172 AvFLAGS (av) = AVf_REIFY;
165 173
166 for (ix = fpad; ix > 0; ix--) 174 for (ix = fpad; ix > 0; ix--)
167 { 175 {
168 SV *namesv = (ix <= fname) ? pname[ix] : Nullsv; 176 SV *namesv = (ix <= fname) ? pname[ix] : Nullsv;
177
169 if (namesv && namesv != &PL_sv_undef) 178 if (namesv && namesv != &PL_sv_undef)
170 { 179 {
171 char *name = SvPVX (namesv); /* XXX */ 180 char *name = SvPVX (namesv); /* XXX */
181
172 if (SvFLAGS (namesv) & SVf_FAKE || *name == '&') 182 if (SvFLAGS (namesv) & SVf_FAKE || *name == '&')
173 { /* lexical from outside? */ 183 { /* lexical from outside? */
174 npad[ix] = SvREFCNT_inc (ppad[ix]); 184 npad[ix] = SvREFCNT_inc (ppad[ix]);
175 } 185 }
176 else 186 else
182 sv = (SV *) newAV (); 192 sv = (SV *) newAV ();
183 else if (*name == '%') 193 else if (*name == '%')
184 sv = (SV *) newHV (); 194 sv = (SV *) newHV ();
185 else 195 else
186 sv = NEWSV (0, 0); 196 sv = NEWSV (0, 0);
197
187#ifdef SvPADBUSY 198#ifdef SvPADBUSY
188 if (!SvPADBUSY (sv)) 199 if (!SvPADBUSY (sv))
189#endif 200#endif
190 SvPADMY_on (sv); 201 SvPADMY_on (sv);
202
191 npad[ix] = sv; 203 npad[ix] = sv;
192 } 204 }
193 } 205 }
194 else if (IS_PADGV (ppad[ix]) || IS_PADCONST (ppad[ix])) 206 else if (IS_PADGV (ppad[ix]) || IS_PADCONST (ppad[ix]))
195 { 207 {
350 362
351 if (padlist) 363 if (padlist)
352 { 364 {
353 put_padlist (cv); /* mark this padlist as available */ 365 put_padlist (cv); /* mark this padlist as available */
354 CvPADLIST(cv) = padlist; 366 CvPADLIST(cv) = padlist;
355#ifdef USE_THREADS
356 /*CvOWNER(cv) = (struct perl_thread *)POPs;*/
357#endif
358 } 367 }
359 368
360 ++CvDEPTH(cv); 369 ++CvDEPTH(cv);
361 } 370 }
362 371
389 if (CxTYPE(cx) == CXt_SUB) 398 if (CxTYPE(cx) == CXt_SUB)
390 { 399 {
391 CV *cv = cx->blk_sub.cv; 400 CV *cv = cx->blk_sub.cv;
392 if (CvDEPTH(cv)) 401 if (CvDEPTH(cv))
393 { 402 {
394#ifdef USE_THREADS
395 /*XPUSHs ((SV *)CvOWNER(cv));*/
396 /*CvOWNER(cv) = 0;*/
397 /*error must unlock this cv etc.. etc...*/
398#endif
399 EXTEND (SP, CvDEPTH(cv)*2); 403 EXTEND (SP, CvDEPTH(cv)*2);
400 404
401 while (--CvDEPTH(cv)) 405 while (--CvDEPTH(cv))
402 { 406 {
403 /* this tells the restore code to increment CvDEPTH */ 407 /* this tells the restore code to increment CvDEPTH */
475 * not usually need a lot of stackspace. 479 * not usually need a lot of stackspace.
476 */ 480 */
477STATIC void 481STATIC void
478coro_init_stacks (pTHX) 482coro_init_stacks (pTHX)
479{ 483{
484 LOCK;
485
480 PL_curstackinfo = new_stackinfo(96, 1024/sizeof(PERL_CONTEXT) - 1); 486 PL_curstackinfo = new_stackinfo(96, 1024/sizeof(PERL_CONTEXT) - 1);
481 PL_curstackinfo->si_type = PERLSI_MAIN; 487 PL_curstackinfo->si_type = PERLSI_MAIN;
482 PL_curstack = PL_curstackinfo->si_stack; 488 PL_curstack = PL_curstackinfo->si_stack;
483 PL_mainstack = PL_curstack; /* remember in case we switch stacks */ 489 PL_mainstack = PL_curstack; /* remember in case we switch stacks */
484 490
508 PL_savestack_max = 96; 514 PL_savestack_max = 96;
509 515
510 New(54,PL_retstack,8,OP*); 516 New(54,PL_retstack,8,OP*);
511 PL_retstack_ix = 0; 517 PL_retstack_ix = 0;
512 PL_retstack_max = 8; 518 PL_retstack_max = 8;
519
520 UNLOCK;
513} 521}
514 522
515/* 523/*
516 * destroy the stacks, the callchain etc... 524 * destroy the stacks, the callchain etc...
517 */ 525 */
566 New (0, stack, 1, coro_stack); 574 New (0, stack, 1, coro_stack);
567 575
568 stack->refcnt = 1; 576 stack->refcnt = 1;
569 stack->usecnt = 1; 577 stack->usecnt = 1;
570 stack->gencnt = ctx->gencnt = 0; 578 stack->gencnt = ctx->gencnt = 0;
579
571 if (alloc) 580 if (alloc)
572 { 581 {
573#if HAVE_MMAP 582#if HAVE_MMAP
574 stack->ssize = 16384 * sizeof (long); /* mmap should do allocate-on-write for us */ 583 stack->ssize = 16384 * sizeof (long); /* mmap should do allocate-on-write for us */
575 stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); 584 stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
687 696
688 abort (); 697 abort ();
689} 698}
690 699
691STATIC void 700STATIC void
692transfer(pTHX_ struct coro *prev, struct coro *next, int flags) 701transfer (pTHX_ struct coro *prev, struct coro *next, int flags)
693{ 702{
694 dSTACKLEVEL; 703 dSTACKLEVEL;
695 static struct coro *xnext;
696 704
697 if (prev != next) 705 if (prev != next)
698 { 706 {
699 xnext = next;
700
701 if (next->mainstack) 707 if (next->mainstack)
702 { 708 {
709 LOCK;
703 SAVE (prev, flags); 710 SAVE (prev, flags);
704 LOAD (next); 711 LOAD (next);
712 UNLOCK;
705 713
706 /* mark this state as in-use */ 714 /* mark this state as in-use */
707 next->mainstack = 0; 715 next->mainstack = 0;
708 next->tmps_ix = -2; 716 next->tmps_ix = -2;
709 717
728 continue_coro, (void *)next, 736 continue_coro, (void *)next,
729 next->stack->sptr, labs (next->stack->ssize)); 737 next->stack->sptr, labs (next->stack->ssize));
730 } 738 }
731 739
732 coro_transfer (&(prev->stack->cctx), &(next->stack->cctx)); 740 coro_transfer (&(prev->stack->cctx), &(next->stack->cctx));
741 prev->cursp = stacklevel;
733 /* don't add any code here */ 742 /* don't add any code here */
734 } 743 }
735 744 else
745 next->cursp = stacklevel;
736 } 746 }
737 else if (next->tmps_ix == -2) 747 else if (next->tmps_ix == -2)
738 croak ("tried to transfer to running coroutine"); 748 croak ("tried to transfer to running coroutine");
739 else 749 else
740 { 750 {
751 LOCK;
741 SAVE (prev, -1); /* first get rid of the old state */ 752 SAVE (prev, -1); /* first get rid of the old state */
753 UNLOCK;
742 754
743 if (flags & TRANSFER_SAVE_CCTXT) 755 if (flags & TRANSFER_SAVE_CCTXT)
744 { 756 {
745 if (!prev->stack) 757 if (!prev->stack)
746 allocate_stack (prev, 0); 758 allocate_stack (prev, 0);
748 if (prev->stack->sptr && flags & TRANSFER_LAZY_STACK) 760 if (prev->stack->sptr && flags & TRANSFER_LAZY_STACK)
749 { 761 {
750 PL_top_env = &next->start_env; 762 PL_top_env = &next->start_env;
751 763
752 setup_coro (next); 764 setup_coro (next);
765 next->cursp = stacklevel;
753 766
754 prev->stack->refcnt++; 767 prev->stack->refcnt++;
755 prev->stack->usecnt++; 768 prev->stack->usecnt++;
756 next->stack = prev->stack; 769 next->stack = prev->stack;
757 next->gencnt = prev->gencnt; 770 next->gencnt = prev->gencnt;
762 allocate_stack (next, 1); 775 allocate_stack (next, 1);
763 coro_create (&(next->stack->cctx), 776 coro_create (&(next->stack->cctx),
764 setup_coro, (void *)next, 777 setup_coro, (void *)next,
765 next->stack->sptr, labs (next->stack->ssize)); 778 next->stack->sptr, labs (next->stack->ssize));
766 coro_transfer (&(prev->stack->cctx), &(next->stack->cctx)); 779 coro_transfer (&(prev->stack->cctx), &(next->stack->cctx));
780 prev->cursp = stacklevel;
767 /* don't add any code here */ 781 /* don't add any code here */
768 } 782 }
769 } 783 }
770 else 784 else
785 {
771 setup_coro (next); 786 setup_coro (next);
787 next->cursp = stacklevel;
788 }
772 } 789 }
773
774 /*
775 * xnext is now either prev or next, depending on wether
776 * we switched the c stack or not. that's why I use a global
777 * variable, that should become thread-specific at one point.
778 */
779 xnext->cursp = stacklevel;
780 } 790 }
781 791
792 LOCK;
782 if (coro_mortal) 793 if (coro_mortal)
783 { 794 {
784 SvREFCNT_dec (coro_mortal); 795 SvREFCNT_dec (coro_mortal);
785 coro_mortal = 0; 796 coro_mortal = 0;
786 } 797 }
798 UNLOCK;
787} 799}
788 800
789#define SV_CORO(sv,func) \ 801#define SV_CORO(sv,func) \
790 do { \ 802 do { \
791 if (SvROK (sv)) \ 803 if (SvROK (sv)) \
792 sv = SvRV (sv); \ 804 sv = SvRV (sv); \
793 \ 805 \
794 if (SvTYPE(sv) == SVt_PVHV) \ 806 if (SvTYPE (sv) == SVt_PVHV) \
795 { \ 807 { \
796 HE *he = hv_fetch_ent((HV *)sv, ucoro_state_sv, 0, ucoro_state_hash); \ 808 HE *he = hv_fetch_ent ((HV *)sv, ucoro_state_sv, 0, ucoro_state_hash); \
797 \ 809 \
798 if (!he) \ 810 if (!he) \
799 croak ("%s() -- %s is a hashref but lacks the " UCORO_STATE " key", func, # sv); \ 811 croak ("%s() -- %s is a hashref but lacks the " UCORO_STATE " key", func, # sv); \
800 \ 812 \
801 (sv) = SvRV (HeVAL(he)); \ 813 (sv) = SvRV (HeVAL(he)); \
802 } \ 814 } \
803 \ 815 \
804 /* must also be changed inside Coro::Cont::yield */ \ 816 /* must also be changed inside Coro::Cont::yield */ \
805 if (!SvOBJECT(sv) || SvSTASH(sv) != coro_state_stash) \ 817 if (!SvOBJECT (sv) || SvSTASH (sv) != coro_state_stash) \
806 croak ("%s() -- %s is not (and contains not) a Coro::State object", func, # sv); \ 818 croak ("%s() -- %s is not (and contains not) a Coro::State object", func, # sv); \
807 \ 819 \
808 } while(0) 820 } while(0)
809 821
810#define SvSTATE(sv) (struct coro *)SvIV (sv) 822#define SvSTATE(sv) (struct coro *)SvIV (sv)
876api_ready (SV *coro) 888api_ready (SV *coro)
877{ 889{
878 if (SvROK (coro)) 890 if (SvROK (coro))
879 coro = SvRV (coro); 891 coro = SvRV (coro);
880 892
893 LOCK;
881 coro_enq (SvREFCNT_inc (coro)); 894 coro_enq (SvREFCNT_inc (coro));
895 UNLOCK;
882} 896}
883 897
884static void 898static void
885api_schedule (void) 899api_schedule (void)
886{ 900{
887 SV *prev, *next; 901 SV *prev, *next;
902
903 LOCK;
888 904
889 prev = SvRV (GvSV (coro_current)); 905 prev = SvRV (GvSV (coro_current));
890 next = coro_deq (PRIO_MIN); 906 next = coro_deq (PRIO_MIN);
891 907
892 if (!next) 908 if (!next)
898 914
899 SvRV (GvSV (coro_current)) = next; 915 SvRV (GvSV (coro_current)) = next;
900 916
901 SV_CORO (next, "Coro::schedule"); 917 SV_CORO (next, "Coro::schedule");
902 918
919 UNLOCK;
920
903 transfer (aTHX_ SvSTATE (prev), SvSTATE (next), 921 transfer (aTHX_ SvSTATE (prev), SvSTATE (next),
904 TRANSFER_SAVE_ALL | TRANSFER_LAZY_STACK); 922 TRANSFER_SAVE_ALL | TRANSFER_LAZY_STACK);
905} 923}
906 924
907static void 925static void
908api_cede (void) 926api_cede (void)
909{ 927{
928 LOCK;
910 coro_enq (SvREFCNT_inc (SvRV (GvSV (coro_current)))); 929 coro_enq (SvREFCNT_inc (SvRV (GvSV (coro_current))));
930 UNLOCK;
911 931
912 api_schedule (); 932 api_schedule ();
913} 933}
914 934
915MODULE = Coro::State PACKAGE = Coro::State 935MODULE = Coro::State PACKAGE = Coro::State
916 936
917PROTOTYPES: ENABLE 937PROTOTYPES: ENABLE
918 938
919BOOT: 939BOOT:
920{ /* {} necessary for stoopid perl-5.6.x */ 940{ /* {} necessary for stoopid perl-5.6.x */
941#ifdef USE_ITHREADS
942 MUTEX_INIT (&coro_mutex);
943#endif
944
921 ucoro_state_sv = newSVpv (UCORO_STATE, sizeof(UCORO_STATE) - 1); 945 ucoro_state_sv = newSVpv (UCORO_STATE, sizeof(UCORO_STATE) - 1);
922 PERL_HASH(ucoro_state_hash, UCORO_STATE, sizeof(UCORO_STATE) - 1); 946 PERL_HASH(ucoro_state_hash, UCORO_STATE, sizeof(UCORO_STATE) - 1);
923 coro_state_stash = gv_stashpv ("Coro::State", TRUE); 947 coro_state_stash = gv_stashpv ("Coro::State", TRUE);
924 948
925 newCONSTSUB (coro_state_stash, "SAVE_DEFAV", newSViv (TRANSFER_SAVE_DEFAV)); 949 newCONSTSUB (coro_state_stash, "SAVE_DEFAV", newSViv (TRANSFER_SAVE_DEFAV));
926 newCONSTSUB (coro_state_stash, "SAVE_DEFSV", newSViv (TRANSFER_SAVE_DEFSV)); 950 newCONSTSUB (coro_state_stash, "SAVE_DEFSV", newSViv (TRANSFER_SAVE_DEFSV));
927 newCONSTSUB (coro_state_stash, "SAVE_ERRSV", newSViv (TRANSFER_SAVE_ERRSV)); 951 newCONSTSUB (coro_state_stash, "SAVE_ERRSV", newSViv (TRANSFER_SAVE_ERRSV));
928 newCONSTSUB (coro_state_stash, "SAVE_CCTXT", newSViv (TRANSFER_SAVE_CCTXT)); 952 newCONSTSUB (coro_state_stash, "SAVE_CCTXT", newSViv (TRANSFER_SAVE_CCTXT));
929
930 if (!padlist_cache)
931 padlist_cache = newHV ();
932 953
933 main_mainstack = PL_mainstack; 954 main_mainstack = PL_mainstack;
934 955
935 coroapi.ver = CORO_API_VERSION; 956 coroapi.ver = CORO_API_VERSION;
936 coroapi.transfer = api_transfer; 957 coroapi.transfer = api_transfer;

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines