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 )