… | |
… | |
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 CORO_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 */ |
… | |
… | |
625 | |
625 | |
626 | static coro_cctx * |
626 | static coro_cctx * |
627 | cctx_new () |
627 | cctx_new () |
628 | { |
628 | { |
629 | coro_cctx *cctx; |
629 | coro_cctx *cctx; |
|
|
630 | void *stack_start; |
|
|
631 | size_t stack_size; |
630 | |
632 | |
631 | ++cctx_count; |
633 | ++cctx_count; |
632 | |
634 | |
633 | Newz (0, cctx, 1, coro_cctx); |
635 | Newz (0, cctx, 1, coro_cctx); |
634 | |
636 | |
635 | #if HAVE_MMAP |
637 | #if HAVE_MMAP |
636 | |
638 | |
637 | cctx->ssize = ((CORO_STACKSIZE * sizeof (long) + PAGESIZE - 1) / PAGESIZE + CORO_STACKGUARD) * PAGESIZE; |
639 | cctx->ssize = ((coro_stacksize * sizeof (long) + PAGESIZE - 1) / PAGESIZE + CORO_STACKGUARD) * PAGESIZE; |
638 | /* mmap supposedly does allocate-on-write for us */ |
640 | /* mmap supposedly does allocate-on-write for us */ |
639 | 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); |
640 | |
642 | |
641 | if (cctx->sptr != (void *)-1) |
643 | if (cctx->sptr != (void *)-1) |
642 | { |
644 | { |
643 | # if CORO_STACKGUARD |
645 | # if CORO_STACKGUARD |
644 | mprotect (cctx->sptr, CORO_STACKGUARD * PAGESIZE, PROT_NONE); |
646 | mprotect (cctx->sptr, CORO_STACKGUARD * PAGESIZE, PROT_NONE); |
645 | # endif |
647 | # endif |
646 | REGISTER_STACK ( |
|
|
647 | cctx, |
|
|
648 | CORO_STACKGUARD * PAGESIZE + (char *)cctx->sptr, |
648 | stack_start = CORO_STACKGUARD * PAGESIZE + (char *)cctx->sptr; |
649 | cctx->ssize + (char *)cctx->sptr |
649 | stack_size = cctx->ssize - CORO_STACKGUARD * PAGESIZE; |
650 | ); |
650 | cctx->mapped = 1; |
651 | |
|
|
652 | coro_create (&cctx->cctx, coro_run, (void *)cctx, cctx->sptr, cctx->ssize); |
|
|
653 | } |
651 | } |
654 | else |
652 | else |
655 | #endif |
653 | #endif |
656 | { |
654 | { |
657 | cctx->ssize = -CORO_STACKSIZE * (long)sizeof (long); |
655 | cctx->ssize = coro_stacksize * (long)sizeof (long); |
658 | New (0, cctx->sptr, CORO_STACKSIZE, long); |
656 | New (0, cctx->sptr, coro_stacksize, long); |
659 | |
657 | |
660 | if (!cctx->sptr) |
658 | if (!cctx->sptr) |
661 | { |
659 | { |
662 | perror ("FATAL: unable to allocate stack for coroutine"); |
660 | perror ("FATAL: unable to allocate stack for coroutine"); |
663 | _exit (EXIT_FAILURE); |
661 | _exit (EXIT_FAILURE); |
664 | } |
662 | } |
665 | |
663 | |
666 | REGISTER_STACK ( |
664 | stack_start = cctx->sptr; |
667 | cctx, |
665 | stack_size = cctx->ssize; |
668 | (char *)cctx->sptr, |
666 | } |
669 | (char *)cctx->sptr - cctx->ssize |
|
|
670 | ); |
|
|
671 | |
667 | |
|
|
668 | REGISTER_STACK (cctx, (char *)stack_start, (char *)stack_start + stack_size); |
672 | 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); |
673 | } |
|
|
674 | |
670 | |
675 | return cctx; |
671 | return cctx; |
676 | } |
672 | } |
677 | |
673 | |
678 | static void |
674 | static void |
… | |
… | |
686 | #if CORO_USE_VALGRIND |
682 | #if CORO_USE_VALGRIND |
687 | VALGRIND_STACK_DEREGISTER (cctx->valgrind_id); |
683 | VALGRIND_STACK_DEREGISTER (cctx->valgrind_id); |
688 | #endif |
684 | #endif |
689 | |
685 | |
690 | #if HAVE_MMAP |
686 | #if HAVE_MMAP |
691 | if (cctx->ssize > 0) |
687 | if (cctx->mapped) |
692 | munmap (cctx->sptr, cctx->ssize); |
688 | munmap (cctx->sptr, cctx->ssize); |
693 | else |
689 | else |
694 | #endif |
690 | #endif |
695 | Safefree (cctx->sptr); |
691 | Safefree (cctx->sptr); |
696 | |
692 | |
… | |
… | |
698 | } |
694 | } |
699 | |
695 | |
700 | static coro_cctx * |
696 | static coro_cctx * |
701 | cctx_get () |
697 | cctx_get () |
702 | { |
698 | { |
703 | coro_cctx *cctx; |
|
|
704 | |
|
|
705 | if (cctx_first) |
699 | while (cctx_first) |
706 | { |
700 | { |
707 | cctx = cctx_first; |
701 | coro_cctx *cctx = cctx_first; |
708 | cctx_first = cctx->next; |
702 | cctx_first = cctx->next; |
709 | --cctx_idle; |
703 | --cctx_idle; |
|
|
704 | |
|
|
705 | if (cctx->ssize >= coro_stacksize) |
|
|
706 | return cctx; |
|
|
707 | |
|
|
708 | cctx_destroy (cctx); |
710 | } |
709 | } |
711 | else |
710 | |
712 | { |
|
|
713 | cctx = cctx_new (); |
|
|
714 | PL_op = PL_op->op_next; |
711 | PL_op = PL_op->op_next; |
715 | } |
|
|
716 | |
|
|
717 | return cctx; |
712 | return cctx_new (); |
718 | } |
713 | } |
719 | |
714 | |
720 | static void |
715 | static void |
721 | cctx_put (coro_cctx *cctx) |
716 | cctx_put (coro_cctx *cctx) |
722 | { |
717 | { |
… | |
… | |
1258 | PROTOTYPE: $ |
1253 | PROTOTYPE: $ |
1259 | CODE: |
1254 | CODE: |
1260 | _exit (code); |
1255 | _exit (code); |
1261 | |
1256 | |
1262 | 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 |
1263 | cctx_count () |
1267 | cctx_count () |
1264 | CODE: |
1268 | CODE: |
1265 | RETVAL = cctx_count; |
1269 | RETVAL = cctx_count; |
1266 | OUTPUT: |
1270 | OUTPUT: |
1267 | RETVAL |
1271 | RETVAL |