Coro

 view release on metacpan or  search on metacpan

Coro/State.xs  view on Meta::CPAN

 
  if (coro->status)
    {
      av = coro->status;
      av_clear (av);
    }
  else
    av = coro->status = newAV ();

  /* items are actually not so common, so optimise for this case */
  if (items)
    {
      int i;

      av_extend (av, items - 1);

      for (i = 0; i < items; ++i)
        av_push (av, SvREFCNT_inc_NN (arg [i]));
    }
}

static void
slf_init_terminate_cancel_common (pTHX_ struct CoroSLF *frame, HV *coro_hv)
{
  av_push (av_destroy, (SV *)newRV_inc ((SV *)coro_hv)); /* RVinc for perl */
  api_ready (aTHX_ sv_manager);

  frame->prepare = prepare_schedule;
  frame->check   = slf_check_repeat;

  /* as a minor optimisation, we could unwind all stacks here */
  /* but that puts extra pressure on pp_slf, and is not worth much */
  /*coro_unwind_stacks (aTHX);*/
}

static void
slf_init_terminate (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
{
  HV *coro_hv = (HV *)SvRV (coro_current);

  coro_set_status (aTHX_ SvSTATE ((SV *)coro_hv), arg, items);
  slf_init_terminate_cancel_common (aTHX_ frame, coro_hv);
}

static void
slf_init_cancel (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items)
{
  HV *coro_hv;
  struct coro *coro;

  if (items <= 0)
    croak ("Coro::cancel called without coro object,");

  coro = SvSTATE (arg [0]);
  coro_hv = coro->hv;

  coro_set_status (aTHX_ coro, arg + 1, items - 1);
 
  if (ecb_expect_false (coro->flags & CF_NOCANCEL))
    {
      /* coro currently busy cancelling something, so just notify it */
      coro->slf_frame.data = (void *)coro;

      frame->prepare = prepare_nop;
      frame->check   = slf_check_nop;
    }
  else if (coro_hv == (HV *)SvRV (coro_current))
    {
      /* cancelling the current coro is allowed, and equals terminate */
      slf_init_terminate_cancel_common (aTHX_ frame, coro_hv);
    }
  else
    {
      struct coro *self = SvSTATE_current;

      if (!self)
        croak ("Coro::cancel called outside of thread content,");

      /* otherwise we cancel directly, purely for speed reasons
       * unfortunately, this requires some magic trickery, as
       * somebody else could cancel us, so we have to fight the cancellation.
       * this is ugly, and hopefully fully worth the extra speed.
       * besides, I can't get the slow-but-safe version working...
       */
      slf_frame.data = 0;
      self->flags |= CF_NOCANCEL;
      coro_state_destroy (aTHX_ coro);
      self->flags &= ~CF_NOCANCEL;

      if (slf_frame.data)
        {
          /* while we were busy we have been cancelled, so terminate */
          slf_init_terminate_cancel_common (aTHX_ frame, self->hv);
        }
      else
        {
          frame->prepare = prepare_nop;
          frame->check   = slf_check_nop;
        }
    }
}

static int
slf_check_safe_cancel (pTHX_ struct CoroSLF *frame)
{
  frame->prepare = 0;
  coro_unwind_stacks (aTHX);

  slf_init_terminate_cancel_common (aTHX_ frame, (HV *)SvRV (coro_current));

  return 1;
}

static int
safe_cancel (pTHX_ struct coro *coro, SV **arg, int items)
{
  if (coro->cctx)
    croak ("coro inside C callback, unable to cancel at this time, caught");

  if (coro->flags & (CF_NEW | CF_ZOMBIE))
    {
      coro_set_status (aTHX_ coro, arg, items);
      coro_state_destroy (aTHX_ coro);
    }
  else
    {
      if (!coro->slf_frame.prepare)
        croak ("coro outside an SLF function, unable to cancel at this time, caught");

      slf_destroy (aTHX_ coro);

      coro_set_status (aTHX_ coro, arg, items);
      coro->slf_frame.prepare = prepare_nop;
      coro->slf_frame.check   = slf_check_safe_cancel;

      api_ready (aTHX_ (SV *)coro->hv);
    }

  return 1;
}

/*****************************************************************************/
/* async pool handler */

static int
slf_check_pool_handler (pTHX_ struct CoroSLF *frame)
{
  HV *hv = (HV *)SvRV (coro_current);
  struct coro *coro = (struct coro *)frame->data;

  if (!coro->invoke_cb)
    return 1; /* loop till we have invoke */



( run in 1.450 second using v1.01-cache-2.11-cpan-ceb78f64989 )