… | |
… | |
252 | #undef VAR |
252 | #undef VAR |
253 | } perl_slots; |
253 | } perl_slots; |
254 | |
254 | |
255 | #define SLOT_COUNT ((sizeof (perl_slots) + sizeof (PERL_CONTEXT) - 1) / sizeof (PERL_CONTEXT)) |
255 | #define SLOT_COUNT ((sizeof (perl_slots) + sizeof (PERL_CONTEXT) - 1) / sizeof (PERL_CONTEXT)) |
256 | |
256 | |
257 | /* this is the per-perl-coro slf frame info */ |
|
|
258 | /* it is treated like other "global" interpreter data */ |
|
|
259 | /* and unfortunately is copied around, so kepe it small */ |
|
|
260 | struct slf_frame |
|
|
261 | { |
|
|
262 | void (*prepare) (struct coro_transfer_args *ta); /* 0 means not yet initialised */ |
|
|
263 | int (*check) (pTHX); |
|
|
264 | }; |
|
|
265 | |
|
|
266 | /* this is a structure representing a perl-level coroutine */ |
257 | /* this is a structure representing a perl-level coroutine */ |
267 | struct coro { |
258 | struct coro { |
268 | /* the C coroutine allocated to this perl coroutine, if any */ |
259 | /* the C coroutine allocated to this perl coroutine, if any */ |
269 | coro_cctx *cctx; |
260 | coro_cctx *cctx; |
270 | |
261 | |
271 | /* process data */ |
262 | /* process data */ |
272 | struct slf_frame slf_frame; /* saved slf frame */ |
263 | struct CoroSLF slf_frame; /* saved slf frame */ |
273 | void *slf_data; |
|
|
274 | AV *mainstack; |
264 | AV *mainstack; |
275 | perl_slots *slot; /* basically the saved sp */ |
265 | perl_slots *slot; /* basically the saved sp */ |
276 | |
266 | |
277 | AV *args; /* data associated with this coroutine (initial args) */ |
267 | AV *args; /* data associated with this coroutine (initial args) */ |
278 | int refcnt; /* coroutines are refcounted, yes */ |
268 | int refcnt; /* coroutines are refcounted, yes */ |
… | |
… | |
294 | }; |
284 | }; |
295 | |
285 | |
296 | typedef struct coro *Coro__State; |
286 | typedef struct coro *Coro__State; |
297 | typedef struct coro *Coro__State_or_hashref; |
287 | typedef struct coro *Coro__State_or_hashref; |
298 | |
288 | |
299 | static struct slf_frame slf_frame; /* the current slf frame */ |
289 | static struct CoroSLF slf_frame; /* the current slf frame */ |
300 | |
290 | |
301 | /** Coro ********************************************************************/ |
291 | /** Coro ********************************************************************/ |
302 | |
292 | |
303 | #define PRIO_MAX 3 |
293 | #define PRIO_MAX 3 |
304 | #define PRIO_HIGH 1 |
294 | #define PRIO_HIGH 1 |
… | |
… | |
526 | |
516 | |
527 | PUTBACK; |
517 | PUTBACK; |
528 | } |
518 | } |
529 | |
519 | |
530 | slf_frame = c->slf_frame; |
520 | slf_frame = c->slf_frame; |
531 | coroapi.slf_data = c->slf_data; |
|
|
532 | } |
521 | } |
533 | |
522 | |
534 | static void |
523 | static void |
535 | save_perl (pTHX_ Coro__State c) |
524 | save_perl (pTHX_ Coro__State c) |
536 | { |
525 | { |
537 | c->slf_data = coroapi.slf_data; |
|
|
538 | c->slf_frame = slf_frame; |
526 | c->slf_frame = slf_frame; |
539 | |
527 | |
540 | { |
528 | { |
541 | dSP; |
529 | dSP; |
542 | I32 cxix = cxstack_ix; |
530 | I32 cxix = cxstack_ix; |
… | |
… | |
1308 | transfer_check (pTHX_ struct coro *prev, struct coro *next) |
1296 | transfer_check (pTHX_ struct coro *prev, struct coro *next) |
1309 | { |
1297 | { |
1310 | if (expect_true (prev != next)) |
1298 | if (expect_true (prev != next)) |
1311 | { |
1299 | { |
1312 | if (expect_false (!(prev->flags & (CF_RUNNING | CF_NEW)))) |
1300 | if (expect_false (!(prev->flags & (CF_RUNNING | CF_NEW)))) |
1313 | croak ("Coro::State::transfer called with non-running/new prev Coro::State, but can only transfer from running or new states"); |
1301 | croak ("Coro::State::transfer called with non-running/new prev Coro::State, but can only transfer from running or new states,"); |
1314 | |
1302 | |
1315 | if (expect_false (next->flags & CF_RUNNING)) |
1303 | if (expect_false (next->flags & CF_RUNNING)) |
1316 | croak ("Coro::State::transfer called with running next Coro::State, but can only transfer to inactive states"); |
1304 | croak ("Coro::State::transfer called with running next Coro::State, but can only transfer to inactive states,"); |
1317 | |
1305 | |
1318 | if (expect_false (next->flags & CF_DESTROYED)) |
1306 | if (expect_false (next->flags & CF_DESTROYED)) |
1319 | croak ("Coro::State::transfer called with destroyed next Coro::State, but can only transfer to inactive states"); |
1307 | croak ("Coro::State::transfer called with destroyed next Coro::State, but can only transfer to inactive states,"); |
1320 | |
1308 | |
1321 | #if !PERL_VERSION_ATLEAST (5,10,0) |
1309 | #if !PERL_VERSION_ATLEAST (5,10,0) |
1322 | if (expect_false (PL_lex_state != LEX_NOTPARSING)) |
1310 | if (expect_false (PL_lex_state != LEX_NOTPARSING)) |
1323 | croak ("Coro::State::transfer called while parsing, but this is not supported in your perl version"); |
1311 | croak ("Coro::State::transfer called while parsing, but this is not supported in your perl version,"); |
1324 | #endif |
1312 | #endif |
1325 | } |
1313 | } |
1326 | } |
1314 | } |
1327 | |
1315 | |
1328 | /* always use the TRANSFER macro */ |
1316 | /* always use the TRANSFER macro */ |
… | |
… | |
1435 | |
1423 | |
1436 | if (coro->mainstack && coro->mainstack != main_mainstack) |
1424 | if (coro->mainstack && coro->mainstack != main_mainstack) |
1437 | { |
1425 | { |
1438 | struct coro temp; |
1426 | struct coro temp; |
1439 | |
1427 | |
1440 | if (coro->flags & CF_RUNNING) |
1428 | assert (("FATAL: tried to destroy currently running coroutine (please report)", !(coro->flags & CF_RUNNING))); |
1441 | croak ("FATAL: tried to destroy currently running coroutine"); |
|
|
1442 | |
1429 | |
1443 | save_perl (aTHX_ &temp); |
1430 | save_perl (aTHX_ &temp); |
1444 | load_perl (aTHX_ coro); |
1431 | load_perl (aTHX_ coro); |
1445 | |
1432 | |
1446 | coro_destruct (aTHX_ coro); |
1433 | coro_destruct (aTHX_ coro); |
… | |
… | |
1718 | if (flags & CC_TRACE) |
1705 | if (flags & CC_TRACE) |
1719 | { |
1706 | { |
1720 | if (!coro->cctx) |
1707 | if (!coro->cctx) |
1721 | coro->cctx = cctx_new_run (); |
1708 | coro->cctx = cctx_new_run (); |
1722 | else if (!(coro->cctx->flags & CC_TRACE)) |
1709 | else if (!(coro->cctx->flags & CC_TRACE)) |
1723 | croak ("cannot enable tracing on coroutine with custom stack"); |
1710 | croak ("cannot enable tracing on coroutine with custom stack,"); |
1724 | |
1711 | |
1725 | coro->cctx->flags |= CC_NOREUSE | (flags & (CC_TRACE | CC_TRACE_ALL)); |
1712 | coro->cctx->flags |= CC_NOREUSE | (flags & (CC_TRACE | CC_TRACE_ALL)); |
1726 | } |
1713 | } |
1727 | else if (coro->cctx && coro->cctx->flags & CC_TRACE) |
1714 | else if (coro->cctx && coro->cctx->flags & CC_TRACE) |
1728 | { |
1715 | { |
… | |
… | |
1833 | static const CV *slf_cv; /* for quick consistency check */ |
1820 | static const CV *slf_cv; /* for quick consistency check */ |
1834 | |
1821 | |
1835 | static UNOP slf_restore; /* restore stack as entersub did, for first-re-run */ |
1822 | static UNOP slf_restore; /* restore stack as entersub did, for first-re-run */ |
1836 | static SV *slf_arg0; |
1823 | static SV *slf_arg0; |
1837 | static SV *slf_arg1; |
1824 | static SV *slf_arg1; |
|
|
1825 | static SV *slf_arg2; |
1838 | |
1826 | |
1839 | /* this restores the stack in the case we patched the entersub, to */ |
1827 | /* this restores the stack in the case we patched the entersub, to */ |
1840 | /* recreate the stack frame as perl will on following calls */ |
1828 | /* recreate the stack frame as perl will on following calls */ |
1841 | /* since entersub cleared the stack */ |
1829 | /* since entersub cleared the stack */ |
1842 | static OP * |
1830 | static OP * |
… | |
… | |
1847 | PUSHMARK (SP); |
1835 | PUSHMARK (SP); |
1848 | |
1836 | |
1849 | EXTEND (SP, 3); |
1837 | EXTEND (SP, 3); |
1850 | if (slf_arg0) PUSHs (sv_2mortal (slf_arg0)); |
1838 | if (slf_arg0) PUSHs (sv_2mortal (slf_arg0)); |
1851 | if (slf_arg1) PUSHs (sv_2mortal (slf_arg1)); |
1839 | if (slf_arg1) PUSHs (sv_2mortal (slf_arg1)); |
|
|
1840 | if (slf_arg2) PUSHs (sv_2mortal (slf_arg2)); |
1852 | PUSHs ((SV *)CvGV (slf_cv)); |
1841 | PUSHs ((SV *)CvGV (slf_cv)); |
1853 | |
1842 | |
1854 | RETURNOP (slf_restore.op_first); |
1843 | RETURNOP (slf_restore.op_first); |
1855 | } |
1844 | } |
1856 | |
1845 | |
1857 | static void |
1846 | static void |
|
|
1847 | slf_prepare_set_stacklevel (pTHX_ struct coro_transfer_args *ta) |
|
|
1848 | { |
|
|
1849 | prepare_set_stacklevel (ta, (struct coro_cctx *)slf_frame.data); |
|
|
1850 | } |
|
|
1851 | |
|
|
1852 | static void |
1858 | slf_init_set_stacklevel (pTHX_ SV **arg, int items) |
1853 | slf_init_set_stacklevel (pTHX_ struct CoroSLF *frame, SV **arg, int items) |
1859 | { |
1854 | { |
1860 | assert (("FATAL: set_stacklevel needs the coro cctx as sole argument", items == 1)); |
1855 | assert (("FATAL: set_stacklevel needs the coro cctx as sole argument", items == 1)); |
1861 | CORO_SLF_DATA = (void *)SvIV (arg [0]); |
|
|
1862 | } |
|
|
1863 | |
1856 | |
|
|
1857 | frame->prepare = slf_prepare_set_stacklevel; |
|
|
1858 | frame->check = slf_check_nop; |
|
|
1859 | frame->data = (void *)SvIV (arg [0]); |
|
|
1860 | } |
|
|
1861 | |
1864 | static void |
1862 | static void |
1865 | slf_prepare_set_stacklevel (pTHX_ struct coro_transfer_args *ta) |
1863 | slf_prepare_transfer (pTHX_ struct coro_transfer_args *ta) |
1866 | { |
1864 | { |
1867 | prepare_set_stacklevel (ta, (struct coro_cctx *)CORO_SLF_DATA); |
1865 | SV **arg = (SV **)slf_frame.data; |
1868 | } |
|
|
1869 | |
1866 | |
|
|
1867 | prepare_transfer (ta, arg [0], arg [1]); |
|
|
1868 | } |
|
|
1869 | |
1870 | static void |
1870 | static void |
1871 | slf_init_transfer (pTHX_ SV **arg, int items) |
1871 | slf_init_transfer (pTHX_ struct CoroSLF *frame, SV **arg, int items) |
1872 | { |
1872 | { |
1873 | if (items != 2) |
1873 | if (items != 2) |
1874 | croak ("Coro::State::transfer (prev, next) expects two arguments, not %d.", items); |
1874 | croak ("Coro::State::transfer (prev, next) expects two arguments, not %d,", items); |
1875 | |
1875 | |
|
|
1876 | frame->prepare = slf_prepare_transfer; |
|
|
1877 | frame->check = slf_check_nop; |
1876 | CORO_SLF_DATA = (void *)arg; /* let's hope it will stay valid */ |
1878 | frame->data = (void *)arg; /* let's hope it will stay valid */ |
1877 | } |
1879 | } |
1878 | |
1880 | |
1879 | static void |
1881 | static void |
1880 | slf_prepare_transfer (pTHX_ struct coro_transfer_args *ta) |
1882 | slf_init_schedule (pTHX_ struct CoroSLF *frame, SV **arg, int items) |
1881 | { |
1883 | { |
1882 | SV **arg = (SV **)CORO_SLF_DATA; |
1884 | frame->prepare = prepare_schedule; |
1883 | |
1885 | frame->check = slf_check_nop; |
1884 | prepare_transfer (ta, arg [0], arg [1]); |
|
|
1885 | } |
1886 | } |
1886 | |
1887 | |
1887 | static void |
1888 | static void |
1888 | slf_init_nop (pTHX_ SV **arg, int items) |
1889 | slf_init_cede (pTHX_ struct CoroSLF *frame, SV **arg, int items) |
1889 | { |
1890 | { |
|
|
1891 | frame->prepare = prepare_cede; |
|
|
1892 | frame->check = slf_check_nop; |
1890 | } |
1893 | } |
1891 | |
1894 | |
1892 | /* slf_prepare_schedule == prepare_schedule */ |
1895 | static void |
1893 | /* slf_prepare_cede == prepare_cede */ |
1896 | slf_init_cede_notself (pTHX_ struct CoroSLF *frame, SV **arg, int items) |
1894 | /* slf_prepare_notself == prepare_notself */ |
1897 | { |
|
|
1898 | frame->prepare = prepare_cede_notself; |
|
|
1899 | frame->check = slf_check_nop; |
|
|
1900 | } |
1895 | |
1901 | |
1896 | /* we hijack an hopefully unused CV flag for our purposes */ |
1902 | /* we hijack an hopefully unused CV flag for our purposes */ |
1897 | #define CVf_SLF 0x4000 |
1903 | #define CVf_SLF 0x4000 |
1898 | |
1904 | |
1899 | /* |
1905 | /* |
… | |
… | |
1905 | static OP * |
1911 | static OP * |
1906 | pp_slf (pTHX) |
1912 | pp_slf (pTHX) |
1907 | { |
1913 | { |
1908 | I32 checkmark; /* mark SP to see how many elements check has pushed */ |
1914 | I32 checkmark; /* mark SP to see how many elements check has pushed */ |
1909 | |
1915 | |
|
|
1916 | /* set up the slf frame, unless it has already been set-up */ |
|
|
1917 | /* the latter happens when a new coro has been started */ |
|
|
1918 | /* or when a new cctx was attached to an existing coroutine */ |
1910 | if (expect_true (!slf_frame.prepare)) |
1919 | if (expect_true (!slf_frame.prepare)) |
1911 | { |
1920 | { |
1912 | /* first iteration */ |
1921 | /* first iteration */ |
1913 | dSP; |
1922 | dSP; |
1914 | SV **arg = PL_stack_base + TOPMARK + 1; |
1923 | SV **arg = PL_stack_base + TOPMARK + 1; |
1915 | int items = SP - arg; /* args without function object */ |
1924 | int items = SP - arg; /* args without function object */ |
1916 | SV *gv = *sp; |
1925 | SV *gv = *sp; |
1917 | struct CoroSLF *slf; |
|
|
1918 | |
1926 | |
1919 | /* do a quick consistency check on the "function" object, and if it isn't */ |
1927 | /* do a quick consistency check on the "function" object, and if it isn't */ |
1920 | /* for us, divert to the real entersub */ |
1928 | /* for us, divert to the real entersub */ |
1921 | if (SvTYPE (gv) != SVt_PVGV || !(CvFLAGS (GvCV (gv)) & CVf_SLF)) |
1929 | if (SvTYPE (gv) != SVt_PVGV || !(CvFLAGS (GvCV (gv)) & CVf_SLF)) |
1922 | return PL_ppaddr[OP_ENTERSUB](aTHX); |
1930 | return PL_ppaddr[OP_ENTERSUB](aTHX); |
… | |
… | |
1932 | items = AvFILLp (av) + 1; |
1940 | items = AvFILLp (av) + 1; |
1933 | } |
1941 | } |
1934 | |
1942 | |
1935 | PUTBACK; |
1943 | PUTBACK; |
1936 | |
1944 | |
1937 | slf = (struct CoroSLF *)CvXSUBANY (GvCV (gv)).any_ptr; |
1945 | ((coro_slf_cb)CvXSUBANY (GvCV (gv)).any_ptr) (aTHX_ &slf_frame, arg, items); |
1938 | slf_frame.prepare = slf->prepare; |
|
|
1939 | slf_frame.check = slf->check; |
|
|
1940 | slf->init (aTHX_ arg, items); |
|
|
1941 | } |
1946 | } |
1942 | |
1947 | |
1943 | /* now interpret the slf_frame */ |
1948 | /* now interpret the slf_frame */ |
1944 | /* we use a callback system not to make the code needlessly */ |
1949 | /* we use a callback system not to make the code needlessly */ |
1945 | /* complicated, but so we can run multiple perl coros from one cctx */ |
1950 | /* complicated, but so we can run multiple perl coros from one cctx */ |
… | |
… | |
1951 | slf_frame.prepare (aTHX_ &ta); |
1956 | slf_frame.prepare (aTHX_ &ta); |
1952 | TRANSFER (ta, 0); |
1957 | TRANSFER (ta, 0); |
1953 | |
1958 | |
1954 | checkmark = PL_stack_sp - PL_stack_base; |
1959 | checkmark = PL_stack_sp - PL_stack_base; |
1955 | } |
1960 | } |
1956 | while (slf_frame.check (aTHX)); |
1961 | while (slf_frame.check (aTHX_ &slf_frame)); |
1957 | |
1962 | |
1958 | { |
1963 | { |
1959 | dSP; |
1964 | dSP; |
1960 | SV **bot = PL_stack_base + checkmark; |
1965 | SV **bot = PL_stack_base + checkmark; |
1961 | int gimme = GIMME_V; |
1966 | int gimme = GIMME_V; |
… | |
… | |
1976 | |
1981 | |
1977 | return NORMAL; |
1982 | return NORMAL; |
1978 | } |
1983 | } |
1979 | |
1984 | |
1980 | static void |
1985 | static void |
1981 | api_execute_slf (pTHX_ CV *cv, const struct CoroSLF *slf, SV **arg, int items) |
1986 | api_execute_slf (pTHX_ CV *cv, coro_slf_cb init_cb, SV **arg, int items) |
1982 | { |
1987 | { |
1983 | assert (("FATAL: SLF call recursion in Coro module (please report)", PL_op->op_ppaddr != pp_slf)); |
|
|
1984 | assert (("FATAL: SLF call with illegal CV value", !CvANON (cv))); |
1988 | assert (("FATAL: SLF call with illegal CV value", !CvANON (cv))); |
1985 | |
1989 | |
|
|
1990 | if (PL_op->op_ppaddr != PL_ppaddr [OP_ENTERSUB] |
|
|
1991 | && PL_op->op_ppaddr != pp_slf) |
|
|
1992 | croak ("FATAL: Coro SLF calls can only be made normally, not via goto or any other means, caught"); |
|
|
1993 | |
1986 | if (items > 2) |
1994 | if (items > 3) |
1987 | croak ("Coro only supports a max of two arguments to SLF functions."); |
1995 | croak ("Coro only supports up to three arguments to SLF functions currently (not %d), caught", items); |
1988 | |
1996 | |
1989 | CvFLAGS (cv) |= CVf_SLF; |
1997 | CvFLAGS (cv) |= CVf_SLF; |
1990 | CvXSUBANY (cv).any_ptr = (void *)slf; |
1998 | CvXSUBANY (cv).any_ptr = (void *)init_cb; |
1991 | slf_cv = cv; |
1999 | slf_cv = cv; |
1992 | |
2000 | |
1993 | /* we patch the op, and then re-run the whole call */ |
2001 | /* we patch the op, and then re-run the whole call */ |
1994 | /* we have to put the same argument on the stack for this to work */ |
2002 | /* we have to put the same argument on the stack for this to work */ |
1995 | /* and this will be done by pp_restore */ |
2003 | /* and this will be done by pp_restore */ |
… | |
… | |
1998 | slf_restore.op_ppaddr = pp_restore; |
2006 | slf_restore.op_ppaddr = pp_restore; |
1999 | slf_restore.op_first = PL_op; |
2007 | slf_restore.op_first = PL_op; |
2000 | |
2008 | |
2001 | slf_arg0 = items > 0 ? SvREFCNT_inc (arg [0]) : 0; |
2009 | slf_arg0 = items > 0 ? SvREFCNT_inc (arg [0]) : 0; |
2002 | slf_arg1 = items > 1 ? SvREFCNT_inc (arg [1]) : 0; |
2010 | slf_arg1 = items > 1 ? SvREFCNT_inc (arg [1]) : 0; |
|
|
2011 | slf_arg2 = items > 2 ? SvREFCNT_inc (arg [2]) : 0; |
2003 | |
2012 | |
2004 | PL_op->op_ppaddr = pp_slf; |
2013 | PL_op->op_ppaddr = pp_slf; |
2005 | |
2014 | |
2006 | PL_op = (OP *)&slf_restore; |
2015 | PL_op = (OP *)&slf_restore; |
|
|
2016 | } |
|
|
2017 | |
|
|
2018 | /*****************************************************************************/ |
|
|
2019 | |
|
|
2020 | static int |
|
|
2021 | slf_check_semaphore_down (pTHX_ struct CoroSLF *frame) |
|
|
2022 | { |
|
|
2023 | AV *av = (AV *)frame->data; |
|
|
2024 | SV *count_sv = AvARRAY (av)[0]; |
|
|
2025 | |
|
|
2026 | if (SvIVX (count_sv) > 0) |
|
|
2027 | { |
|
|
2028 | SvIVX (count_sv) = SvIVX (count_sv) - 1; |
|
|
2029 | return 0; |
|
|
2030 | } |
|
|
2031 | else |
|
|
2032 | { |
|
|
2033 | int i; |
|
|
2034 | /* if we were woken up but can't down, we look through the whole */ |
|
|
2035 | /* waiters list and only add us if we aren't in there already */ |
|
|
2036 | /* this avoids some degenerate memory usage cases */ |
|
|
2037 | |
|
|
2038 | for (i = 1; i <= AvFILLp (av); ++i) |
|
|
2039 | if (AvARRAY (av)[i] == SvRV (coro_current)) |
|
|
2040 | return 1; |
|
|
2041 | |
|
|
2042 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
|
|
2043 | return 1; |
|
|
2044 | } |
|
|
2045 | } |
|
|
2046 | |
|
|
2047 | static void |
|
|
2048 | slf_init_semaphore_down (pTHX_ struct CoroSLF *frame, SV **arg, int items) |
|
|
2049 | { |
|
|
2050 | AV *av = (AV *)SvRV (arg [0]); |
|
|
2051 | |
|
|
2052 | if (SvIVX (AvARRAY (av)[0]) > 0) |
|
|
2053 | { |
|
|
2054 | frame->data = (void *)av; |
|
|
2055 | frame->prepare = prepare_nop; |
|
|
2056 | } |
|
|
2057 | else |
|
|
2058 | { |
|
|
2059 | av_push (av, SvREFCNT_inc (SvRV (coro_current))); |
|
|
2060 | |
|
|
2061 | frame->data = (void *)sv_2mortal (SvREFCNT_inc ((SV *)av)); |
|
|
2062 | frame->prepare = prepare_schedule; |
|
|
2063 | } |
|
|
2064 | |
|
|
2065 | frame->check = slf_check_semaphore_down; |
|
|
2066 | |
2007 | } |
2067 | } |
2008 | |
2068 | |
2009 | MODULE = Coro::State PACKAGE = Coro::State PREFIX = api_ |
2069 | MODULE = Coro::State PACKAGE = Coro::State PREFIX = api_ |
2010 | |
2070 | |
2011 | PROTOTYPES: DISABLE |
2071 | PROTOTYPES: DISABLE |
… | |
… | |
2044 | while (main_top_env->je_prev) |
2104 | while (main_top_env->je_prev) |
2045 | main_top_env = main_top_env->je_prev; |
2105 | main_top_env = main_top_env->je_prev; |
2046 | |
2106 | |
2047 | coroapi.ver = CORO_API_VERSION; |
2107 | coroapi.ver = CORO_API_VERSION; |
2048 | coroapi.rev = CORO_API_REVISION; |
2108 | coroapi.rev = CORO_API_REVISION; |
|
|
2109 | |
2049 | coroapi.transfer = api_transfer; |
2110 | coroapi.transfer = api_transfer; |
|
|
2111 | |
|
|
2112 | coroapi.sv_state = SvSTATE_; |
2050 | coroapi.execute_slf = api_execute_slf; |
2113 | coroapi.execute_slf = api_execute_slf; |
2051 | coroapi.sv_state = SvSTATE_; |
2114 | coroapi.prepare_nop = prepare_nop; |
|
|
2115 | coroapi.prepare_schedule = prepare_schedule; |
|
|
2116 | coroapi.prepare_cede = prepare_cede; |
|
|
2117 | coroapi.prepare_cede_notself = prepare_cede_notself; |
2052 | |
2118 | |
2053 | { |
2119 | { |
2054 | SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0); |
2120 | SV **svp = hv_fetch (PL_modglobal, "Time::NVtime", 12, 0); |
2055 | |
2121 | |
2056 | if (!svp) croak ("Time::HiRes is required"); |
2122 | if (!svp) croak ("Time::HiRes is required"); |
… | |
… | |
2092 | RETVAL |
2158 | RETVAL |
2093 | |
2159 | |
2094 | void |
2160 | void |
2095 | _set_stacklevel (...) |
2161 | _set_stacklevel (...) |
2096 | CODE: |
2162 | CODE: |
2097 | { |
|
|
2098 | static struct CoroSLF slf = { slf_init_set_stacklevel, slf_prepare_set_stacklevel, slf_check_nop }; |
|
|
2099 | api_execute_slf (aTHX_ cv, &slf, &ST (0), items); |
2163 | api_execute_slf (aTHX_ cv, slf_init_set_stacklevel, &ST (0), items); |
2100 | } |
|
|
2101 | |
2164 | |
2102 | void |
2165 | void |
2103 | transfer (...) |
2166 | transfer (...) |
|
|
2167 | PROTOTYPE: $$ |
2104 | CODE: |
2168 | CODE: |
2105 | { |
|
|
2106 | static struct CoroSLF slf = { slf_init_transfer, slf_prepare_transfer, slf_check_nop }; |
|
|
2107 | api_execute_slf (aTHX_ cv, &slf, &ST (0), items); |
2169 | api_execute_slf (aTHX_ cv, slf_init_transfer, &ST (0), items); |
2108 | } |
|
|
2109 | |
2170 | |
2110 | bool |
2171 | bool |
2111 | _destroy (SV *coro_sv) |
2172 | _destroy (SV *coro_sv) |
2112 | CODE: |
2173 | CODE: |
2113 | RETVAL = coro_state_destroy (aTHX_ SvSTATE (coro_sv)); |
2174 | RETVAL = coro_state_destroy (aTHX_ SvSTATE (coro_sv)); |
… | |
… | |
2120 | CODE: |
2181 | CODE: |
2121 | _exit (code); |
2182 | _exit (code); |
2122 | |
2183 | |
2123 | int |
2184 | int |
2124 | cctx_stacksize (int new_stacksize = 0) |
2185 | cctx_stacksize (int new_stacksize = 0) |
|
|
2186 | PROTOTYPE: ;$ |
2125 | CODE: |
2187 | CODE: |
2126 | RETVAL = cctx_stacksize; |
2188 | RETVAL = cctx_stacksize; |
2127 | if (new_stacksize) |
2189 | if (new_stacksize) |
2128 | { |
2190 | { |
2129 | cctx_stacksize = new_stacksize; |
2191 | cctx_stacksize = new_stacksize; |
… | |
… | |
2132 | OUTPUT: |
2194 | OUTPUT: |
2133 | RETVAL |
2195 | RETVAL |
2134 | |
2196 | |
2135 | int |
2197 | int |
2136 | cctx_max_idle (int max_idle = 0) |
2198 | cctx_max_idle (int max_idle = 0) |
|
|
2199 | PROTOTYPE: ;$ |
2137 | CODE: |
2200 | CODE: |
2138 | RETVAL = cctx_max_idle; |
2201 | RETVAL = cctx_max_idle; |
2139 | if (max_idle > 1) |
2202 | if (max_idle > 1) |
2140 | cctx_max_idle = max_idle; |
2203 | cctx_max_idle = max_idle; |
2141 | OUTPUT: |
2204 | OUTPUT: |
2142 | RETVAL |
2205 | RETVAL |
2143 | |
2206 | |
2144 | int |
2207 | int |
2145 | cctx_count () |
2208 | cctx_count () |
|
|
2209 | PROTOTYPE: |
2146 | CODE: |
2210 | CODE: |
2147 | RETVAL = cctx_count; |
2211 | RETVAL = cctx_count; |
2148 | OUTPUT: |
2212 | OUTPUT: |
2149 | RETVAL |
2213 | RETVAL |
2150 | |
2214 | |
2151 | int |
2215 | int |
2152 | cctx_idle () |
2216 | cctx_idle () |
|
|
2217 | PROTOTYPE: |
2153 | CODE: |
2218 | CODE: |
2154 | RETVAL = cctx_idle; |
2219 | RETVAL = cctx_idle; |
2155 | OUTPUT: |
2220 | OUTPUT: |
2156 | RETVAL |
2221 | RETVAL |
2157 | |
2222 | |
2158 | void |
2223 | void |
2159 | list () |
2224 | list () |
|
|
2225 | PROTOTYPE: |
2160 | PPCODE: |
2226 | PPCODE: |
2161 | { |
2227 | { |
2162 | struct coro *coro; |
2228 | struct coro *coro; |
2163 | for (coro = coro_first; coro; coro = coro->next) |
2229 | for (coro = coro_first; coro; coro = coro->next) |
2164 | if (coro->hv) |
2230 | if (coro->hv) |
… | |
… | |
2231 | SvREFCNT_dec (self->throw); |
2297 | SvREFCNT_dec (self->throw); |
2232 | self->throw = SvOK (throw) ? newSVsv (throw) : 0; |
2298 | self->throw = SvOK (throw) ? newSVsv (throw) : 0; |
2233 | |
2299 | |
2234 | void |
2300 | void |
2235 | api_trace (SV *coro, int flags = CC_TRACE | CC_TRACE_SUB) |
2301 | api_trace (SV *coro, int flags = CC_TRACE | CC_TRACE_SUB) |
|
|
2302 | PROTOTYPE: $;$ |
2236 | C_ARGS: aTHX_ coro, flags |
2303 | C_ARGS: aTHX_ coro, flags |
2237 | |
2304 | |
2238 | SV * |
2305 | SV * |
2239 | has_cctx (Coro::State coro) |
2306 | has_cctx (Coro::State coro) |
2240 | PROTOTYPE: $ |
2307 | PROTOTYPE: $ |
… | |
… | |
2265 | OUTPUT: |
2332 | OUTPUT: |
2266 | RETVAL |
2333 | RETVAL |
2267 | |
2334 | |
2268 | void |
2335 | void |
2269 | force_cctx () |
2336 | force_cctx () |
|
|
2337 | PROTOTYPE: |
2270 | CODE: |
2338 | CODE: |
2271 | struct coro *coro = SvSTATE (coro_current); |
2339 | struct coro *coro = SvSTATE (coro_current); |
2272 | coro->cctx->idle_sp = 0; |
2340 | coro->cctx->idle_sp = 0; |
2273 | |
2341 | |
2274 | void |
2342 | void |
… | |
… | |
2276 | PROTOTYPE: $ |
2344 | PROTOTYPE: $ |
2277 | ALIAS: |
2345 | ALIAS: |
2278 | swap_defav = 1 |
2346 | swap_defav = 1 |
2279 | CODE: |
2347 | CODE: |
2280 | if (!self->slot) |
2348 | if (!self->slot) |
2281 | croak ("cannot swap state with coroutine that has no saved state"); |
2349 | croak ("cannot swap state with coroutine that has no saved state,"); |
2282 | else |
2350 | else |
2283 | { |
2351 | { |
2284 | SV **src = ix ? (SV **)&GvAV (PL_defgv) : &GvSV (PL_defgv); |
2352 | SV **src = ix ? (SV **)&GvAV (PL_defgv) : &GvSV (PL_defgv); |
2285 | SV **dst = ix ? (SV **)&self->slot->defav : (SV **)&self->slot->defsv; |
2353 | SV **dst = ix ? (SV **)&self->slot->defav : (SV **)&self->slot->defsv; |
2286 | |
2354 | |
… | |
… | |
2330 | } |
2398 | } |
2331 | |
2399 | |
2332 | void |
2400 | void |
2333 | schedule (...) |
2401 | schedule (...) |
2334 | CODE: |
2402 | CODE: |
2335 | { |
|
|
2336 | static struct CoroSLF slf = { slf_init_nop, prepare_schedule, slf_check_nop }; |
|
|
2337 | api_execute_slf (aTHX_ cv, &slf, &ST (0), items); |
2403 | api_execute_slf (aTHX_ cv, slf_init_schedule, &ST (0), 0); |
2338 | } |
|
|
2339 | |
2404 | |
2340 | void |
2405 | void |
2341 | cede (...) |
2406 | cede (...) |
2342 | CODE: |
2407 | CODE: |
2343 | { |
|
|
2344 | static struct CoroSLF slf = { slf_init_nop, prepare_cede, slf_check_nop }; |
|
|
2345 | api_execute_slf (aTHX_ cv, &slf, &ST (0), items); |
2408 | api_execute_slf (aTHX_ cv, slf_init_cede, &ST (0), 0); |
2346 | } |
|
|
2347 | |
2409 | |
2348 | void |
2410 | void |
2349 | cede_notself (...) |
2411 | cede_notself (...) |
2350 | CODE: |
2412 | CODE: |
2351 | { |
|
|
2352 | static struct CoroSLF slf = { slf_init_nop, prepare_cede_notself, slf_check_nop }; |
|
|
2353 | api_execute_slf (aTHX_ cv, &slf, &ST (0), items); |
2413 | api_execute_slf (aTHX_ cv, slf_init_cede_notself, &ST (0), 0); |
2354 | } |
|
|
2355 | |
2414 | |
2356 | void |
2415 | void |
2357 | _set_current (SV *current) |
2416 | _set_current (SV *current) |
2358 | PROTOTYPE: $ |
2417 | PROTOTYPE: $ |
2359 | CODE: |
2418 | CODE: |
… | |
… | |
2369 | coro_readyhook = SvOK (hook) ? newSVsv (hook) : 0; |
2428 | coro_readyhook = SvOK (hook) ? newSVsv (hook) : 0; |
2370 | UNLOCK; |
2429 | UNLOCK; |
2371 | |
2430 | |
2372 | int |
2431 | int |
2373 | prio (Coro::State coro, int newprio = 0) |
2432 | prio (Coro::State coro, int newprio = 0) |
|
|
2433 | PROTOTYPE: $;$ |
2374 | ALIAS: |
2434 | ALIAS: |
2375 | nice = 1 |
2435 | nice = 1 |
2376 | CODE: |
2436 | CODE: |
2377 | { |
2437 | { |
2378 | RETVAL = coro->prio; |
2438 | RETVAL = coro->prio; |
… | |
… | |
2442 | { |
2502 | { |
2443 | av_fill (defav, len - 1); |
2503 | av_fill (defav, len - 1); |
2444 | for (i = 0; i < len; ++i) |
2504 | for (i = 0; i < len; ++i) |
2445 | av_store (defav, i, SvREFCNT_inc_NN (AvARRAY (invoke_av)[i + 1])); |
2505 | av_store (defav, i, SvREFCNT_inc_NN (AvARRAY (invoke_av)[i + 1])); |
2446 | } |
2506 | } |
2447 | |
|
|
2448 | SvREFCNT_dec (invoke); |
|
|
2449 | } |
2507 | } |
2450 | |
2508 | |
2451 | void |
2509 | void |
2452 | _pool_2 (SV *cb) |
2510 | _pool_2 (SV *cb) |
2453 | CODE: |
2511 | CODE: |
… | |
… | |
2531 | |
2589 | |
2532 | MODULE = Coro::State PACKAGE = Coro::AIO |
2590 | MODULE = Coro::State PACKAGE = Coro::AIO |
2533 | |
2591 | |
2534 | void |
2592 | void |
2535 | _get_state (SV *self) |
2593 | _get_state (SV *self) |
|
|
2594 | PROTOTYPE: $ |
2536 | PPCODE: |
2595 | PPCODE: |
2537 | { |
2596 | { |
2538 | AV *defav = GvAV (PL_defgv); |
2597 | AV *defav = GvAV (PL_defgv); |
2539 | AV *av = newAV (); |
2598 | AV *av = newAV (); |
2540 | int i; |
2599 | int i; |
… | |
… | |
2585 | BOOT: |
2644 | BOOT: |
2586 | sv_activity = coro_get_sv (aTHX_ "Coro::AnyEvent::ACTIVITY", TRUE); |
2645 | sv_activity = coro_get_sv (aTHX_ "Coro::AnyEvent::ACTIVITY", TRUE); |
2587 | |
2646 | |
2588 | SV * |
2647 | SV * |
2589 | _schedule (...) |
2648 | _schedule (...) |
2590 | PROTOTYPE: @ |
|
|
2591 | CODE: |
2649 | CODE: |
2592 | { |
2650 | { |
2593 | static int incede; |
2651 | static int incede; |
2594 | |
2652 | |
2595 | api_cede_notself (aTHX); |
2653 | api_cede_notself (aTHX); |
… | |
… | |
2614 | MODULE = Coro::State PACKAGE = PerlIO::cede |
2672 | MODULE = Coro::State PACKAGE = PerlIO::cede |
2615 | |
2673 | |
2616 | BOOT: |
2674 | BOOT: |
2617 | PerlIO_define_layer (aTHX_ &PerlIO_cede); |
2675 | PerlIO_define_layer (aTHX_ &PerlIO_cede); |
2618 | |
2676 | |
|
|
2677 | MODULE = Coro::State PACKAGE = Coro::Semaphore |
|
|
2678 | |
|
|
2679 | SV * |
|
|
2680 | new (SV *klass, SV *count_ = 0) |
|
|
2681 | CODE: |
|
|
2682 | { |
|
|
2683 | /* a semaphore contains a counter IV in $sem->[0] and any waiters after that */ |
|
|
2684 | AV *av = newAV (); |
|
|
2685 | av_push (av, newSViv (count_ && SvOK (count_) ? SvIV (count_) : 1)); |
|
|
2686 | RETVAL = sv_bless (newRV_noinc ((SV *)av), GvSTASH (CvGV (cv))); |
|
|
2687 | } |
|
|
2688 | OUTPUT: |
|
|
2689 | RETVAL |
|
|
2690 | |
|
|
2691 | SV * |
|
|
2692 | count (SV *self) |
|
|
2693 | CODE: |
|
|
2694 | RETVAL = newSVsv (AvARRAY ((AV *)SvRV (self))[0]); |
|
|
2695 | OUTPUT: |
|
|
2696 | RETVAL |
|
|
2697 | |
|
|
2698 | void |
|
|
2699 | up (SV *self, int adjust = 1) |
|
|
2700 | ALIAS: |
|
|
2701 | adjust = 1 |
|
|
2702 | CODE: |
|
|
2703 | { |
|
|
2704 | AV *av = (AV *)SvRV (self); |
|
|
2705 | SV *count_sv = AvARRAY (av)[0]; |
|
|
2706 | IV count = SvIVX (count_sv); |
|
|
2707 | |
|
|
2708 | count += ix ? adjust : 1; |
|
|
2709 | SvIVX (count_sv) = count; |
|
|
2710 | |
|
|
2711 | /* now wake up as many waiters as possible */ |
|
|
2712 | while (count > 0 && AvFILLp (av) >= count) |
|
|
2713 | { |
|
|
2714 | SV *cb; |
|
|
2715 | |
|
|
2716 | /* swap first two elements so we can shift a waiter */ |
|
|
2717 | AvARRAY (av)[0] = AvARRAY (av)[1]; |
|
|
2718 | AvARRAY (av)[1] = count_sv; |
|
|
2719 | cb = av_shift (av); |
|
|
2720 | |
|
|
2721 | if (SvOBJECT (cb)) |
|
|
2722 | api_ready (cb); |
|
|
2723 | else |
|
|
2724 | croak ("callbacks not yet supported"); |
|
|
2725 | |
|
|
2726 | SvREFCNT_dec (cb); |
|
|
2727 | } |
|
|
2728 | } |
|
|
2729 | |
|
|
2730 | void |
|
|
2731 | down (SV *self) |
|
|
2732 | CODE: |
|
|
2733 | api_execute_slf (aTHX_ cv, slf_init_semaphore_down, &ST (0), 1); |
|
|
2734 | |
|
|
2735 | void |
|
|
2736 | try (SV *self) |
|
|
2737 | PPCODE: |
|
|
2738 | { |
|
|
2739 | AV *av = (AV *)SvRV (self); |
|
|
2740 | SV *count_sv = AvARRAY (av)[0]; |
|
|
2741 | IV count = SvIVX (count_sv); |
|
|
2742 | |
|
|
2743 | if (count > 0) |
|
|
2744 | { |
|
|
2745 | --count; |
|
|
2746 | SvIVX (count_sv) = count; |
|
|
2747 | XSRETURN_YES; |
|
|
2748 | } |
|
|
2749 | else |
|
|
2750 | XSRETURN_NO; |
|
|
2751 | } |
|
|
2752 | |
|
|
2753 | void |
|
|
2754 | waiters (SV *self) |
|
|
2755 | CODE: |
|
|
2756 | { |
|
|
2757 | AV *av = (AV *)SvRV (self); |
|
|
2758 | |
|
|
2759 | if (GIMME_V == G_SCALAR) |
|
|
2760 | XPUSHs (sv_2mortal (newSVsv (AvARRAY (av)[0]))); |
|
|
2761 | else |
|
|
2762 | { |
|
|
2763 | int i; |
|
|
2764 | EXTEND (SP, AvFILLp (av) + 1 - 1); |
|
|
2765 | for (i = 1; i <= AvFILLp (av); ++i) |
|
|
2766 | PUSHs (newSVsv (AvARRAY (av)[i])); |
|
|
2767 | } |
|
|
2768 | } |
|
|
2769 | |