… | |
… | |
31 | #else |
31 | #else |
32 | # define PAGESIZE 0 |
32 | # define PAGESIZE 0 |
33 | # define BOOT_PAGESIZE (void)0 |
33 | # define BOOT_PAGESIZE (void)0 |
34 | #endif |
34 | #endif |
35 | |
35 | |
36 | #if USE_VALGRIND |
36 | #if CORO_USE_VALGRIND |
37 | # include <valgrind/valgrind.h> |
37 | # include <valgrind/valgrind.h> |
38 | # define REGISTER_STACK(cctx,start,end) (cctx)->valgrind_id = VALGRIND_STACK_REGISTER ((start), (end)) |
38 | # define REGISTER_STACK(cctx,start,end) (cctx)->valgrind_id = VALGRIND_STACK_REGISTER ((start), (end)) |
39 | #else |
39 | #else |
40 | # define REGISTER_STACK(cctx,start,end) |
40 | # define REGISTER_STACK(cctx,start,end) |
41 | #endif |
41 | #endif |
… | |
… | |
74 | #ifndef SvRV_set |
74 | #ifndef SvRV_set |
75 | # define SvRV_set(s,v) SvRV(s) = (v) |
75 | # define SvRV_set(s,v) SvRV(s) = (v) |
76 | #endif |
76 | #endif |
77 | |
77 | |
78 | #if !__i386 && !__x86_64 && !__powerpc && !__m68k && !__alpha && !__mips && !__sparc64 |
78 | #if !__i386 && !__x86_64 && !__powerpc && !__m68k && !__alpha && !__mips && !__sparc64 |
79 | # undef STACKGUARD |
79 | # undef CORO_STACKGUARD |
80 | #endif |
80 | #endif |
81 | |
81 | |
82 | #ifndef STACKGUARD |
82 | #ifndef CORO_STACKGUARD |
83 | # define STACKGUARD 0 |
83 | # define CORO_STACKGUARD 0 |
84 | #endif |
84 | #endif |
85 | |
85 | |
86 | /* prefer perl internal functions over our own? */ |
86 | /* prefer perl internal functions over our own? */ |
87 | #ifndef PREFER_PERL_FUNCTIONS |
87 | #ifndef CORO_PREFER_PERL_FUNCTIONS |
88 | # define PREFER_PERL_FUNCTIONS 0 |
88 | # define CORO_PREFER_PERL_FUNCTIONS 0 |
89 | #endif |
89 | #endif |
90 | |
90 | |
91 | /* The next macro should declare a variable stacklevel that contains and approximation |
91 | /* The next macro should declare a variable stacklevel that contains and approximation |
92 | * to the current C stack pointer. Its property is that it changes with each call |
92 | * to the current C stack pointer. Its property is that it changes with each call |
93 | * and should be unique. */ |
93 | * and should be unique. */ |
… | |
… | |
124 | I32 laststype; |
124 | I32 laststype; |
125 | int laststatval; |
125 | int laststatval; |
126 | Stat_t statcache; |
126 | Stat_t statcache; |
127 | }; |
127 | }; |
128 | |
128 | |
|
|
129 | static size_t coro_stacksize = CORO_STACKSIZE; |
129 | static struct CoroAPI coroapi; |
130 | static struct CoroAPI coroapi; |
130 | static AV *main_mainstack; /* used to differentiate between $main and others */ |
131 | static AV *main_mainstack; /* used to differentiate between $main and others */ |
131 | static HV *coro_state_stash, *coro_stash; |
132 | static HV *coro_state_stash, *coro_stash; |
132 | static SV *coro_mortal; /* will be freed after next transfer */ |
133 | static SV *coro_mortal; /* will be freed after next transfer */ |
133 | |
134 | |
… | |
… | |
138 | typedef struct coro_cctx { |
139 | typedef struct coro_cctx { |
139 | struct coro_cctx *next; |
140 | struct coro_cctx *next; |
140 | |
141 | |
141 | /* the stack */ |
142 | /* the stack */ |
142 | void *sptr; |
143 | void *sptr; |
143 | ssize_t ssize; /* positive == mmap, otherwise malloc */ |
144 | size_t ssize; |
144 | |
145 | |
145 | /* cpu state */ |
146 | /* cpu state */ |
146 | void *idle_sp; /* sp of top-level transfer/schedule/cede call */ |
147 | void *idle_sp; /* sp of top-level transfer/schedule/cede call */ |
147 | JMPENV *idle_te; /* same as idle_sp, but for top_env, TODO: remove once stable */ |
148 | JMPENV *idle_te; /* same as idle_sp, but for top_env, TODO: remove once stable */ |
148 | JMPENV *top_env; |
149 | JMPENV *top_env; |
149 | coro_context cctx; |
150 | coro_context cctx; |
150 | |
151 | |
151 | int inuse; |
|
|
152 | |
|
|
153 | #if USE_VALGRIND |
152 | #if CORO_USE_VALGRIND |
154 | int valgrind_id; |
153 | int valgrind_id; |
155 | #endif |
154 | #endif |
|
|
155 | char inuse, mapped; |
156 | } coro_cctx; |
156 | } coro_cctx; |
157 | |
157 | |
158 | enum { |
158 | enum { |
159 | CF_RUNNING = 0x0001, /* coroutine is running */ |
159 | CF_RUNNING = 0x0001, /* coroutine is running */ |
160 | CF_READY = 0x0002, /* coroutine is ready */ |
160 | CF_READY = 0x0002, /* coroutine is ready */ |
… | |
… | |
288 | |
288 | |
289 | if (mg && AvFILLp ((av = (AV *)mg->mg_obj)) >= 0) |
289 | if (mg && AvFILLp ((av = (AV *)mg->mg_obj)) >= 0) |
290 | CvPADLIST (cv) = (AV *)AvARRAY (av)[AvFILLp (av)--]; |
290 | CvPADLIST (cv) = (AV *)AvARRAY (av)[AvFILLp (av)--]; |
291 | else |
291 | else |
292 | { |
292 | { |
293 | #if PREFER_PERL_FUNCTIONS |
293 | #if CORO_PREFER_PERL_FUNCTIONS |
294 | /* this is probably cleaner, but also slower? */ |
294 | /* this is probably cleaner, but also slower? */ |
295 | CV *cp = Perl_cv_clone (cv); |
295 | CV *cp = Perl_cv_clone (cv); |
296 | CvPADLIST (cv) = CvPADLIST (cp); |
296 | CvPADLIST (cv) = CvPADLIST (cp); |
297 | CvPADLIST (cp) = 0; |
297 | CvPADLIST (cp) = 0; |
298 | SvREFCNT_dec (cp); |
298 | SvREFCNT_dec (cp); |
… | |
… | |
365 | CvPADLIST (cv) = (AV *)POPs; |
365 | CvPADLIST (cv) = (AV *)POPs; |
366 | } |
366 | } |
367 | |
367 | |
368 | PUTBACK; |
368 | PUTBACK; |
369 | } |
369 | } |
|
|
370 | assert (!PL_comppad || AvARRAY (PL_comppad));//D |
370 | } |
371 | } |
371 | |
372 | |
372 | static void |
373 | static void |
373 | save_perl (Coro__State c) |
374 | save_perl (Coro__State c) |
374 | { |
375 | { |
|
|
376 | assert (!PL_comppad || AvARRAY (PL_comppad));//D |
375 | { |
377 | { |
376 | dSP; |
378 | dSP; |
377 | I32 cxix = cxstack_ix; |
379 | I32 cxix = cxstack_ix; |
378 | PERL_CONTEXT *ccstk = cxstack; |
380 | PERL_CONTEXT *ccstk = cxstack; |
379 | PERL_SI *top_si = PL_curstackinfo; |
381 | PERL_SI *top_si = PL_curstackinfo; |
… | |
… | |
434 | * allocate various perl stacks. This is an exact copy |
436 | * allocate various perl stacks. This is an exact copy |
435 | * of perl.c:init_stacks, except that it uses less memory |
437 | * of perl.c:init_stacks, except that it uses less memory |
436 | * on the (sometimes correct) assumption that coroutines do |
438 | * on the (sometimes correct) assumption that coroutines do |
437 | * not usually need a lot of stackspace. |
439 | * not usually need a lot of stackspace. |
438 | */ |
440 | */ |
439 | #if PREFER_PERL_FUNCTIONS |
441 | #if CORO_PREFER_PERL_FUNCTIONS |
440 | # define coro_init_stacks init_stacks |
442 | # define coro_init_stacks init_stacks |
441 | #else |
443 | #else |
442 | static void |
444 | static void |
443 | coro_init_stacks () |
445 | coro_init_stacks () |
444 | { |
446 | { |
… | |
… | |
538 | |
540 | |
539 | coro_init_stacks (); |
541 | coro_init_stacks (); |
540 | |
542 | |
541 | PL_curcop = &PL_compiling; |
543 | PL_curcop = &PL_compiling; |
542 | PL_in_eval = EVAL_NULL; |
544 | PL_in_eval = EVAL_NULL; |
|
|
545 | PL_comppad = 0; |
543 | PL_curpm = 0; |
546 | PL_curpm = 0; |
544 | PL_localizing = 0; |
547 | PL_localizing = 0; |
545 | PL_dirty = 0; |
548 | PL_dirty = 0; |
546 | PL_restartop = 0; |
549 | PL_restartop = 0; |
547 | |
550 | |
… | |
… | |
622 | |
625 | |
623 | static coro_cctx * |
626 | static coro_cctx * |
624 | cctx_new () |
627 | cctx_new () |
625 | { |
628 | { |
626 | coro_cctx *cctx; |
629 | coro_cctx *cctx; |
|
|
630 | void *stack_start; |
|
|
631 | size_t stack_size; |
627 | |
632 | |
628 | ++cctx_count; |
633 | ++cctx_count; |
629 | |
634 | |
630 | Newz (0, cctx, 1, coro_cctx); |
635 | Newz (0, cctx, 1, coro_cctx); |
631 | |
636 | |
632 | #if HAVE_MMAP |
637 | #if HAVE_MMAP |
633 | |
638 | |
634 | cctx->ssize = ((STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + STACKGUARD) * PAGESIZE; |
639 | cctx->ssize = ((coro_stacksize * sizeof (long) + PAGESIZE - 1) / PAGESIZE + CORO_STACKGUARD) * PAGESIZE; |
635 | /* mmap supposedly does allocate-on-write for us */ |
640 | /* mmap supposedly does allocate-on-write for us */ |
636 | cctx->sptr = mmap (0, cctx->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); |
641 | cctx->sptr = mmap (0, cctx->ssize, PROT_EXEC|PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0); |
637 | |
642 | |
638 | if (cctx->sptr != (void *)-1) |
643 | if (cctx->sptr != (void *)-1) |
639 | { |
644 | { |
640 | # if STACKGUARD |
645 | # if CORO_STACKGUARD |
641 | mprotect (cctx->sptr, STACKGUARD * PAGESIZE, PROT_NONE); |
646 | mprotect (cctx->sptr, CORO_STACKGUARD * PAGESIZE, PROT_NONE); |
642 | # endif |
647 | # endif |
643 | REGISTER_STACK ( |
|
|
644 | cctx, |
|
|
645 | STACKGUARD * PAGESIZE + (char *)cctx->sptr, |
648 | stack_start = CORO_STACKGUARD * PAGESIZE + (char *)cctx->sptr; |
646 | cctx->ssize + (char *)cctx->sptr |
649 | stack_size = cctx->ssize - CORO_STACKGUARD * PAGESIZE; |
647 | ); |
650 | cctx->mapped = 1; |
648 | |
|
|
649 | coro_create (&cctx->cctx, coro_run, (void *)cctx, cctx->sptr, cctx->ssize); |
|
|
650 | } |
651 | } |
651 | else |
652 | else |
652 | #endif |
653 | #endif |
653 | { |
654 | { |
654 | cctx->ssize = -STACKSIZE * (long)sizeof (long); |
655 | cctx->ssize = coro_stacksize * (long)sizeof (long); |
655 | New (0, cctx->sptr, STACKSIZE, long); |
656 | New (0, cctx->sptr, coro_stacksize, long); |
656 | |
657 | |
657 | if (!cctx->sptr) |
658 | if (!cctx->sptr) |
658 | { |
659 | { |
659 | perror ("FATAL: unable to allocate stack for coroutine"); |
660 | perror ("FATAL: unable to allocate stack for coroutine"); |
660 | _exit (EXIT_FAILURE); |
661 | _exit (EXIT_FAILURE); |
661 | } |
662 | } |
662 | |
663 | |
663 | REGISTER_STACK ( |
664 | stack_start = cctx->sptr; |
664 | cctx, |
665 | stack_size = cctx->ssize; |
665 | (char *)cctx->sptr, |
666 | } |
666 | (char *)cctx->sptr - cctx->ssize |
|
|
667 | ); |
|
|
668 | |
667 | |
|
|
668 | REGISTER_STACK (cctx, (char *)stack_start, (char *)stack_start + stack_size); |
669 | coro_create (&cctx->cctx, coro_run, (void *)cctx, cctx->sptr, -cctx->ssize); |
669 | coro_create (&cctx->cctx, coro_run, (void *)cctx, stack_start, stack_size); |
670 | } |
|
|
671 | |
670 | |
672 | return cctx; |
671 | return cctx; |
673 | } |
672 | } |
674 | |
673 | |
675 | static void |
674 | static void |
… | |
… | |
678 | if (!cctx) |
677 | if (!cctx) |
679 | return; |
678 | return; |
680 | |
679 | |
681 | --cctx_count; |
680 | --cctx_count; |
682 | |
681 | |
683 | #if USE_VALGRIND |
682 | #if CORO_USE_VALGRIND |
684 | VALGRIND_STACK_DEREGISTER (cctx->valgrind_id); |
683 | VALGRIND_STACK_DEREGISTER (cctx->valgrind_id); |
685 | #endif |
684 | #endif |
686 | |
685 | |
687 | #if HAVE_MMAP |
686 | #if HAVE_MMAP |
688 | if (cctx->ssize > 0) |
687 | if (cctx->mapped) |
689 | munmap (cctx->sptr, cctx->ssize); |
688 | munmap (cctx->sptr, cctx->ssize); |
690 | else |
689 | else |
691 | #endif |
690 | #endif |
692 | Safefree (cctx->sptr); |
691 | Safefree (cctx->sptr); |
693 | |
692 | |
… | |
… | |
695 | } |
694 | } |
696 | |
695 | |
697 | static coro_cctx * |
696 | static coro_cctx * |
698 | cctx_get () |
697 | cctx_get () |
699 | { |
698 | { |
700 | coro_cctx *cctx; |
|
|
701 | |
|
|
702 | if (cctx_first) |
699 | while (cctx_first) |
703 | { |
700 | { |
704 | cctx = cctx_first; |
701 | coro_cctx *cctx = cctx_first; |
705 | cctx_first = cctx->next; |
702 | cctx_first = cctx->next; |
706 | --cctx_idle; |
703 | --cctx_idle; |
|
|
704 | |
|
|
705 | if (cctx->ssize >= coro_stacksize) |
|
|
706 | return cctx; |
|
|
707 | |
|
|
708 | cctx_destroy (cctx); |
707 | } |
709 | } |
708 | else |
710 | |
709 | { |
|
|
710 | cctx = cctx_new (); |
|
|
711 | PL_op = PL_op->op_next; |
711 | PL_op = PL_op->op_next; |
712 | } |
|
|
713 | |
|
|
714 | return cctx; |
712 | return cctx_new (); |
715 | } |
713 | } |
716 | |
714 | |
717 | static void |
715 | static void |
718 | cctx_put (coro_cctx *cctx) |
716 | cctx_put (coro_cctx *cctx) |
719 | { |
717 | { |
… | |
… | |
933 | /* very slow, but rare, check */ |
931 | /* very slow, but rare, check */ |
934 | if (!sv_derived_from (sv_2mortal (newRV_inc (coro)), "Coro::State")) |
932 | if (!sv_derived_from (sv_2mortal (newRV_inc (coro)), "Coro::State")) |
935 | croak ("Coro::State object required"); |
933 | croak ("Coro::State object required"); |
936 | } |
934 | } |
937 | |
935 | |
938 | mg = SvMAGIC (coro); |
936 | mg = CORO_MAGIC (coro); |
939 | assert (mg->mg_type == PERL_MAGIC_ext); |
|
|
940 | return (struct coro *)mg->mg_ptr; |
937 | return (struct coro *)mg->mg_ptr; |
941 | } |
938 | } |
942 | |
939 | |
943 | static void |
940 | static void |
944 | prepare_transfer (struct transfer_args *ta, SV *prev_sv, SV *next_sv) |
941 | prepare_transfer (struct transfer_args *ta, SV *prev_sv, SV *next_sv) |
… | |
… | |
1256 | PROTOTYPE: $ |
1253 | PROTOTYPE: $ |
1257 | CODE: |
1254 | CODE: |
1258 | _exit (code); |
1255 | _exit (code); |
1259 | |
1256 | |
1260 | int |
1257 | int |
|
|
1258 | cctx_stacksize (int new_stacksize = 0) |
|
|
1259 | CODE: |
|
|
1260 | RETVAL = coro_stacksize; |
|
|
1261 | if (new_stacksize) |
|
|
1262 | coro_stacksize = new_stacksize; |
|
|
1263 | OUTPUT: |
|
|
1264 | RETVAL |
|
|
1265 | |
|
|
1266 | int |
1261 | cctx_count () |
1267 | cctx_count () |
1262 | CODE: |
1268 | CODE: |
1263 | RETVAL = cctx_count; |
1269 | RETVAL = cctx_count; |
1264 | OUTPUT: |
1270 | OUTPUT: |
1265 | RETVAL |
1271 | RETVAL |