… | |
… | |
161 | /* async_pool helper stuff */ |
161 | /* async_pool helper stuff */ |
162 | static SV *sv_pool_rss; |
162 | static SV *sv_pool_rss; |
163 | static SV *sv_pool_size; |
163 | static SV *sv_pool_size; |
164 | static AV *av_async_pool; |
164 | static AV *av_async_pool; |
165 | |
165 | |
166 | static struct coro_cctx *cctx_first[3]; /* index by GIMME_V type, void, scalar, array */ |
166 | static struct coro_cctx *cctx_first; |
167 | static int cctx_count, cctx_idle[3]; |
167 | static int cctx_count, cctx_idle; |
168 | |
168 | |
169 | enum { |
169 | enum { |
170 | CC_MAPPED = 0x01, |
170 | CC_MAPPED = 0x01, |
171 | CC_NOREUSE = 0x02, /* throw this away after tracing */ |
171 | CC_NOREUSE = 0x02, /* throw this away after tracing */ |
172 | CC_TRACE = 0x04, |
172 | CC_TRACE = 0x04, |
… | |
… | |
217 | |
217 | |
218 | /* this is a structure representing a perl-level coroutine */ |
218 | /* this is a structure representing a perl-level coroutine */ |
219 | struct coro { |
219 | struct coro { |
220 | /* the c coroutine allocated to this perl coroutine, if any */ |
220 | /* the c coroutine allocated to this perl coroutine, if any */ |
221 | coro_cctx *cctx; |
221 | coro_cctx *cctx; |
222 | int gimme; |
|
|
223 | |
222 | |
224 | /* process data */ |
223 | /* process data */ |
225 | AV *mainstack; |
224 | AV *mainstack; |
226 | perl_slots *slot; /* basically the saved sp */ |
225 | perl_slots *slot; /* basically the saved sp */ |
227 | |
226 | |
… | |
… | |
712 | XPUSHs (sv_2mortal (av_shift (GvAV (PL_defgv)))); |
711 | XPUSHs (sv_2mortal (av_shift (GvAV (PL_defgv)))); |
713 | PUTBACK; |
712 | PUTBACK; |
714 | PL_op = (OP *)&myop; |
713 | PL_op = (OP *)&myop; |
715 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
714 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
716 | SPAGAIN; |
715 | SPAGAIN; |
717 | |
|
|
718 | /* |
|
|
719 | * now its very tricky. the "tail" of the next transfer might end up |
|
|
720 | * either in a new cctx, or an existing one. |
|
|
721 | * in case of an existing one we have to take care of whatever |
|
|
722 | * entersub and transfer do to the perl stack. |
|
|
723 | */ |
|
|
724 | ENTER; |
|
|
725 | EXTEND (SP, 4); |
|
|
726 | PUSHs ((SV *)0); /* items */ |
|
|
727 | PUSHs ((SV *)0); /* ix, set_stacklevel */ |
|
|
728 | PUSHs ((SV *)(sp - PL_stack_base + 1)); /* ax */ |
|
|
729 | PUSHs ((SV *)0); /* again */ |
|
|
730 | PUTBACK; |
|
|
731 | } |
716 | } |
732 | |
717 | |
733 | /* this newly created coroutine might be run on an existing cctx which most |
718 | /* this newly created coroutine might be run on an existing cctx which most |
734 | * likely was suspended in set_stacklevel, called from entersub. |
719 | * likely was suspended in set_stacklevel, called from entersub. |
735 | * set_stacklevl doesn't do anything on return, but entersub does LEAVE, |
720 | * set_stacklevl doesn't do anything on return, but entersub does LEAVE, |
… | |
… | |
1039 | |
1024 | |
1040 | /* wether this cctx should be destructed */ |
1025 | /* wether this cctx should be destructed */ |
1041 | #define CCTX_EXPIRED(cctx) ((cctx)->ssize < coro_stacksize || ((cctx)->flags & CC_NOREUSE)) |
1026 | #define CCTX_EXPIRED(cctx) ((cctx)->ssize < coro_stacksize || ((cctx)->flags & CC_NOREUSE)) |
1042 | |
1027 | |
1043 | static coro_cctx * |
1028 | static coro_cctx * |
1044 | cctx_get (pTHX_ int gimme) |
1029 | cctx_get (pTHX) |
1045 | { |
1030 | { |
1046 | while (expect_true (cctx_first[gimme])) |
1031 | while (expect_true (cctx_first)) |
1047 | { |
1032 | { |
1048 | coro_cctx *cctx = cctx_first[gimme]; |
1033 | coro_cctx *cctx = cctx_first; |
1049 | cctx_first[gimme] = cctx->next; |
1034 | cctx_first = cctx->next; |
1050 | --cctx_idle[gimme]; |
1035 | --cctx_idle; |
1051 | |
1036 | |
1052 | if (expect_true (!CCTX_EXPIRED (cctx))) |
1037 | if (expect_true (!CCTX_EXPIRED (cctx))) |
1053 | return cctx; |
1038 | return cctx; |
1054 | |
1039 | |
1055 | cctx_destroy (cctx); |
1040 | cctx_destroy (cctx); |
1056 | } |
1041 | } |
1057 | |
1042 | |
1058 | assert (!gimme); |
|
|
1059 | return cctx_new (); |
1043 | return cctx_new (); |
1060 | } |
1044 | } |
1061 | |
1045 | |
1062 | static void |
1046 | static void |
1063 | cctx_put (coro_cctx *cctx, int gimme) |
1047 | cctx_put (coro_cctx *cctx) |
1064 | { |
1048 | { |
1065 | /* free another cctx if overlimit */ |
1049 | /* free another cctx if overlimit */ |
1066 | if (expect_false (cctx_idle[gimme] >= MAX_IDLE_CCTX)) |
1050 | if (expect_false (cctx_idle >= MAX_IDLE_CCTX)) |
1067 | { |
1051 | { |
1068 | coro_cctx *first = cctx_first[gimme]; |
1052 | coro_cctx *first = cctx_first; |
1069 | cctx_first[gimme] = first->next; |
1053 | cctx_first = first->next; |
1070 | --cctx_idle[gimme]; |
1054 | --cctx_idle; |
1071 | |
1055 | |
1072 | cctx_destroy (first); |
1056 | cctx_destroy (first); |
1073 | } |
1057 | } |
1074 | |
1058 | |
1075 | ++cctx_idle[gimme]; |
1059 | ++cctx_idle; |
1076 | cctx->next = cctx_first[gimme]; |
1060 | cctx->next = cctx_first; |
1077 | cctx_first[gimme] = cctx; |
1061 | cctx_first = cctx; |
1078 | } |
1062 | } |
1079 | |
1063 | |
1080 | /** coroutine switching *****************************************************/ |
1064 | /** coroutine switching *****************************************************/ |
1081 | |
1065 | |
1082 | static void |
1066 | static void |
… | |
… | |
1161 | |
1145 | |
1162 | /* if the cctx is about to be destroyed we need to make sure we won't see it in cctx_get */ |
1146 | /* if the cctx is about to be destroyed we need to make sure we won't see it in cctx_get */ |
1163 | /* without this the next cctx_get might destroy the prev__cctx while still in use */ |
1147 | /* without this the next cctx_get might destroy the prev__cctx while still in use */ |
1164 | if (expect_false (CCTX_EXPIRED (prev__cctx))) |
1148 | if (expect_false (CCTX_EXPIRED (prev__cctx))) |
1165 | if (!next->cctx) |
1149 | if (!next->cctx) |
1166 | next->cctx = cctx_get (aTHX_ next->gimme); |
1150 | next->cctx = cctx_get (aTHX); |
1167 | |
1151 | |
1168 | cctx_put (prev__cctx, prev->gimme); |
1152 | cctx_put (prev__cctx); |
1169 | } |
1153 | } |
1170 | |
1154 | |
1171 | ++next->usecount; |
1155 | ++next->usecount; |
1172 | |
1156 | |
1173 | if (expect_true (!next->cctx)) |
1157 | if (expect_true (!next->cctx)) |
1174 | next->cctx = cctx_get (aTHX_ next->gimme); |
1158 | next->cctx = cctx_get (aTHX); |
1175 | |
1159 | |
1176 | if (expect_false (prev__cctx != next->cctx)) |
1160 | if (expect_false (prev__cctx != next->cctx)) |
1177 | { |
1161 | { |
1178 | prev__cctx->top_env = PL_top_env; |
1162 | prev__cctx->top_env = PL_top_env; |
1179 | PL_top_env = next->cctx->top_env; |
1163 | PL_top_env = next->cctx->top_env; |
… | |
… | |
1661 | RETVAL |
1645 | RETVAL |
1662 | |
1646 | |
1663 | int |
1647 | int |
1664 | cctx_idle () |
1648 | cctx_idle () |
1665 | CODE: |
1649 | CODE: |
1666 | RETVAL = cctx_idle[0] + cctx_idle[1] + cctx_idle[2]; |
1650 | RETVAL = cctx_idle; |
1667 | OUTPUT: |
1651 | OUTPUT: |
1668 | RETVAL |
1652 | RETVAL |
1669 | |
1653 | |
1670 | void |
1654 | void |
1671 | list () |
1655 | list () |
… | |
… | |
1705 | eval_sv (coderef, 0); |
1689 | eval_sv (coderef, 0); |
1706 | else |
1690 | else |
1707 | call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
1691 | call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
1708 | |
1692 | |
1709 | POPSTACK; |
1693 | POPSTACK; |
|
|
1694 | SPAGAIN; |
1710 | FREETMPS; |
1695 | FREETMPS; |
1711 | LEAVE; |
1696 | LEAVE; |
1712 | PUTBACK; |
1697 | PUTBACK; |
1713 | } |
1698 | } |
1714 | |
1699 | |