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.92 by root, Sun Nov 26 02:16:19 2006 UTC vs.
Revision 1.95 by root, Sun Nov 26 17:35:42 2006 UTC

66#define dSTACKLEVEL int stacklevel 66#define dSTACKLEVEL int stacklevel
67#define STACKLEVEL ((void *)&stacklevel) 67#define STACKLEVEL ((void *)&stacklevel)
68 68
69#define IN_DESTRUCT (PL_main_cv == Nullcv) 69#define IN_DESTRUCT (PL_main_cv == Nullcv)
70 70
71#define labs(l) ((l) >= 0 ? (l) : -(l))
72
73#include "CoroAPI.h" 71#include "CoroAPI.h"
74 72
75#define TRANSFER_SET_STACKLEVEL 0x8bfbfbfb /* magic cookie */ 73#define TRANSFER_SET_STACKLEVEL 0x8bfbfbfb /* magic cookie */
76 74
77#ifdef USE_ITHREADS 75#ifdef USE_ITHREADS
90 88
91/* this is a structure representing a c-level coroutine */ 89/* this is a structure representing a c-level coroutine */
92typedef struct coro_stack { 90typedef struct coro_stack {
93 struct coro_stack *next; 91 struct coro_stack *next;
94 92
95 void *idle_sp; /* original stacklevel when coroutine was created */ 93 /* the stack */
96 void *sptr; 94 void *sptr;
97 long ssize; /* positive == mmap, otherwise malloc */ 95 long ssize; /* positive == mmap, otherwise malloc */
98 96
99 /* cpu state */ 97 /* cpu state */
98 void *idle_sp; /* original stacklevel when coroutine was created */
99 JMPENV *top_env;
100 coro_context cctx; 100 coro_context cctx;
101 JMPENV *top_env;
102} coro_stack; 101} coro_stack;
103
104/* the (fake) coro_stack representing the main program */
105static coro_stack *main_stack;
106 102
107/* this is a structure representing a perl-level coroutine */ 103/* this is a structure representing a perl-level coroutine */
108struct coro { 104struct coro {
109 /* the c coroutine allocated to this perl coroutine, if any */ 105 /* the c coroutine allocated to this perl coroutine, if any */
110 coro_stack *stack; 106 coro_stack *stack;
584{ 580{
585 /* 581 /*
586 * this is a _very_ stripped down perl interpreter ;) 582 * this is a _very_ stripped down perl interpreter ;)
587 */ 583 */
588 dTHX; 584 dTHX;
585 int ret;
586
587 UNLOCK;
588
589 PL_top_env = &PL_start_env; 589 PL_top_env = &PL_start_env;
590
591 UNLOCK;
592 590
593 sv_setiv (get_sv ("Coro::State::cctx_stack", FALSE), PTR2IV ((coro_stack *)arg)); 591 sv_setiv (get_sv ("Coro::State::cctx_stack", FALSE), PTR2IV ((coro_stack *)arg));
594 sv_setiv (get_sv ("Coro::State::cctx_restartop", FALSE), PTR2IV (PL_op)); 592 sv_setiv (get_sv ("Coro::State::cctx_restartop", FALSE), PTR2IV (PL_op));
593
594 /* continue at cctx_init, without entersub */
595 PL_restartop = CvSTART (get_cv ("Coro::State::cctx_init", FALSE)); 595 PL_restartop = CvSTART (get_cv ("Coro::State::cctx_init", FALSE));
596 596
597 /* somebody will hit me for both perl_run and PL_restart_op */ 597 /* somebody will hit me for both perl_run and PL_restartop */
598 perl_run (aTHX_ PERL_GET_CONTEXT); 598 ret = perl_run (aTHX_ PERL_GET_CONTEXT);
599 printf ("ret %d\n", ret);//D
599 600
601 fputs ("FATAL: C coroutine fell over the edge of the world, aborting.\n", stderr);
600 abort (); 602 abort ();
601} 603}
602 604
603static coro_stack * 605static coro_stack *
604stack_new () 606stack_new ()
607 609
608 New (0, stack, 1, coro_stack); 610 New (0, stack, 1, coro_stack);
609 611
610#if HAVE_MMAP 612#if HAVE_MMAP
611 613
612 stack->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE; /* mmap should do allocate-on-write for us */ 614 stack->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE;
615 /* mmap suppsedly does allocate-on-write for us */
613 stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); 616 stack->sptr = mmap (0, stack->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0);
614 617
615 if (stack->sptr == (void *)-1) 618 if (stack->sptr == (void *)-1)
616 { 619 {
617 perror ("FATAL: unable to mmap stack for coroutine"); 620 perror ("FATAL: unable to mmap stack for coroutine");
618 _exit (EXIT_FAILURE); 621 _exit (EXIT_FAILURE);
619 } 622 }
620 623
624# if STACKGUARD
621 mprotect (stack->sptr, STACKGUARD * PAGESIZE, PROT_NONE); 625 mprotect (stack->sptr, STACKGUARD * PAGESIZE, PROT_NONE);
626# endif
622 627
623#else 628#else
624 629
625 stack->ssize = STACKSIZE * (long)sizeof (long); 630 stack->ssize = STACKSIZE * (long)sizeof (long);
626 New (0, stack->sptr, STACKSIZE, long); 631 New (0, stack->sptr, STACKSIZE, long);
639} 644}
640 645
641static void 646static void
642stack_free (coro_stack *stack) 647stack_free (coro_stack *stack)
643{ 648{
644 if (!stack || stack == main_stack) 649 if (!stack)
645 return; 650 return;
646 651
647#if HAVE_MMAP 652#if HAVE_MMAP
648 munmap (stack->sptr, stack->ssize); 653 munmap (stack->sptr, stack->ssize);
649#else 654#else
711 setup_coro (next); 716 setup_coro (next);
712 /* need a stack */ 717 /* need a stack */
713 next->stack = 0; 718 next->stack = 0;
714 } 719 }
715 720
721 if (!prev->stack)
722 /* create a new empty context */
723 Newz (0, prev->stack, 1, coro_stack);
724
716 prev__stack = prev->stack; 725 prev__stack = prev->stack;
717 726
718 /* possibly "free" the stack */ 727 /* possibly "free" the stack */
719 if (prev__stack->idle_sp == STACKLEVEL) 728 if (prev__stack->idle_sp == STACKLEVEL)
720 { 729 {
998 main_mainstack = PL_mainstack; 1007 main_mainstack = PL_mainstack;
999 1008
1000 coroapi.ver = CORO_API_VERSION; 1009 coroapi.ver = CORO_API_VERSION;
1001 coroapi.transfer = api_transfer; 1010 coroapi.transfer = api_transfer;
1002 1011
1003 Newz (0, main_stack, 1, coro_stack);
1004 main_stack->idle_sp = (void *)-1;
1005
1006 assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); 1012 assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL));
1007} 1013}
1008 1014
1009SV * 1015SV *
1010new (char *klass, ...) 1016new (char *klass, ...)
1022 RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1)); 1028 RETVAL = sv_bless (newRV_noinc ((SV *)hv), gv_stashpv (klass, 1));
1023 1029
1024 for (i = 1; i < items; i++) 1030 for (i = 1; i < items; i++)
1025 av_push (coro->args, newSVsv (ST (i))); 1031 av_push (coro->args, newSVsv (ST (i)));
1026 1032
1027 coro->stack = main_stack;
1028 /*coro->mainstack = 0; *//*actual work is done inside transfer */ 1033 /*coro->mainstack = 0; *//*actual work is done inside transfer */
1029 /*coro->stack = 0;*/ 1034 /*coro->stack = 0;*/
1030} 1035}
1031 OUTPUT: 1036 OUTPUT:
1032 RETVAL 1037 RETVAL
1033 1038
1034void 1039void
1035transfer (...) 1040_set_stacklevel (...)
1036 ALIAS: 1041 ALIAS:
1037 Coro::schedule = 1 1042 Coro::State::transfer = 1
1038 Coro::cede = 2 1043 Coro::schedule = 2
1039 _set_stacklevel = 3 1044 Coro::cede = 3
1045 Coro::Cont::yield = 4
1040 CODE: 1046 CODE:
1041{ 1047{
1042 struct transfer_args ta; 1048 struct transfer_args ta;
1043 1049
1044 switch (ix) 1050 switch (ix)
1045 { 1051 {
1046 case 0: 1052 case 0:
1047 if (items != 3)
1048 croak ("Coro::State::transfer(prev,next,flags) expects three arguments, not %d", items);
1049
1050 prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2)));
1051 break;
1052
1053 case 1:
1054 prepare_schedule (&ta);
1055 break;
1056
1057 case 2:
1058 prepare_cede (&ta);
1059 break;
1060
1061 case 3:
1062 ta.prev = (struct coro *)INT2PTR (coro_stack *, SvIV (ST (0))); 1053 ta.prev = (struct coro *)INT2PTR (coro_stack *, SvIV (ST (0)));
1063 ta.next = 0; 1054 ta.next = 0;
1064 ta.flags = TRANSFER_SET_STACKLEVEL; 1055 ta.flags = TRANSFER_SET_STACKLEVEL;
1065 break; 1056 break;
1057
1058 case 1:
1059 if (items != 3)
1060 croak ("Coro::State::transfer(prev,next,flags) expects three arguments, not %d", items);
1061
1062 prepare_transfer (&ta, ST (0), ST (1), SvIV (ST (2)));
1063 break;
1064
1065 case 2:
1066 prepare_schedule (&ta);
1067 break;
1068
1069 case 3:
1070 prepare_cede (&ta);
1071 break;
1072
1073 case 4:
1074 {
1075 SV *yieldstack;
1076 SV *sv;
1077 AV *defav = GvAV (PL_defgv);
1078
1079 yieldstack = *hv_fetch (
1080 (HV *)SvRV (GvSV (coro_current)),
1081 "yieldstack", sizeof ("yieldstack") - 1,
1082 0
1083 );
1084
1085 /* set up @_ -- ugly */
1086 av_clear (defav);
1087 av_fill (defav, items - 1);
1088 while (items--)
1089 av_store (defav, items, SvREFCNT_inc (ST(items)));
1090
1091 sv = av_pop ((AV *)SvRV (yieldstack));
1092 ta.prev = SvSTATE (*av_fetch ((AV *)SvRV (sv), 0, 0));
1093 ta.next = SvSTATE (*av_fetch ((AV *)SvRV (sv), 1, 0));
1094 ta.flags = 0;
1095 SvREFCNT_dec (sv);
1096 }
1097 break;
1098
1066 } 1099 }
1067 1100
1068 TRANSFER (ta); 1101 TRANSFER (ta);
1069} 1102}
1070 1103
1090_exit (code) 1123_exit (code)
1091 int code 1124 int code
1092 PROTOTYPE: $ 1125 PROTOTYPE: $
1093 CODE: 1126 CODE:
1094 _exit (code); 1127 _exit (code);
1095
1096MODULE = Coro::State PACKAGE = Coro::Cont
1097
1098void
1099yield (...)
1100 PROTOTYPE: @
1101 CODE:
1102{
1103 SV *yieldstack;
1104 SV *sv;
1105 AV *defav = GvAV (PL_defgv);
1106 struct coro *prev, *next;
1107
1108 yieldstack = *hv_fetch (
1109 (HV *)SvRV (GvSV (coro_current)),
1110 "yieldstack", sizeof ("yieldstack") - 1,
1111 0
1112 );
1113
1114 /* set up @_ -- ugly */
1115 av_clear (defav);
1116 av_fill (defav, items - 1);
1117 while (items--)
1118 av_store (defav, items, SvREFCNT_inc (ST(items)));
1119
1120 sv = av_pop ((AV *)SvRV (yieldstack));
1121 prev = SvSTATE (*av_fetch ((AV *)SvRV (sv), 0, 0));
1122 next = SvSTATE (*av_fetch ((AV *)SvRV (sv), 1, 0));
1123 SvREFCNT_dec (sv);
1124
1125 coro_state_transfer (aTHX_ prev, next, 0);
1126}
1127 1128
1128MODULE = Coro::State PACKAGE = Coro 1129MODULE = Coro::State PACKAGE = Coro
1129 1130
1130BOOT: 1131BOOT:
1131{ 1132{

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines