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 )