Future-AsyncAwait-Frozen
view release on metacpan or search on metacpan
lib/Future/AsyncAwait/Frozen.c view on Meta::CPAN
f = POPs;
PUTBACK;
}
if(!sv_isobject(f))
croak("Expected a blessed object reference to await");
if(future_is_ready(f)) {
assert(CvDEPTH(curcv) > 0);
TRACEPRINT(" READY\n");
if(state)
state->curcop = NULL;
/* This might throw */
future_get_to_stack(f, GIMME_V);
TRACEPRINT("LEAVE await curcv=%p [%s:%d]\n", curcv, CopFILE(PL_curcop), CopLINE(PL_curcop));
return PL_op->op_next;
}
#ifdef DEBUG_SHOW_STACKS
debug_showstack("Stack before suspend");
#endif
if(!state) {
/* Clone the CV and then attach suspendedstate magic to it */
curcv = cv_dup_for_suspend(curcv);
state = suspendedstate_new(curcv);
TRACEPRINT(" SUSPEND cloned CV->%p\n", curcv);
defer_mortal_curcv = TRUE;
}
else {
TRACEPRINT(" SUSPEND reuse CV\n");
}
state->curcop = PL_curcop;
suspendedstate_suspend(state, origcv);
{
SV **hookp = hv_fetchs(PL_modglobal, "Future::AsyncAwait::Frozen/suspendhook", FALSE);
if(hookp && SvOK(*hookp) && SvUV(*hookp)) {
SuspendHookFunc *hook = INT2PTR(SuspendHookFunc *, SvUV(*hookp));
if(!state->modhookdata)
state->modhookdata = newHV();
(*hook)(aTHX_ FAA_PHASE_POSTSUSPEND, curcv, state->modhookdata);
}
}
CvSTART(curcv) = PL_op; /* resume from here */
future_on_ready(f, curcv);
/* If the Future implementation's ->AWAIT_ON_READY failed to capture this CV
* then we'll segfault later after SvREFCNT_dec() on it. We can at least
* detect that here
*/
if(SvREFCNT(curcv) < 2) {
croak("AWAIT_ON_READY failed to capture the CV");
}
state->awaiting_future = newSVsv(f);
sv_rvweaken(state->awaiting_future);
if(!state->returning_future)
state->returning_future = future_new_from_proto(f);
if(defer_mortal_curcv)
SvREFCNT_dec((SV *)curcv);
PUSHMARK(SP);
mPUSHs(newSVsv(state->returning_future));
PUTBACK;
if(!SvWEAKREF(state->returning_future))
sv_rvweaken(state->returning_future);
if(!SvROK(state->returning_future))
panic("ARGH we lost state->returning_future for curcv=%p\n", curcv);
/* For unknown reasons, doing this on perls 5.20 or 5.22 massively breaks
* everything.
* https://rt.cpan.org/Ticket/Display.html?id=129202#txn-1843918
*/
#if HAVE_PERL_VERSION(5, 24, 0)
future_chain_on_cancel(state->returning_future, state->awaiting_future);
#endif
if(!SvROK(state->returning_future))
panic("ARGH we lost state->returning_future for curcv=%p\n", curcv);
if(!SvROK(state->awaiting_future))
panic("ARGH we lost state->awaiting_future for curcv=%p\n", curcv);
TRACEPRINT("LEAVE await curcv=%p [%s:%d]\n", curcv, CopFILE(PL_curcop), CopLINE(PL_curcop));
return PL_ppaddr[OP_RETURN](aTHX);
}
static OP *newAWAITOP(I32 flags, OP *expr)
{
OP *op = newUNOP(OP_CUSTOM, flags, expr);
op->op_ppaddr = &pp_await;
return op;
}
enum {
NO_FORBID,
FORBID_FOREACH_NONLEXICAL,
FORBID_MAP,
FORBID_GREP,
};
static void check_optree(pTHX_ OP *op, int forbid, COP **last_cop);
static void check_optree(pTHX_ OP *op, int forbid, COP **last_cop)
{
OP *op_first;
OP *kid = NULL;
if(OP_CLASS(op) == OA_COP)
*last_cop = (COP *)op;
switch(op->op_type) {
case OP_LEAVELOOP:
if((op_first = cUNOPx(op)->op_first)->op_type != OP_ENTERITER)
break;
/* This is a foreach loop of some kind. If it's not using a lexical
* iterator variable, disallow await inside the body.
* Check the first child, then apply forbid to the remainder of the body
*/
check_optree(aTHX_ op_first, forbid, last_cop);
kid = OpSIBLING(op_first);
if(!op_first->op_targ)
forbid = FORBID_FOREACH_NONLEXICAL;
break;
( run in 0.994 second using v1.01-cache-2.11-cpan-39bf76dae61 )