Future-AsyncAwait
view release on metacpan or search on metacpan
lib/Future/AsyncAwait.xs view on Meta::CPAN
*/
CV *runcv = curcv;
curcv = cv_copy_flags(runcv, CV_COPY_NULL_LEXICALS);
state = suspendedstate_new(curcv);
HV *premodhookdata = precreate_padix ? (HV *)PAD_SVl(precreate_padix + PRECREATE_MODHOOKDATA) : NULL;
if(premodhookdata) {
state->modhookdata = premodhookdata;
PAD_SVl(precreate_padix + PRECREATE_MODHOOKDATA) = NULL; /* steal it */
}
if(regs) {
if(!state->modhookdata)
state->modhookdata = newHV();
RUN_HOOKS_FWD(post_cv_copy, runcv, curcv, state->modhookdata);
}
TRACEPRINT(" SUSPEND cloned CV->%p\n", curcv);
defer_mortal_curcv = TRUE;
}
else {
TRACEPRINT(" SUSPEND reuse CV\n");
}
state->curcop = PL_curcop;
if(regs)
RUN_HOOKS_REV(pre_suspend, curcv, state->modhookdata);
suspendedstate_suspend(state, origcv);
/* New ones first */
if(regs)
RUN_HOOKS_FWD(post_suspend, curcv, state->modhookdata);
/* Legacy ones after */
{
SV **hookp = hv_fetchs(PL_modglobal, "Future::AsyncAwait/suspendhook", FALSE);
if(hookp && SvOK(*hookp) && SvUV(*hookp)) {
warn("Invoking legacy Future::AsyncAwait suspendhook for POSTSUSPEND phase");
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(precancel) {
I32 i;
for(i = 0; i < av_count(precancel); i++)
future_on_cancel(state->returning_future, AvARRAY(precancel)[i]);
AvFILLp(precancel) = -1;
}
#ifndef HAVE_FUTURE_CHAIN_CANCEL
/* We can't chain the cancellation but we do need a different way to
* invoke the defer and finally blocks
*/
future_on_cancel(state->returning_future, newRV_inc((SV *)curcv));
#endif
}
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);
#ifdef HAVE_FUTURE_CHAIN_CANCEL
future_chain_on_cancel(state->returning_future, state->awaiting_future);
if(!SvROK(state->returning_future))
panic("ARGH we lost state->returning_future for curcv=%p\n", curcv);
#endif
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 XOP xop_pushcancel;
static OP *pp_pushcancel(pTHX)
{
SuspendedState *state = suspendedstate_get(find_runcv(0));
CV *on_cancel = cv_clone((CV *)cSVOP->op_sv);
if(state && state->returning_future) {
future_on_cancel(state->returning_future, newRV_noinc((SV *)on_cancel));
}
else {
PADOFFSET precreate_padix = PL_op->op_targ;
AV *precancel = (AV *)PAD_SVl(precreate_padix + PRECREATE_CANCEL);
av_push(precancel, newRV_noinc((SV *)on_cancel));
}
return PL_op->op_next;
}
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.
( run in 1.885 second using v1.01-cache-2.11-cpan-39bf76dae61 )