… | |
… | |
145 | #define expect_true(expr) expect ((expr) != 0, 1) |
145 | #define expect_true(expr) expect ((expr) != 0, 1) |
146 | |
146 | |
147 | #define NOINLINE attribute ((noinline)) |
147 | #define NOINLINE attribute ((noinline)) |
148 | |
148 | |
149 | #include "CoroAPI.h" |
149 | #include "CoroAPI.h" |
|
|
150 | #define GCoroAPI (&coroapi) /* very sneaky */ |
150 | |
151 | |
151 | #ifdef USE_ITHREADS |
152 | #ifdef USE_ITHREADS |
152 | # if CORO_PTHREAD |
153 | # if CORO_PTHREAD |
153 | static void *coro_thx; |
154 | static void *coro_thx; |
154 | # endif |
155 | # endif |
… | |
… | |
256 | /* statistics */ |
257 | /* statistics */ |
257 | int usecount; /* number of transfers to this coro */ |
258 | int usecount; /* number of transfers to this coro */ |
258 | |
259 | |
259 | /* coro process data */ |
260 | /* coro process data */ |
260 | int prio; |
261 | int prio; |
261 | SV *throw; /* exception to be thrown */ |
262 | SV *except; /* exception to be thrown */ |
262 | |
263 | |
263 | /* async_pool */ |
264 | /* async_pool */ |
264 | SV *saved_deffh; |
265 | SV *saved_deffh; |
265 | |
266 | |
266 | /* linked list */ |
267 | /* linked list */ |
… | |
… | |
272 | |
273 | |
273 | /* the following variables are effectively part of the perl context */ |
274 | /* the following variables are effectively part of the perl context */ |
274 | /* and get copied between struct coro and these variables */ |
275 | /* and get copied between struct coro and these variables */ |
275 | /* the mainr easonw e don't support windows process emulation */ |
276 | /* the mainr easonw e don't support windows process emulation */ |
276 | static struct CoroSLF slf_frame; /* the current slf frame */ |
277 | static struct CoroSLF slf_frame; /* the current slf frame */ |
277 | static SV *coro_throw; |
|
|
278 | |
278 | |
279 | /** Coro ********************************************************************/ |
279 | /** Coro ********************************************************************/ |
280 | |
280 | |
281 | #define PRIO_MAX 3 |
281 | #define PRIO_MAX 3 |
282 | #define PRIO_HIGH 1 |
282 | #define PRIO_HIGH 1 |
… | |
… | |
511 | |
511 | |
512 | PUTBACK; |
512 | PUTBACK; |
513 | } |
513 | } |
514 | |
514 | |
515 | slf_frame = c->slf_frame; |
515 | slf_frame = c->slf_frame; |
516 | coro_throw = c->throw; |
516 | CORO_THROW = c->except; |
517 | } |
517 | } |
518 | |
518 | |
519 | static void |
519 | static void |
520 | save_perl (pTHX_ Coro__State c) |
520 | save_perl (pTHX_ Coro__State c) |
521 | { |
521 | { |
522 | c->throw = coro_throw; |
522 | c->except = CORO_THROW; |
523 | c->slf_frame = slf_frame; |
523 | c->slf_frame = slf_frame; |
524 | |
524 | |
525 | { |
525 | { |
526 | dSP; |
526 | dSP; |
527 | I32 cxix = cxstack_ix; |
527 | I32 cxix = cxstack_ix; |
… | |
… | |
885 | /* no flags required, as an init function won't be called */ |
885 | /* no flags required, as an init function won't be called */ |
886 | |
886 | |
887 | PL_op = (OP *)&coro_setup_op; |
887 | PL_op = (OP *)&coro_setup_op; |
888 | |
888 | |
889 | /* copy throw, in case it was set before coro_setup */ |
889 | /* copy throw, in case it was set before coro_setup */ |
890 | coro_throw = coro->throw; |
890 | CORO_THROW = coro->except; |
891 | } |
891 | } |
892 | |
892 | |
893 | static void |
893 | static void |
894 | coro_destruct (pTHX_ struct coro *coro) |
894 | coro_destruct (pTHX_ struct coro *coro) |
895 | { |
895 | { |
… | |
… | |
919 | |
919 | |
920 | SvREFCNT_dec (PL_diehook); |
920 | SvREFCNT_dec (PL_diehook); |
921 | SvREFCNT_dec (PL_warnhook); |
921 | SvREFCNT_dec (PL_warnhook); |
922 | |
922 | |
923 | SvREFCNT_dec (coro->saved_deffh); |
923 | SvREFCNT_dec (coro->saved_deffh); |
924 | SvREFCNT_dec (coro_throw); |
924 | SvREFCNT_dec (CORO_THROW); |
925 | |
925 | |
926 | coro_destruct_stacks (aTHX); |
926 | coro_destruct_stacks (aTHX); |
927 | } |
927 | } |
928 | |
928 | |
929 | INLINE void |
929 | INLINE void |
… | |
… | |
1839 | } |
1839 | } |
1840 | while (slf_frame.check (aTHX_ &slf_frame)); |
1840 | while (slf_frame.check (aTHX_ &slf_frame)); |
1841 | |
1841 | |
1842 | slf_frame.prepare = 0; /* invalidate the frame, we are done processing it */ |
1842 | slf_frame.prepare = 0; /* invalidate the frame, we are done processing it */ |
1843 | |
1843 | |
|
|
1844 | /* exception handling */ |
|
|
1845 | if (expect_false (CORO_THROW)) |
|
|
1846 | { |
|
|
1847 | SV *exception = sv_2mortal (CORO_THROW); |
|
|
1848 | |
|
|
1849 | CORO_THROW = 0; |
|
|
1850 | sv_setsv (ERRSV, exception); |
|
|
1851 | croak (0); |
|
|
1852 | } |
|
|
1853 | |
1844 | /* return value handling - mostly like entersub */ |
1854 | /* return value handling - mostly like entersub */ |
1845 | /* make sure we put something on the stack in scalar context */ |
1855 | /* make sure we put something on the stack in scalar context */ |
1846 | if (GIMME_V == G_SCALAR) |
1856 | if (GIMME_V == G_SCALAR) |
1847 | { |
1857 | { |
1848 | dSP; |
1858 | dSP; |
… | |
… | |
1854 | bot [1] = *sp; |
1864 | bot [1] = *sp; |
1855 | |
1865 | |
1856 | SP = bot + 1; |
1866 | SP = bot + 1; |
1857 | |
1867 | |
1858 | PUTBACK; |
1868 | PUTBACK; |
1859 | } |
|
|
1860 | |
|
|
1861 | /* exception handling */ |
|
|
1862 | if (expect_false (coro_throw)) |
|
|
1863 | { |
|
|
1864 | SV *exception = sv_2mortal (coro_throw); |
|
|
1865 | |
|
|
1866 | coro_throw = 0; |
|
|
1867 | sv_setsv (ERRSV, exception); |
|
|
1868 | croak (0); |
|
|
1869 | } |
1869 | } |
1870 | |
1870 | |
1871 | return NORMAL; |
1871 | return NORMAL; |
1872 | } |
1872 | } |
1873 | |
1873 | |
… | |
… | |
2040 | slf_check_semaphore_down (pTHX_ struct CoroSLF *frame) |
2040 | slf_check_semaphore_down (pTHX_ struct CoroSLF *frame) |
2041 | { |
2041 | { |
2042 | AV *av = (AV *)frame->data; |
2042 | AV *av = (AV *)frame->data; |
2043 | SV *count_sv = AvARRAY (av)[0]; |
2043 | SV *count_sv = AvARRAY (av)[0]; |
2044 | |
2044 | |
|
|
2045 | /* if we are about to throw, don't actually acquire the lock, just throw */ |
|
|
2046 | if (CORO_THROW) |
|
|
2047 | return 0; |
2045 | if (SvIVX (count_sv) > 0) |
2048 | else if (SvIVX (count_sv) > 0) |
2046 | { |
2049 | { |
2047 | SvSTATE_current->on_destroy = 0; |
2050 | SvSTATE_current->on_destroy = 0; |
2048 | SvIVX (count_sv) = SvIVX (count_sv) - 1; |
2051 | SvIVX (count_sv) = SvIVX (count_sv) - 1; |
2049 | return 0; |
2052 | return 0; |
2050 | } |
2053 | } |
… | |
… | |
2071 | |
2074 | |
2072 | if (SvIVX (AvARRAY (av)[0]) > 0) |
2075 | if (SvIVX (AvARRAY (av)[0]) > 0) |
2073 | { |
2076 | { |
2074 | frame->data = (void *)av; |
2077 | frame->data = (void *)av; |
2075 | frame->prepare = prepare_nop; |
2078 | frame->prepare = prepare_nop; |
2076 | SvSTATE_current->on_destroy = coro_semaphore_on_destroy; |
|
|
2077 | } |
2079 | } |
2078 | else |
2080 | else |
2079 | { |
2081 | { |
2080 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
2082 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
2081 | |
2083 | |
2082 | frame->data = (void *)sv_2mortal (SvREFCNT_inc ((SV *)av)); |
2084 | frame->data = (void *)sv_2mortal (SvREFCNT_inc ((SV *)av)); |
2083 | frame->prepare = prepare_schedule; |
2085 | frame->prepare = prepare_schedule; |
2084 | |
2086 | |
2085 | /* to avoid race conditions when a woken-up coro gets terminated */ |
2087 | /* to avoid race conditions when a woken-up coro gets terminated */ |
2086 | /* we arrange for a temporary on_destroy that calls adjust (0) */ |
2088 | /* we arrange for a temporary on_destroy that calls adjust (0) */ |
2087 | assert (!SvSTATE_current->on_destroy);//D |
|
|
2088 | SvSTATE_current->on_destroy = coro_semaphore_on_destroy; |
2089 | SvSTATE_current->on_destroy = coro_semaphore_on_destroy; |
2089 | } |
2090 | } |
2090 | |
2091 | |
2091 | frame->check = slf_check_semaphore_down; |
2092 | frame->check = slf_check_semaphore_down; |
2092 | |
2093 | |
… | |
… | |
2169 | |
2170 | |
2170 | static int |
2171 | static int |
2171 | slf_check_aio_req (pTHX_ struct CoroSLF *frame) |
2172 | slf_check_aio_req (pTHX_ struct CoroSLF *frame) |
2172 | { |
2173 | { |
2173 | AV *state = (AV *)frame->data; |
2174 | AV *state = (AV *)frame->data; |
|
|
2175 | |
|
|
2176 | /* if we are about to throw, return early */ |
|
|
2177 | /* this does not cancel the aio request, but at least */ |
|
|
2178 | /* it quickly returns */ |
|
|
2179 | if (CORO_THROW) |
|
|
2180 | return 0; |
2174 | |
2181 | |
2175 | /* one element that is an RV? repeat! */ |
2182 | /* one element that is an RV? repeat! */ |
2176 | if (AvFILLp (state) == 0 && SvROK (AvARRAY (state)[0])) |
2183 | if (AvFILLp (state) == 0 && SvROK (AvARRAY (state)[0])) |
2177 | return 1; |
2184 | return 1; |
2178 | |
2185 | |
… | |
… | |
2510 | throw (Coro::State self, SV *throw = &PL_sv_undef) |
2517 | throw (Coro::State self, SV *throw = &PL_sv_undef) |
2511 | PROTOTYPE: $;$ |
2518 | PROTOTYPE: $;$ |
2512 | CODE: |
2519 | CODE: |
2513 | { |
2520 | { |
2514 | struct coro *current = SvSTATE_current; |
2521 | struct coro *current = SvSTATE_current; |
2515 | SV **throwp = self == current ? &coro_throw : &self->throw; |
2522 | SV **throwp = self == current ? &CORO_THROW : &self->except; |
2516 | SvREFCNT_dec (*throwp); |
2523 | SvREFCNT_dec (*throwp); |
2517 | *throwp = SvOK (throw) ? newSVsv (throw) : 0; |
2524 | *throwp = SvOK (throw) ? newSVsv (throw) : 0; |
2518 | } |
2525 | } |
2519 | |
2526 | |
2520 | void |
2527 | void |
… | |
… | |
2609 | coroapi.ready = api_ready; |
2616 | coroapi.ready = api_ready; |
2610 | coroapi.is_ready = api_is_ready; |
2617 | coroapi.is_ready = api_is_ready; |
2611 | coroapi.nready = coro_nready; |
2618 | coroapi.nready = coro_nready; |
2612 | coroapi.current = coro_current; |
2619 | coroapi.current = coro_current; |
2613 | |
2620 | |
2614 | GCoroAPI = &coroapi; |
2621 | /*GCoroAPI = &coroapi;*/ |
2615 | sv_setiv (sv, (IV)&coroapi); |
2622 | sv_setiv (sv, (IV)&coroapi); |
2616 | SvREADONLY_on (sv); |
2623 | SvREADONLY_on (sv); |
2617 | } |
2624 | } |
2618 | } |
2625 | } |
2619 | |
2626 | |