… | |
… | |
166 | static char times_valid; |
166 | static char times_valid; |
167 | |
167 | |
168 | static struct coro_cctx *cctx_first; |
168 | static struct coro_cctx *cctx_first; |
169 | static int cctx_count, cctx_idle; |
169 | static int cctx_count, cctx_idle; |
170 | |
170 | |
171 | enum { |
171 | enum |
|
|
172 | { |
172 | CC_MAPPED = 0x01, |
173 | CC_MAPPED = 0x01, |
173 | CC_NOREUSE = 0x02, /* throw this away after tracing */ |
174 | CC_NOREUSE = 0x02, /* throw this away after tracing */ |
174 | CC_TRACE = 0x04, |
175 | CC_TRACE = 0x04, |
175 | CC_TRACE_SUB = 0x08, /* trace sub calls */ |
176 | CC_TRACE_SUB = 0x08, /* trace sub calls */ |
176 | CC_TRACE_LINE = 0x10, /* trace each statement */ |
177 | CC_TRACE_LINE = 0x10, /* trace each statement */ |
… | |
… | |
201 | |
202 | |
202 | static coro_cctx *cctx_current; /* the currently running cctx */ |
203 | static coro_cctx *cctx_current; /* the currently running cctx */ |
203 | |
204 | |
204 | /*****************************************************************************/ |
205 | /*****************************************************************************/ |
205 | |
206 | |
|
|
207 | static MGVTBL coro_state_vtbl; |
|
|
208 | |
206 | enum { |
209 | enum |
|
|
210 | { |
207 | CF_RUNNING = 0x0001, /* coroutine is running */ |
211 | CF_RUNNING = 0x0001, /* coroutine is running */ |
208 | CF_READY = 0x0002, /* coroutine is ready */ |
212 | CF_READY = 0x0002, /* coroutine is ready */ |
209 | CF_NEW = 0x0004, /* has never been switched to */ |
213 | CF_NEW = 0x0004, /* has never been switched to */ |
210 | CF_DESTROYED = 0x0008, /* coroutine data has been freed */ |
214 | CF_DESTROYED = 0x0008, /* coroutine data has been freed */ |
211 | CF_SUSPENDED = 0x0010, /* coroutine can't be scheduled */ |
215 | CF_SUSPENDED = 0x0010, /* coroutine can't be scheduled */ |
… | |
… | |
227 | |
231 | |
228 | // how many context stack entries do we need for perl_slots |
232 | // how many context stack entries do we need for perl_slots |
229 | #define SLOT_COUNT ((sizeof (perl_slots) + sizeof (PERL_CONTEXT) - 1) / sizeof (PERL_CONTEXT)) |
233 | #define SLOT_COUNT ((sizeof (perl_slots) + sizeof (PERL_CONTEXT) - 1) / sizeof (PERL_CONTEXT)) |
230 | |
234 | |
231 | /* this is a structure representing a perl-level coroutine */ |
235 | /* this is a structure representing a perl-level coroutine */ |
232 | struct coro { |
236 | struct coro |
|
|
237 | { |
233 | /* the C coroutine allocated to this perl coroutine, if any */ |
238 | /* the C coroutine allocated to this perl coroutine, if any */ |
234 | coro_cctx *cctx; |
239 | coro_cctx *cctx; |
235 | |
240 | |
236 | /* ready queue */ |
241 | /* ready queue */ |
237 | struct coro *next_ready; |
242 | struct coro *next_ready; |
… | |
… | |
239 | /* state data */ |
244 | /* state data */ |
240 | struct CoroSLF slf_frame; /* saved slf frame */ |
245 | struct CoroSLF slf_frame; /* saved slf frame */ |
241 | AV *mainstack; |
246 | AV *mainstack; |
242 | perl_slots *slot; /* basically the saved sp */ |
247 | perl_slots *slot; /* basically the saved sp */ |
243 | |
248 | |
244 | CV *startcv; /* the CV to execute */ |
249 | CV *startcv; /* the CV to execute */ |
245 | AV *args; /* data associated with this coroutine (initial args) */ |
250 | AV *args; /* data associated with this coroutine (initial args) */ |
246 | int refcnt; /* coroutines are refcounted, yes */ |
|
|
247 | int flags; /* CF_ flags */ |
251 | int flags; /* CF_ flags */ |
248 | HV *hv; /* the perl hash associated with this coro, if any */ |
252 | HV *hv; /* the perl hash associated with this coro, if any */ |
249 | |
253 | |
250 | /* statistics */ |
254 | /* statistics */ |
251 | int usecount; /* number of transfers to this coro */ |
255 | int usecount; /* number of transfers to this coro */ |
252 | |
256 | |
253 | /* coro process data */ |
257 | /* coro process data */ |
254 | int prio; |
258 | int prio; |
255 | SV *except; /* exception to be thrown */ |
259 | SV *except; /* exception to be thrown */ |
256 | SV *rouse_cb; |
260 | SV *rouse_cb; /* last rouse callback */ |
|
|
261 | AV *on_destroy; /* callbacks or coros to notify on destroy */ |
|
|
262 | AV *status; /* the exit status list */ |
257 | |
263 | |
258 | /* async_pool */ |
264 | /* async_pool */ |
259 | SV *saved_deffh; |
265 | SV *saved_deffh; |
260 | SV *invoke_cb; |
266 | SV *invoke_cb; |
261 | AV *invoke_av; |
267 | AV *invoke_av; |
… | |
… | |
467 | : 0) |
473 | : 0) |
468 | |
474 | |
469 | #define CORO_MAGIC_cv(cv) CORO_MAGIC (((SV *)(cv)), CORO_MAGIC_type_cv) |
475 | #define CORO_MAGIC_cv(cv) CORO_MAGIC (((SV *)(cv)), CORO_MAGIC_type_cv) |
470 | #define CORO_MAGIC_state(sv) CORO_MAGIC_NN (((SV *)(sv)), CORO_MAGIC_type_state) |
476 | #define CORO_MAGIC_state(sv) CORO_MAGIC_NN (((SV *)(sv)), CORO_MAGIC_type_state) |
471 | |
477 | |
|
|
478 | INLINE MAGIC * |
|
|
479 | SvSTATEhv_p (pTHX_ SV *coro) |
|
|
480 | { |
|
|
481 | MAGIC *mg; |
|
|
482 | |
|
|
483 | if (expect_true ( |
|
|
484 | SvTYPE (coro) == SVt_PVHV |
|
|
485 | && (mg = CORO_MAGIC_state (coro)) |
|
|
486 | && mg->mg_virtual == &coro_state_vtbl |
|
|
487 | )) |
|
|
488 | return mg; |
|
|
489 | |
|
|
490 | return 0; |
|
|
491 | } |
|
|
492 | |
472 | INLINE struct coro * |
493 | INLINE struct coro * |
473 | SvSTATE_ (pTHX_ SV *coro) |
494 | SvSTATE_ (pTHX_ SV *coro) |
474 | { |
495 | { |
475 | HV *stash; |
|
|
476 | MAGIC *mg; |
496 | MAGIC *mg; |
477 | |
497 | |
478 | if (SvROK (coro)) |
498 | if (SvROK (coro)) |
479 | coro = SvRV (coro); |
499 | coro = SvRV (coro); |
480 | |
500 | |
481 | if (expect_false (SvTYPE (coro) != SVt_PVHV)) |
501 | mg = SvSTATEhv_p (coro); |
|
|
502 | if (!mg) |
482 | croak ("Coro::State object required"); |
503 | croak ("Coro::State object required"); |
483 | |
504 | |
484 | stash = SvSTASH (coro); |
|
|
485 | if (expect_false (stash != coro_stash && stash != coro_state_stash)) |
|
|
486 | { |
|
|
487 | /* very slow, but rare, check */ |
|
|
488 | if (!sv_derived_from (sv_2mortal (newRV_inc (coro)), "Coro::State")) |
|
|
489 | croak ("Coro::State object required"); |
|
|
490 | } |
|
|
491 | |
|
|
492 | mg = CORO_MAGIC_state (coro); |
|
|
493 | return (struct coro *)mg->mg_ptr; |
505 | return (struct coro *)mg->mg_ptr; |
494 | } |
506 | } |
495 | |
507 | |
496 | #define SvSTATE(sv) SvSTATE_ (aTHX_ (sv)) |
508 | #define SvSTATE(sv) SvSTATE_ (aTHX_ (sv)) |
497 | |
509 | |
… | |
… | |
1106 | /* this newly created coroutine might be run on an existing cctx which most |
1118 | /* this newly created coroutine might be run on an existing cctx which most |
1107 | * likely was suspended in pp_slf, so we have to emulate entering pp_slf here. |
1119 | * likely was suspended in pp_slf, so we have to emulate entering pp_slf here. |
1108 | */ |
1120 | */ |
1109 | slf_frame.prepare = prepare_nop; /* provide a nop function for an eventual pp_slf */ |
1121 | slf_frame.prepare = prepare_nop; /* provide a nop function for an eventual pp_slf */ |
1110 | slf_frame.check = slf_check_nop; /* signal pp_slf to not repeat */ |
1122 | slf_frame.check = slf_check_nop; /* signal pp_slf to not repeat */ |
|
|
1123 | slf_frame.destroy = 0; |
1111 | |
1124 | |
1112 | /* and we have to provide the pp_slf op in any case, so pp_slf can skip it */ |
1125 | /* and we have to provide the pp_slf op in any case, so pp_slf can skip it */ |
1113 | init_perl_op.op_next = PL_op; |
1126 | init_perl_op.op_next = PL_op; |
1114 | init_perl_op.op_type = OP_ENTERSUB; |
1127 | init_perl_op.op_type = OP_ENTERSUB; |
1115 | init_perl_op.op_ppaddr = pp_slf; |
1128 | init_perl_op.op_ppaddr = pp_slf; |
… | |
… | |
1167 | SvRV_set (coro_current, (SV *)coro->hv); |
1180 | SvRV_set (coro_current, (SV *)coro->hv); |
1168 | |
1181 | |
1169 | load_perl (aTHX_ coro); |
1182 | load_perl (aTHX_ coro); |
1170 | |
1183 | |
1171 | coro_unwind_stacks (aTHX); |
1184 | coro_unwind_stacks (aTHX); |
1172 | coro_destruct_stacks (aTHX); |
|
|
1173 | |
1185 | |
1174 | /* restore swapped sv's */ |
1186 | /* restore swapped sv's */ |
1175 | SWAP_SVS (coro); |
1187 | SWAP_SVS (coro); |
|
|
1188 | |
|
|
1189 | coro_destruct_stacks (aTHX); |
1176 | |
1190 | |
1177 | // now save some sv's to be free'd later |
1191 | // now save some sv's to be free'd later |
1178 | svf [0] = GvSV (PL_defgv); |
1192 | svf [0] = GvSV (PL_defgv); |
1179 | svf [1] = (SV *)GvAV (PL_defgv); |
1193 | svf [1] = (SV *)GvAV (PL_defgv); |
1180 | svf [2] = GvSV (PL_errgv); |
1194 | svf [2] = GvSV (PL_errgv); |
… | |
… | |
1207 | INLINE void |
1221 | INLINE void |
1208 | free_coro_mortal (pTHX) |
1222 | free_coro_mortal (pTHX) |
1209 | { |
1223 | { |
1210 | if (expect_true (coro_mortal)) |
1224 | if (expect_true (coro_mortal)) |
1211 | { |
1225 | { |
1212 | SvREFCNT_dec (coro_mortal); |
1226 | SvREFCNT_dec ((SV *)coro_mortal); |
1213 | coro_mortal = 0; |
1227 | coro_mortal = 0; |
1214 | } |
1228 | } |
1215 | } |
1229 | } |
1216 | |
1230 | |
1217 | static int |
1231 | static int |
… | |
… | |
1673 | #define TRANSFER(ta, force_cctx) transfer (aTHX_ (ta).prev, (ta).next, (force_cctx)) |
1687 | #define TRANSFER(ta, force_cctx) transfer (aTHX_ (ta).prev, (ta).next, (force_cctx)) |
1674 | #define TRANSFER_CHECK(ta) transfer_check (aTHX_ (ta).prev, (ta).next) |
1688 | #define TRANSFER_CHECK(ta) transfer_check (aTHX_ (ta).prev, (ta).next) |
1675 | |
1689 | |
1676 | /** high level stuff ********************************************************/ |
1690 | /** high level stuff ********************************************************/ |
1677 | |
1691 | |
|
|
1692 | /* this function is actually Coro, not Coro::State, but we call it from here */ |
|
|
1693 | /* because it is convenient - but it hasn't been declared yet for that reason */ |
|
|
1694 | static void |
|
|
1695 | coro_call_on_destroy (pTHX_ struct coro *coro); |
|
|
1696 | |
1678 | static void |
1697 | static void |
1679 | coro_state_destroy (pTHX_ struct coro *coro) |
1698 | coro_state_destroy (pTHX_ struct coro *coro) |
1680 | { |
1699 | { |
1681 | if (coro->flags & CF_DESTROYED) |
1700 | if (coro->flags & CF_DESTROYED) |
1682 | return; |
1701 | return; |
… | |
… | |
1691 | /* alternative: look through all ready queues and remove the coro */ |
1710 | /* alternative: look through all ready queues and remove the coro */ |
1692 | --coro_nready; |
1711 | --coro_nready; |
1693 | } |
1712 | } |
1694 | else |
1713 | else |
1695 | coro->flags |= CF_READY; /* make sure it is NOT put into the readyqueue */ |
1714 | coro->flags |= CF_READY; /* make sure it is NOT put into the readyqueue */ |
|
|
1715 | |
|
|
1716 | if (coro->next) coro->next->prev = coro->prev; |
|
|
1717 | if (coro->prev) coro->prev->next = coro->next; |
|
|
1718 | if (coro == coro_first) coro_first = coro->next; |
1696 | |
1719 | |
1697 | if (coro->mainstack |
1720 | if (coro->mainstack |
1698 | && coro->mainstack != main_mainstack |
1721 | && coro->mainstack != main_mainstack |
1699 | && coro->slot |
1722 | && coro->slot |
1700 | && !PL_dirty) |
1723 | && !PL_dirty) |
1701 | destroy_perl (aTHX_ coro); |
1724 | destroy_perl (aTHX_ coro); |
1702 | |
1725 | |
1703 | if (coro->next) coro->next->prev = coro->prev; |
|
|
1704 | if (coro->prev) coro->prev->next = coro->next; |
|
|
1705 | if (coro == coro_first) coro_first = coro->next; |
|
|
1706 | |
|
|
1707 | cctx_destroy (coro->cctx); |
1726 | cctx_destroy (coro->cctx); |
1708 | SvREFCNT_dec (coro->startcv); |
1727 | SvREFCNT_dec (coro->startcv); |
1709 | SvREFCNT_dec (coro->args); |
1728 | SvREFCNT_dec (coro->args); |
1710 | SvREFCNT_dec (coro->swap_sv); |
1729 | SvREFCNT_dec (coro->swap_sv); |
1711 | SvREFCNT_dec (CORO_THROW); |
1730 | SvREFCNT_dec (CORO_THROW); |
|
|
1731 | |
|
|
1732 | coro_call_on_destroy (coro); |
|
|
1733 | |
|
|
1734 | /* more destruction mayhem in coro_state_free */ |
1712 | } |
1735 | } |
1713 | |
1736 | |
1714 | static int |
1737 | static int |
1715 | coro_state_free (pTHX_ SV *sv, MAGIC *mg) |
1738 | coro_state_free (pTHX_ SV *sv, MAGIC *mg) |
1716 | { |
1739 | { |
1717 | struct coro *coro = (struct coro *)mg->mg_ptr; |
1740 | struct coro *coro = (struct coro *)mg->mg_ptr; |
1718 | mg->mg_ptr = 0; |
1741 | mg->mg_ptr = 0; |
1719 | |
1742 | |
1720 | coro->hv = 0; |
|
|
1721 | |
|
|
1722 | if (--coro->refcnt < 0) |
|
|
1723 | { |
|
|
1724 | coro_state_destroy (aTHX_ coro); |
1743 | coro_state_destroy (coro); |
|
|
1744 | SvREFCNT_dec (coro->on_destroy); |
|
|
1745 | SvREFCNT_dec (coro->status); |
|
|
1746 | |
1725 | Safefree (coro); |
1747 | Safefree (coro); |
1726 | } |
|
|
1727 | |
1748 | |
1728 | return 0; |
1749 | return 0; |
1729 | } |
1750 | } |
1730 | |
1751 | |
1731 | static int |
1752 | static int |
1732 | coro_state_dup (pTHX_ MAGIC *mg, CLONE_PARAMS *params) |
1753 | coro_state_dup (pTHX_ MAGIC *mg, CLONE_PARAMS *params) |
1733 | { |
1754 | { |
1734 | struct coro *coro = (struct coro *)mg->mg_ptr; |
1755 | /* called when perl clones the current process the slow way (windows process emulation) */ |
1735 | |
1756 | /* WE SIMply nuke the pointers in the copy, causing perl to croak */ |
1736 | ++coro->refcnt; |
1757 | mg->mg_ptr = 0; |
|
|
1758 | mg->mg_virtual = 0; |
1737 | |
1759 | |
1738 | return 0; |
1760 | return 0; |
1739 | } |
1761 | } |
1740 | |
1762 | |
1741 | static MGVTBL coro_state_vtbl = { |
1763 | static MGVTBL coro_state_vtbl = { |
… | |
… | |
2010 | coro->slot->runops = RUNOPS_DEFAULT; |
2032 | coro->slot->runops = RUNOPS_DEFAULT; |
2011 | } |
2033 | } |
2012 | } |
2034 | } |
2013 | |
2035 | |
2014 | static void |
2036 | static void |
|
|
2037 | coro_push_av (pTHX_ AV *av, I32 gimme_v) |
|
|
2038 | { |
|
|
2039 | if (AvFILLp (av) >= 0 && gimme_v != G_VOID) |
|
|
2040 | { |
|
|
2041 | dSP; |
|
|
2042 | |
|
|
2043 | if (gimme_v == G_SCALAR) |
|
|
2044 | XPUSHs (AvARRAY (av)[AvFILLp (av)]); |
|
|
2045 | else |
|
|
2046 | { |
|
|
2047 | int i; |
|
|
2048 | EXTEND (SP, AvFILLp (av) + 1); |
|
|
2049 | |
|
|
2050 | for (i = 0; i <= AvFILLp (av); ++i) |
|
|
2051 | PUSHs (AvARRAY (av)[i]); |
|
|
2052 | } |
|
|
2053 | |
|
|
2054 | PUTBACK; |
|
|
2055 | } |
|
|
2056 | } |
|
|
2057 | |
|
|
2058 | static void |
|
|
2059 | coro_push_on_destroy (aTHX_ struct coro *coro, SV *cb) |
|
|
2060 | { |
|
|
2061 | if (!coro->on_destroy) |
|
|
2062 | coro->on_destroy = newAV (); |
|
|
2063 | |
|
|
2064 | av_push (coro->on_destroy, cb); |
|
|
2065 | } |
|
|
2066 | |
|
|
2067 | static void |
|
|
2068 | slf_destroy_join (pTHX_ struct CoroSLF *frame) |
|
|
2069 | { |
|
|
2070 | SvREFCNT_dec ((SV *)((struct coro *)frame->data)->hv); |
|
|
2071 | } |
|
|
2072 | |
|
|
2073 | static int |
|
|
2074 | slf_check_join (pTHX_ struct CoroSLF *frame) |
|
|
2075 | { |
|
|
2076 | struct coro *coro = (struct coro *)frame->data; |
|
|
2077 | |
|
|
2078 | if (!coro->status) |
|
|
2079 | return 1; |
|
|
2080 | |
|
|
2081 | frame->destroy = 0; |
|
|
2082 | |
|
|
2083 | coro_push_av (coro->status, GIMME_V); |
|
|
2084 | |
|
|
2085 | SvREFCNT_dec ((SV *)coro->hv); |
|
|
2086 | |
|
|
2087 | return 0; |
|
|
2088 | } |
|
|
2089 | |
|
|
2090 | static void |
|
|
2091 | slf_init_join (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
|
|
2092 | { |
|
|
2093 | struct coro *coro = SvSTATE (items > 0 ? arg [0] : &PL_sv_undef); |
|
|
2094 | |
|
|
2095 | if (items > 1) |
|
|
2096 | croak ("join called with too many arguments"); |
|
|
2097 | |
|
|
2098 | if (coro->status) |
|
|
2099 | frame->prepare = prepare_nop; |
|
|
2100 | else |
|
|
2101 | { |
|
|
2102 | coro_push_on_destroy (aTHX_ coro, SvREFCNT_inc_NN (SvRV (coro_current))); |
|
|
2103 | frame->prepare = prepare_schedule; |
|
|
2104 | } |
|
|
2105 | |
|
|
2106 | frame->check = slf_check_join; |
|
|
2107 | frame->destroy = slf_destroy_join; |
|
|
2108 | frame->data = (void *)coro; |
|
|
2109 | SvREFCNT_inc (coro->hv); |
|
|
2110 | } |
|
|
2111 | |
|
|
2112 | static void |
2015 | coro_call_on_destroy (pTHX_ struct coro *coro) |
2113 | coro_call_on_destroy (pTHX_ struct coro *coro) |
2016 | { |
2114 | { |
2017 | SV **on_destroyp = hv_fetch (coro->hv, "_on_destroy", sizeof ("_on_destroy") - 1, 0); |
2115 | AV *od = coro->on_destroy; |
2018 | |
2116 | |
2019 | if (on_destroyp) |
2117 | if (!od) |
2020 | { |
2118 | return; |
2021 | SV **statusp = hv_fetch (coro->hv, "_status", sizeof ("_status") - 1, 0); |
|
|
2022 | AV *on_destroy = sv_2mortal (SvREFCNT_inc ((AV *)SvRV (*on_destroyp))); |
|
|
2023 | AV *status = statusp ? sv_2mortal (SvREFCNT_inc ((AV *)SvRV (*statusp))) : 0; |
|
|
2024 | |
2119 | |
2025 | while (AvFILLp (on_destroy) >= 0) |
2120 | while (AvFILLp (od) >= 0) |
|
|
2121 | { |
|
|
2122 | SV *cb = sv_2mortal (av_pop (od)); |
|
|
2123 | |
|
|
2124 | /* coro hv's (and only hv's at the moment) are supported as well */ |
|
|
2125 | if (SvSTATEhv_p (aTHX_ cb)) |
|
|
2126 | api_ready (aTHX_ cb); |
|
|
2127 | else |
2026 | { |
2128 | { |
2027 | dSP; /* don't disturb outer sp */ |
2129 | dSP; /* don't disturb outer sp */ |
2028 | SV *cb = av_pop (on_destroy); |
|
|
2029 | |
|
|
2030 | PUSHMARK (SP); |
2130 | PUSHMARK (SP); |
2031 | |
2131 | |
2032 | if (statusp) |
2132 | if (coro->status) |
2033 | { |
2133 | { |
2034 | int i; |
2134 | PUTBACK; |
2035 | EXTEND (SP, AvFILLp (status) + 1); |
2135 | coro_push_av (aTHX_ coro->status, G_ARRAY); |
2036 | |
2136 | SPAGAIN; |
2037 | for (i = 0; i <= AvFILLp (status); ++i) |
|
|
2038 | PUSHs (AvARRAY (status)[i]); |
|
|
2039 | } |
2137 | } |
2040 | |
2138 | |
2041 | PUTBACK; |
2139 | PUTBACK; |
2042 | call_sv (sv_2mortal (cb), G_VOID | G_DISCARD); |
2140 | call_sv (sv_2mortal (cb), G_VOID | G_DISCARD); |
2043 | } |
2141 | } |
2044 | } |
2142 | } |
2045 | } |
2143 | } |
2046 | |
2144 | |
2047 | static void |
2145 | static void |
2048 | coro_set_status (pTHX_ HV *coro_hv, SV **arg, int items) |
2146 | coro_set_status (pTHX_ struct coro *coro, SV **arg, int items) |
2049 | { |
2147 | { |
2050 | AV *av = newAV (); |
2148 | AV *av; |
|
|
2149 | |
|
|
2150 | if (coro->status) |
|
|
2151 | { |
|
|
2152 | av = coro->status; |
|
|
2153 | av_clear (av); |
|
|
2154 | } |
|
|
2155 | else |
|
|
2156 | av = coro->status = newAV (); |
2051 | |
2157 | |
2052 | /* items are actually not so common, so optimise for this case */ |
2158 | /* items are actually not so common, so optimise for this case */ |
2053 | if (items) |
2159 | if (items) |
2054 | { |
2160 | { |
2055 | int i; |
2161 | int i; |
… | |
… | |
2057 | av_extend (av, items - 1); |
2163 | av_extend (av, items - 1); |
2058 | |
2164 | |
2059 | for (i = 0; i < items; ++i) |
2165 | for (i = 0; i < items; ++i) |
2060 | av_push (av, SvREFCNT_inc_NN (arg [i])); |
2166 | av_push (av, SvREFCNT_inc_NN (arg [i])); |
2061 | } |
2167 | } |
2062 | |
|
|
2063 | hv_store (coro_hv, "_status", sizeof ("_status") - 1, newRV_noinc ((SV *)av), 0); |
|
|
2064 | } |
2168 | } |
2065 | |
2169 | |
2066 | static void |
2170 | static void |
2067 | slf_init_terminate_cancel_common (pTHX_ struct CoroSLF *frame, HV *coro_hv) |
2171 | slf_init_terminate_cancel_common (pTHX_ struct CoroSLF *frame, HV *coro_hv) |
2068 | { |
2172 | { |
… | |
… | |
2080 | static void |
2184 | static void |
2081 | slf_init_terminate (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
2185 | slf_init_terminate (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
2082 | { |
2186 | { |
2083 | HV *coro_hv = (HV *)SvRV (coro_current); |
2187 | HV *coro_hv = (HV *)SvRV (coro_current); |
2084 | |
2188 | |
2085 | coro_set_status (aTHX_ coro_hv, arg, items); |
2189 | coro_set_status (aTHX_ SvSTATE ((SV *)coro_hv), arg, items); |
2086 | slf_init_terminate_cancel_common (aTHX_ frame, coro_hv); |
2190 | slf_init_terminate_cancel_common (aTHX_ frame, coro_hv); |
2087 | } |
2191 | } |
2088 | |
2192 | |
2089 | static void |
2193 | static void |
2090 | slf_init_cancel (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
2194 | slf_init_cancel (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
… | |
… | |
2096 | croak ("Coro::cancel called without coro object,"); |
2200 | croak ("Coro::cancel called without coro object,"); |
2097 | |
2201 | |
2098 | coro = SvSTATE (arg [0]); |
2202 | coro = SvSTATE (arg [0]); |
2099 | coro_hv = coro->hv; |
2203 | coro_hv = coro->hv; |
2100 | |
2204 | |
2101 | coro_set_status (aTHX_ coro_hv, arg + 1, items - 1); |
2205 | coro_set_status (aTHX_ coro, arg + 1, items - 1); |
2102 | |
2206 | |
2103 | if (expect_false (coro->flags & CF_NOCANCEL)) |
2207 | if (expect_false (coro->flags & CF_NOCANCEL)) |
2104 | { |
2208 | { |
2105 | /* coro currently busy cancelling something, so just notify it */ |
2209 | /* coro currently busy cancelling something, so just notify it */ |
2106 | coro->slf_frame.data = (void *)coro; |
2210 | coro->slf_frame.data = (void *)coro; |
… | |
… | |
2123 | * this is ugly, and hopefully fully worth the extra speed. |
2227 | * this is ugly, and hopefully fully worth the extra speed. |
2124 | * besides, I can't get the slow-but-safe version working... |
2228 | * besides, I can't get the slow-but-safe version working... |
2125 | */ |
2229 | */ |
2126 | slf_frame.data = 0; |
2230 | slf_frame.data = 0; |
2127 | self->flags |= CF_NOCANCEL; |
2231 | self->flags |= CF_NOCANCEL; |
2128 | |
|
|
2129 | coro_state_destroy (aTHX_ coro); |
2232 | coro_state_destroy (aTHX_ coro); |
2130 | coro_call_on_destroy (aTHX_ coro); |
|
|
2131 | |
|
|
2132 | self->flags &= ~CF_NOCANCEL; |
2233 | self->flags &= ~CF_NOCANCEL; |
2133 | |
2234 | |
2134 | if (slf_frame.data) |
2235 | if (slf_frame.data) |
2135 | { |
2236 | { |
2136 | /* while we were busy we have been cancelled, so terminate */ |
2237 | /* while we were busy we have been cancelled, so terminate */ |
… | |
… | |
2161 | if (coro->cctx) |
2262 | if (coro->cctx) |
2162 | croak ("coro inside C callback, unable to cancel at this time, caught"); |
2263 | croak ("coro inside C callback, unable to cancel at this time, caught"); |
2163 | |
2264 | |
2164 | if (coro->flags & CF_NEW) |
2265 | if (coro->flags & CF_NEW) |
2165 | { |
2266 | { |
2166 | coro_set_status (aTHX_ coro->hv, arg, items); |
2267 | coro_set_status (aTHX_ coro, arg, items); |
2167 | coro_state_destroy (aTHX_ coro); |
2268 | coro_state_destroy (aTHX_ coro); |
2168 | coro_call_on_destroy (aTHX_ coro); |
|
|
2169 | } |
2269 | } |
2170 | else |
2270 | else |
2171 | { |
2271 | { |
2172 | if (!coro->slf_frame.prepare) |
2272 | if (!coro->slf_frame.prepare) |
2173 | croak ("coro outside an SLF function, unable to cancel at this time, caught"); |
2273 | croak ("coro outside an SLF function, unable to cancel at this time, caught"); |
2174 | |
2274 | |
2175 | slf_destroy (aTHX_ coro); |
2275 | slf_destroy (aTHX_ coro); |
2176 | |
2276 | |
2177 | coro_set_status (aTHX_ coro->hv, arg, items); |
2277 | coro_set_status (aTHX_ coro, arg, items); |
2178 | coro->slf_frame.prepare = prepare_nop; |
2278 | coro->slf_frame.prepare = prepare_nop; |
2179 | coro->slf_frame.check = slf_check_safe_cancel; |
2279 | coro->slf_frame.check = slf_check_safe_cancel; |
2180 | |
2280 | |
2181 | api_ready (aTHX_ coro->hv); |
2281 | api_ready (aTHX_ (SV *)coro->hv); |
2182 | } |
2282 | } |
2183 | |
2283 | |
2184 | return 1; |
2284 | return 1; |
2185 | } |
2285 | } |
2186 | |
2286 | |
… | |
… | |
2471 | static void |
2571 | static void |
2472 | slf_destroy (pTHX_ struct coro *coro) |
2572 | slf_destroy (pTHX_ struct coro *coro) |
2473 | { |
2573 | { |
2474 | /* this callback is reserved for slf functions needing to do cleanup */ |
2574 | /* this callback is reserved for slf functions needing to do cleanup */ |
2475 | if (coro->slf_frame.destroy && coro->slf_frame.prepare && !PL_dirty) |
2575 | if (coro->slf_frame.destroy && coro->slf_frame.prepare && !PL_dirty) |
2476 | coro->slf_frame.destroy (aTHX_ coro); |
2576 | coro->slf_frame.destroy (aTHX_ &coro->slf_frame); |
2477 | |
2577 | |
2478 | /* |
2578 | /* |
2479 | * The on_destroy above most likely is from an SLF call. |
2579 | * The on_destroy above most likely is from an SLF call. |
2480 | * Since by definition the SLF call will not finish when we destroy |
2580 | * Since by definition the SLF call will not finish when we destroy |
2481 | * the coro, we will have to force-finish it here, otherwise |
2581 | * the coro, we will have to force-finish it here, otherwise |
… | |
… | |
2558 | croak (0); |
2658 | croak (0); |
2559 | } |
2659 | } |
2560 | |
2660 | |
2561 | /* return value handling - mostly like entersub */ |
2661 | /* return value handling - mostly like entersub */ |
2562 | /* make sure we put something on the stack in scalar context */ |
2662 | /* make sure we put something on the stack in scalar context */ |
2563 | if (GIMME_V == G_SCALAR) |
2663 | if (GIMME_V == G_SCALAR |
|
|
2664 | && expect_false (PL_stack_sp != PL_stack_base + checkmark + 1)) |
2564 | { |
2665 | { |
2565 | dSP; |
2666 | dSP; |
2566 | SV **bot = PL_stack_base + checkmark; |
2667 | SV **bot = PL_stack_base + checkmark; |
2567 | |
2668 | |
2568 | if (sp == bot) /* too few, push undef */ |
2669 | if (sp == bot) /* too few, push undef */ |
2569 | bot [1] = &PL_sv_undef; |
2670 | bot [1] = &PL_sv_undef; |
2570 | else if (sp != bot + 1) /* too many, take last one */ |
2671 | else /* too many, take last one */ |
2571 | bot [1] = *sp; |
2672 | bot [1] = *sp; |
2572 | |
2673 | |
2573 | SP = bot + 1; |
2674 | SP = bot + 1; |
2574 | |
2675 | |
2575 | PUTBACK; |
2676 | PUTBACK; |
… | |
… | |
2815 | SvREFCNT_dec (cb); |
2916 | SvREFCNT_dec (cb); |
2816 | } |
2917 | } |
2817 | } |
2918 | } |
2818 | |
2919 | |
2819 | static void |
2920 | static void |
2820 | coro_semaphore_destroy (pTHX_ struct coro *coro) |
2921 | coro_semaphore_destroy (pTHX_ struct CoroSLF *frame) |
2821 | { |
2922 | { |
2822 | /* call $sem->adjust (0) to possibly wake up some other waiters */ |
2923 | /* call $sem->adjust (0) to possibly wake up some other waiters */ |
2823 | coro_semaphore_adjust (aTHX_ (AV *)coro->slf_frame.data, 0); |
2924 | coro_semaphore_adjust (aTHX_ (AV *)frame->data, 0); |
2824 | } |
2925 | } |
2825 | |
2926 | |
2826 | static int |
2927 | static int |
2827 | slf_check_semaphore_down_or_wait (pTHX_ struct CoroSLF *frame, int acquire) |
2928 | slf_check_semaphore_down_or_wait (pTHX_ struct CoroSLF *frame, int acquire) |
2828 | { |
2929 | { |
2829 | AV *av = (AV *)frame->data; |
2930 | AV *av = (AV *)frame->data; |
2830 | SV *count_sv = AvARRAY (av)[0]; |
2931 | SV *count_sv = AvARRAY (av)[0]; |
|
|
2932 | SV *coro_hv = SvRV (coro_current); |
2831 | |
2933 | |
2832 | /* if we are about to throw, don't actually acquire the lock, just throw */ |
2934 | /* if we are about to throw, don't actually acquire the lock, just throw */ |
2833 | if (CORO_THROW) |
2935 | if (CORO_THROW) |
2834 | return 0; |
2936 | return 0; |
2835 | else if (SvIVX (count_sv) > 0) |
2937 | else if (SvIVX (count_sv) > 0) |
… | |
… | |
2847 | { |
2949 | { |
2848 | int i; |
2950 | int i; |
2849 | /* if we were woken up but can't down, we look through the whole */ |
2951 | /* if we were woken up but can't down, we look through the whole */ |
2850 | /* waiters list and only add us if we aren't in there already */ |
2952 | /* waiters list and only add us if we aren't in there already */ |
2851 | /* this avoids some degenerate memory usage cases */ |
2953 | /* this avoids some degenerate memory usage cases */ |
2852 | |
2954 | for (i = AvFILLp (av); i > 0; --i) // i > 0 is not an off-by-one bug |
2853 | for (i = 1; i <= AvFILLp (av); ++i) |
|
|
2854 | if (AvARRAY (av)[i] == SvRV (coro_current)) |
2955 | if (AvARRAY (av)[i] == coro_hv) |
2855 | return 1; |
2956 | return 1; |
2856 | |
2957 | |
2857 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
2958 | av_push (av, SvREFCNT_inc (coro_hv)); |
2858 | return 1; |
2959 | return 1; |
2859 | } |
2960 | } |
2860 | } |
2961 | } |
2861 | |
2962 | |
2862 | static int |
2963 | static int |
… | |
… | |
3644 | void |
3745 | void |
3645 | _destroy (Coro::State coro) |
3746 | _destroy (Coro::State coro) |
3646 | CODE: |
3747 | CODE: |
3647 | /* used by the manager thread */ |
3748 | /* used by the manager thread */ |
3648 | coro_state_destroy (aTHX_ coro); |
3749 | coro_state_destroy (aTHX_ coro); |
|
|
3750 | |
|
|
3751 | void |
|
|
3752 | on_destroy (Coro::State coro, SV *cb) |
|
|
3753 | CODE: |
3649 | coro_call_on_destroy (aTHX_ coro); |
3754 | coro_push_on_destroy (aTHX_ coro, newSVsv (cb)); |
|
|
3755 | |
|
|
3756 | void |
|
|
3757 | join (...) |
|
|
3758 | CODE: |
|
|
3759 | CORO_EXECUTE_SLF_XS (slf_init_join); |
3650 | |
3760 | |
3651 | void |
3761 | void |
3652 | terminate (...) |
3762 | terminate (...) |
3653 | CODE: |
3763 | CODE: |
3654 | CORO_EXECUTE_SLF_XS (slf_init_terminate); |
3764 | CORO_EXECUTE_SLF_XS (slf_init_terminate); |