… | |
… | |
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 | |
… | |
… | |
2035 | /* call $sem->adjust (0) to possibly wake up some other waiters */ |
2035 | /* call $sem->adjust (0) to possibly wake up some other waiters */ |
2036 | coro_semaphore_adjust (aTHX_ (AV *)coro->slf_frame.data, 0); |
2036 | coro_semaphore_adjust (aTHX_ (AV *)coro->slf_frame.data, 0); |
2037 | } |
2037 | } |
2038 | |
2038 | |
2039 | static int |
2039 | static int |
2040 | slf_check_semaphore_down (pTHX_ struct CoroSLF *frame) |
2040 | slf_check_semaphore_down_or_wait (pTHX_ struct CoroSLF *frame, int acquire) |
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; |
|
|
2051 | |
|
|
2052 | if (acquire) |
2048 | SvIVX (count_sv) = SvIVX (count_sv) - 1; |
2053 | SvIVX (count_sv) = SvIVX (count_sv) - 1; |
|
|
2054 | else |
|
|
2055 | coro_semaphore_adjust (aTHX_ av, 0); |
|
|
2056 | |
2049 | return 0; |
2057 | return 0; |
2050 | } |
2058 | } |
2051 | else |
2059 | else |
2052 | { |
2060 | { |
2053 | int i; |
2061 | int i; |
… | |
… | |
2062 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
2070 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
2063 | return 1; |
2071 | return 1; |
2064 | } |
2072 | } |
2065 | } |
2073 | } |
2066 | |
2074 | |
2067 | static void |
2075 | static int |
|
|
2076 | slf_check_semaphore_down (pTHX_ struct CoroSLF *frame) |
|
|
2077 | { |
|
|
2078 | return slf_check_semaphore_down_or_wait (aTHX_ frame, 1); |
|
|
2079 | } |
|
|
2080 | |
|
|
2081 | static int |
|
|
2082 | slf_check_semaphore_wait (pTHX_ struct CoroSLF *frame) |
|
|
2083 | { |
|
|
2084 | return slf_check_semaphore_down_or_wait (aTHX_ frame, 0); |
|
|
2085 | } |
|
|
2086 | |
|
|
2087 | static void |
2068 | slf_init_semaphore_down (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
2088 | slf_init_semaphore_down_or_wait (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
2069 | { |
2089 | { |
2070 | AV *av = (AV *)SvRV (arg [0]); |
2090 | AV *av = (AV *)SvRV (arg [0]); |
2071 | |
2091 | |
2072 | if (SvIVX (AvARRAY (av)[0]) > 0) |
2092 | if (SvIVX (AvARRAY (av)[0]) > 0) |
2073 | { |
2093 | { |
2074 | frame->data = (void *)av; |
2094 | frame->data = (void *)av; |
2075 | frame->prepare = prepare_nop; |
2095 | frame->prepare = prepare_nop; |
2076 | SvSTATE_current->on_destroy = coro_semaphore_on_destroy; |
|
|
2077 | } |
2096 | } |
2078 | else |
2097 | else |
2079 | { |
2098 | { |
2080 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
2099 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
2081 | |
2100 | |
2082 | frame->data = (void *)sv_2mortal (SvREFCNT_inc ((SV *)av)); |
2101 | frame->data = (void *)sv_2mortal (SvREFCNT_inc ((SV *)av)); |
2083 | frame->prepare = prepare_schedule; |
2102 | frame->prepare = prepare_schedule; |
2084 | |
2103 | |
2085 | /* to avoid race conditions when a woken-up coro gets terminated */ |
2104 | /* to avoid race conditions when a woken-up coro gets terminated */ |
2086 | /* we arrange for a temporary on_destroy that calls adjust (0) */ |
2105 | /* 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; |
2106 | SvSTATE_current->on_destroy = coro_semaphore_on_destroy; |
2089 | } |
2107 | } |
|
|
2108 | } |
2090 | |
2109 | |
|
|
2110 | static void |
|
|
2111 | slf_init_semaphore_down (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
|
|
2112 | { |
|
|
2113 | slf_init_semaphore_down_or_wait (aTHX_ frame, cv, arg, items); |
2091 | frame->check = slf_check_semaphore_down; |
2114 | frame->check = slf_check_semaphore_down; |
|
|
2115 | } |
2092 | |
2116 | |
|
|
2117 | static void |
|
|
2118 | slf_init_semaphore_wait (pTHX_ struct CoroSLF *frame, CV *cv, SV **arg, int items) |
|
|
2119 | { |
|
|
2120 | slf_init_semaphore_down_or_wait (aTHX_ frame, cv, arg, items); |
|
|
2121 | frame->check = slf_check_semaphore_wait; |
2093 | } |
2122 | } |
2094 | |
2123 | |
2095 | /*****************************************************************************/ |
2124 | /*****************************************************************************/ |
2096 | /* gensub: simple closure generation utility */ |
2125 | /* gensub: simple closure generation utility */ |
2097 | |
2126 | |
… | |
… | |
2169 | |
2198 | |
2170 | static int |
2199 | static int |
2171 | slf_check_aio_req (pTHX_ struct CoroSLF *frame) |
2200 | slf_check_aio_req (pTHX_ struct CoroSLF *frame) |
2172 | { |
2201 | { |
2173 | AV *state = (AV *)frame->data; |
2202 | AV *state = (AV *)frame->data; |
|
|
2203 | |
|
|
2204 | /* if we are about to throw, return early */ |
|
|
2205 | /* this does not cancel the aio request, but at least */ |
|
|
2206 | /* it quickly returns */ |
|
|
2207 | if (CORO_THROW) |
|
|
2208 | return 0; |
2174 | |
2209 | |
2175 | /* one element that is an RV? repeat! */ |
2210 | /* one element that is an RV? repeat! */ |
2176 | if (AvFILLp (state) == 0 && SvROK (AvARRAY (state)[0])) |
2211 | if (AvFILLp (state) == 0 && SvROK (AvARRAY (state)[0])) |
2177 | return 1; |
2212 | return 1; |
2178 | |
2213 | |
… | |
… | |
2510 | throw (Coro::State self, SV *throw = &PL_sv_undef) |
2545 | throw (Coro::State self, SV *throw = &PL_sv_undef) |
2511 | PROTOTYPE: $;$ |
2546 | PROTOTYPE: $;$ |
2512 | CODE: |
2547 | CODE: |
2513 | { |
2548 | { |
2514 | struct coro *current = SvSTATE_current; |
2549 | struct coro *current = SvSTATE_current; |
2515 | SV **throwp = self == current ? &coro_throw : &self->throw; |
2550 | SV **throwp = self == current ? &CORO_THROW : &self->except; |
2516 | SvREFCNT_dec (*throwp); |
2551 | SvREFCNT_dec (*throwp); |
2517 | *throwp = SvOK (throw) ? newSVsv (throw) : 0; |
2552 | *throwp = SvOK (throw) ? newSVsv (throw) : 0; |
2518 | } |
2553 | } |
2519 | |
2554 | |
2520 | void |
2555 | void |
… | |
… | |
2609 | coroapi.ready = api_ready; |
2644 | coroapi.ready = api_ready; |
2610 | coroapi.is_ready = api_is_ready; |
2645 | coroapi.is_ready = api_is_ready; |
2611 | coroapi.nready = coro_nready; |
2646 | coroapi.nready = coro_nready; |
2612 | coroapi.current = coro_current; |
2647 | coroapi.current = coro_current; |
2613 | |
2648 | |
2614 | GCoroAPI = &coroapi; |
2649 | /*GCoroAPI = &coroapi;*/ |
2615 | sv_setiv (sv, (IV)&coroapi); |
2650 | sv_setiv (sv, (IV)&coroapi); |
2616 | SvREADONLY_on (sv); |
2651 | SvREADONLY_on (sv); |
2617 | } |
2652 | } |
2618 | } |
2653 | } |
2619 | |
2654 | |
… | |
… | |
2803 | |
2838 | |
2804 | void |
2839 | void |
2805 | down (SV *self) |
2840 | down (SV *self) |
2806 | CODE: |
2841 | CODE: |
2807 | CORO_EXECUTE_SLF_XS (slf_init_semaphore_down); |
2842 | CORO_EXECUTE_SLF_XS (slf_init_semaphore_down); |
|
|
2843 | |
|
|
2844 | void |
|
|
2845 | wait (SV *self) |
|
|
2846 | CODE: |
|
|
2847 | CORO_EXECUTE_SLF_XS (slf_init_semaphore_wait); |
2808 | |
2848 | |
2809 | void |
2849 | void |
2810 | try (SV *self) |
2850 | try (SV *self) |
2811 | PPCODE: |
2851 | PPCODE: |
2812 | { |
2852 | { |