Coro

 view release on metacpan or  search on metacpan

Coro/State.xs  view on Meta::CPAN

clone (Coro::State coro)
	CODE:
{
#if CORO_CLONE
        struct coro *ncoro = coro_clone (aTHX_ coro);
        MAGIC *mg;
        /* TODO: too much duplication */
        ncoro->hv = newHV ();
        mg = sv_magicext ((SV *)ncoro->hv, 0, CORO_MAGIC_type_state, &coro_state_vtbl, (char *)ncoro, 0);
        mg->mg_flags |= MGf_DUP;
        RETVAL = sv_bless (newRV_noinc ((SV *)ncoro->hv), SvSTASH (coro->hv));
#else
        croak ("Coro::State->clone has not been configured into this installation of Coro, realised");
#endif
}
	OUTPUT:
        RETVAL

int
cctx_stacksize (int new_stacksize = 0)
	PROTOTYPE: ;$
	CODE:
        RETVAL = cctx_stacksize;
        if (new_stacksize)
          {
            cctx_stacksize = new_stacksize;
            ++cctx_gen;
          }
	OUTPUT:
        RETVAL

int
cctx_max_idle (int max_idle = 0)
	PROTOTYPE: ;$
	CODE:
        RETVAL = cctx_max_idle;
        if (max_idle > 1)
          cctx_max_idle = max_idle;
	OUTPUT:
        RETVAL

int
cctx_count ()
	PROTOTYPE:
	CODE:
        RETVAL = cctx_count;
	OUTPUT:
        RETVAL

int
cctx_idle ()
	PROTOTYPE:
	CODE:
        RETVAL = cctx_idle;
	OUTPUT:
        RETVAL

void
list ()
	PROTOTYPE:
	PPCODE:
{
	struct coro *coro;
        for (coro = coro_first; coro; coro = coro->next)
          if (coro->hv)
            XPUSHs (sv_2mortal (newRV_inc ((SV *)coro->hv)));
}

void
call (Coro::State coro, SV *coderef)
	ALIAS:
        eval = 1
	CODE:
{
        if (coro->mainstack && ((coro->flags & CF_RUNNING) || coro->slot))
          {
            struct coro *current = SvSTATE_current;
            struct CoroSLF slf_save;

            if (current != coro)
              {
                PUTBACK;
                save_perl (aTHX_ current);
                load_perl (aTHX_ coro);
                /* the coro is most likely in an active SLF call.
                 * while not strictly required (the code we execute is
                 * not allowed to call any SLF functions), it's cleaner
                 * to reinitialise the slf_frame and restore it later.
                 * This might one day allow us to actually do SLF calls
                 * from code executed here.
                 */
                slf_save = slf_frame;
                slf_frame.prepare = 0;
                SPAGAIN;
              }

            PUSHSTACK;

            PUSHMARK (SP);
            PUTBACK;

            if (ix)
              eval_sv (coderef, 0);
            else
              call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD);

            POPSTACK;
            SPAGAIN;

            if (current != coro)
              {
                PUTBACK;
                slf_frame = slf_save;
                save_perl (aTHX_ coro);
                load_perl (aTHX_ current);
                SPAGAIN;
              }
          }
}

SV *

Coro/State.xs  view on Meta::CPAN

UV
rss (Coro::State coro)
        PROTOTYPE: $
        ALIAS:
        usecount = 1
        CODE:
        switch (ix)
	  {
            case 0: RETVAL = coro_rss (aTHX_ coro); break;
            case 1: RETVAL = coro->usecount;        break;
          }
	OUTPUT:
        RETVAL

void
force_cctx ()
	PROTOTYPE:
	CODE:
        cctx_current->idle_sp = 0;

void
swap_defsv (Coro::State self)
	PROTOTYPE: $
        ALIAS:
        swap_defav = 1
        CODE:
	if (!self->slot)
          croak ("cannot swap state with coroutine that has no saved state,");
        else
          {
            SV **src = ix ? (SV **)&GvAV (PL_defgv) : &GvSV (PL_defgv);
            SV **dst = ix ? (SV **)&self->slot->defav : (SV **)&self->slot->defsv;

            SV *tmp = *src; *src = *dst; *dst = tmp;
          }

void
cancel (Coro::State self)
	CODE:
	coro_state_destroy (aTHX_ self);

SV *
enable_times (int enabled = enable_times)
	CODE:
{
        RETVAL = boolSV (enable_times);

        if (enabled != enable_times)
          {
            enable_times = enabled;

            coro_times_update ();
            (enabled ? coro_times_sub : coro_times_add)(SvSTATE (coro_current));
          }
}
        OUTPUT:
        RETVAL

void
times (Coro::State self)
	PPCODE:
{
	struct coro *current = SvSTATE (coro_current);

        if (ecb_expect_false (current == self))
          {
            coro_times_update ();
            coro_times_add (SvSTATE (coro_current));
          }

        EXTEND (SP, 2);
        PUSHs (sv_2mortal (newSVnv (self->t_real [0] + self->t_real [1] * 1e-9)));
        PUSHs (sv_2mortal (newSVnv (self->t_cpu  [0] + self->t_cpu  [1] * 1e-9)));

        if (ecb_expect_false (current == self))
          coro_times_sub (SvSTATE (coro_current));
}

void
swap_sv (Coro::State coro, SV *sva, SV *svb)
	CODE:
{
        struct coro *current = SvSTATE_current;
        AV *swap_sv;
        int i;

        sva = SvRV (sva);
        svb = SvRV (svb);

        if (current == coro)
          SWAP_SVS_LEAVE (current);

        if (!coro->swap_sv)
          coro->swap_sv = newAV ();

        swap_sv = coro->swap_sv;

        for (i = AvFILLp (swap_sv) - 1; i >= 0; i -= 2)
          {
            SV *a = AvARRAY (swap_sv)[i    ];
            SV *b = AvARRAY (swap_sv)[i + 1];

            if (a == sva && b == svb)
              {
                SvREFCNT_dec_NN (a);
                SvREFCNT_dec_NN (b);

                for (; i <= AvFILLp (swap_sv) - 2; i++)
                  AvARRAY (swap_sv)[i] = AvARRAY (swap_sv)[i + 2];

                AvFILLp (swap_sv) -= 2;

                goto removed;
              }
          }

        av_push (swap_sv, SvREFCNT_inc_NN (sva));
        av_push (swap_sv, SvREFCNT_inc_NN (svb));

	removed:

Coro/State.xs  view on Meta::CPAN


int
prio (Coro::State coro, int newprio = 0)
	PROTOTYPE: $;$
        ALIAS:
        nice = 1
        CODE:
{
        RETVAL = coro->prio;

        if (items > 1)
          {
            if (ix)
              newprio = coro->prio - newprio;

            if (newprio < CORO_PRIO_MIN) newprio = CORO_PRIO_MIN;
            if (newprio > CORO_PRIO_MAX) newprio = CORO_PRIO_MAX;

            coro->prio = newprio;
          }
}
	OUTPUT:
        RETVAL

SV *
ready (SV *self)
        PROTOTYPE: $
	CODE:
        RETVAL = boolSV (api_ready (aTHX_ self));
	OUTPUT:
        RETVAL

int
nready (...)
	PROTOTYPE:
        CODE:
        RETVAL = coro_nready;
	OUTPUT:
        RETVAL

void
suspend (Coro::State self)
	PROTOTYPE: $
	CODE:
        self->flags |= CF_SUSPENDED;

void
resume (Coro::State self)
	PROTOTYPE: $
	CODE:
        self->flags &= ~CF_SUSPENDED;

void
_pool_handler (...)
	CODE:
        CORO_EXECUTE_SLF_XS (slf_init_pool_handler);

void
async_pool (SV *cv, ...)
	PROTOTYPE: &@
        PPCODE:
{
	HV *hv = (HV *)av_pop (av_async_pool);
        AV *av = newAV ();
        SV *cb = ST (0);
        int i;

        av_extend (av, items - 2);
        for (i = 1; i < items; ++i)
          av_push (av, SvREFCNT_inc_NN (ST (i)));

        if ((SV *)hv == &PL_sv_undef)
          {
            SV *sv = coro_new (aTHX_ coro_stash, (SV **)&cv_pool_handler, 1, 1);
            hv = (HV *)SvREFCNT_inc_NN (SvRV (sv));
            SvREFCNT_dec_NN (sv);
          }

        {
          struct coro *coro = SvSTATE_hv (hv);

          assert (!coro->invoke_cb);
          assert (!coro->invoke_av);
          coro->invoke_cb = SvREFCNT_inc (cb);
          coro->invoke_av = av;
        }

        api_ready (aTHX_ (SV *)hv);

        if (GIMME_V != G_VOID)
          XPUSHs (sv_2mortal (newRV_noinc ((SV *)hv)));
        else
          SvREFCNT_dec_NN (hv);
}

SV *
rouse_cb ()
        PROTOTYPE:
	CODE:
        RETVAL = coro_new_rouse_cb (aTHX);
	OUTPUT:
        RETVAL

void
rouse_wait (...)
        PROTOTYPE: ;$
	PPCODE:
        CORO_EXECUTE_SLF_XS (slf_init_rouse_wait);

void
on_enter (SV *block)
	ALIAS:
        on_leave = 1
	PROTOTYPE: &
	CODE:
{
	struct coro *coro = SvSTATE_current;
	AV **avp = ix ? &coro->on_leave : &coro->on_enter;

        block = s_get_cv_croak (block);

        if (!*avp)
          *avp = newAV ();

        av_push (*avp, SvREFCNT_inc (block));

        if (!ix)
          on_enterleave_call (aTHX_ block);

        LEAVE; /* pp_entersub unfortunately forces an ENTER/LEAVE around XS calls */
        SAVEDESTRUCTOR_X (ix ? coro_pop_on_leave : coro_pop_on_enter, (void *)coro);
        ENTER; /* pp_entersub unfortunately forces an ENTER/LEAVE around XS calls */
}


MODULE = Coro::State                PACKAGE = PerlIO::cede

BOOT:
	PerlIO_define_layer (aTHX_ &PerlIO_cede);


MODULE = Coro::State                PACKAGE = Coro::Semaphore

SV *
new (SV *klass, SV *count = 0)
	CODE:
{
	int semcnt = 1;

        if (count)
          {
            SvGETMAGIC (count);

            if (SvOK (count))
              semcnt = SvIV (count);
          }

        RETVAL = sv_bless (
                   coro_waitarray_new (aTHX_ semcnt),
                   GvSTASH (CvGV (cv))
                 );
}
	OUTPUT:
        RETVAL

# helper for Coro::Channel and others
SV *
_alloc (int count)
	CODE:
        RETVAL = coro_waitarray_new (aTHX_ count);
	OUTPUT:
        RETVAL

SV *
count (SV *self)
	CODE:
        RETVAL = newSVsv (AvARRAY ((AV *)SvRV (self))[0]);
	OUTPUT:
        RETVAL

void
up (SV *self)
        CODE:
        coro_semaphore_adjust (aTHX_ (AV *)SvRV (self), 1);

void
adjust (SV *self, int adjust)
        CODE:
        coro_semaphore_adjust (aTHX_ (AV *)SvRV (self), adjust);

void
down (...)
        CODE:
        CORO_EXECUTE_SLF_XS (slf_init_semaphore_down);

void
wait (...)
        CODE:
        CORO_EXECUTE_SLF_XS (slf_init_semaphore_wait);

void
try (SV *self)
        PPCODE:
{
        AV *av = (AV *)SvRV (self);
        SV *count_sv = AvARRAY (av)[0];
        IV count = SvIVX (count_sv);

        if (count > 0)
          {
            --count;
            SvIVX (count_sv) = count;
            XSRETURN_YES;
          }
        else
          XSRETURN_NO;
}

void
waiters (SV *self)
	PPCODE:
{
        AV *av = (AV *)SvRV (self);
        int wcount = AvFILLp (av) + 1 - 1;

        if (GIMME_V == G_SCALAR)
          XPUSHs (sv_2mortal (newSViv (wcount)));
        else
          {
            int i;
            EXTEND (SP, wcount);
            for (i = 1; i <= wcount; ++i)
              PUSHs (sv_2mortal (newRV_inc (AvARRAY (av)[i])));
          }
}

MODULE = Coro::State                PACKAGE = Coro::SemaphoreSet

void
_may_delete (SV *sem, int count, unsigned int extra_refs)
	PPCODE:
{
	AV *av = (AV *)SvRV (sem);

        if (SvREFCNT ((SV *)av) == 1 + extra_refs
            && AvFILLp (av) == 0 /* no waiters, just count */
            && SvIV (AvARRAY (av)[0]) == count)
          XSRETURN_YES;

        XSRETURN_NO;
}

MODULE = Coro::State                PACKAGE = Coro::Signal

SV *
new (SV *klass)
	CODE:
        RETVAL = sv_bless (
                   coro_waitarray_new (aTHX_ 0),
                   GvSTASH (CvGV (cv))
                 );
        OUTPUT:
        RETVAL

void
wait (...)
        CODE:
        CORO_EXECUTE_SLF_XS (slf_init_signal_wait);

void
broadcast (SV *self)
        CODE:
{
	AV *av = (AV *)SvRV (self);
        coro_signal_wake (aTHX_ av, AvFILLp (av));
}

void
send (SV *self)
        CODE:
{
	AV *av = (AV *)SvRV (self);

        if (AvFILLp (av))
          coro_signal_wake (aTHX_ av, 1);
        else
          SvIVX (AvARRAY (av)[0]) = 1; /* remember the signal */
}

IV
awaited (SV *self)
	CODE:
        RETVAL = AvFILLp ((AV *)SvRV (self)) + 1 - 1;
	OUTPUT:
        RETVAL


MODULE = Coro::State                PACKAGE = Coro::AnyEvent

BOOT:
        sv_activity = coro_get_sv (aTHX_ "Coro::AnyEvent::ACTIVITY", TRUE);

Coro/State.xs  view on Meta::CPAN

          {
            PUSHMARK (SP);
            PUTBACK;
            call_pv ("Coro::AnyEvent::_activity", G_KEEPERR | G_EVAL | G_VOID | G_DISCARD);
          }

        --incede;
}


MODULE = Coro::State                PACKAGE = Coro::AIO

void
_register (char *target, char *proto, SV *req)
	CODE:
{
        SV *req_cv = s_get_cv_croak (req);
        /* newXSproto doesn't return the CV on 5.8 */
        CV *slf_cv = newXS (target, coro_aio_req_xs, __FILE__);
        sv_setpv ((SV *)slf_cv, proto);
        sv_magicext ((SV *)slf_cv, (SV *)req_cv, CORO_MAGIC_type_aio, 0, 0, 0);
}

MODULE = Coro::State                PACKAGE = Coro::Select

void
patch_pp_sselect ()
	CODE:
        if (!coro_old_pp_sselect)
          {
            coro_select_select = (SV *)get_cv ("Coro::Select::select", 0);
            coro_old_pp_sselect = PL_ppaddr [OP_SSELECT];
            PL_ppaddr [OP_SSELECT] = coro_pp_sselect;
          }

void
unpatch_pp_sselect ()
	CODE:
        if (coro_old_pp_sselect)
          {
            PL_ppaddr [OP_SSELECT] = coro_old_pp_sselect;
            coro_old_pp_sselect = 0;
          }

MODULE = Coro::State                PACKAGE = Coro::Util

void
_exit (int code)
	CODE:
	_exit (code);

NV
time ()
	CODE:
        RETVAL = nvtime (aTHX);
	OUTPUT:
        RETVAL

NV
gettimeofday ()
	PPCODE:
{
        UV tv [2];
        u2time (aTHX_ tv);
        EXTEND (SP, 2);
        PUSHs (sv_2mortal (newSVuv (tv [0])));
        PUSHs (sv_2mortal (newSVuv (tv [1])));
}



( run in 1.261 second using v1.01-cache-2.11-cpan-71847e10f99 )