ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Coro/Coro/State.xs
(Generate patch)

Comparing Coro/Coro/State.xs (file contents):
Revision 1.268 by root, Fri Nov 14 06:41:41 2008 UTC vs.
Revision 1.270 by root, Fri Nov 14 07:22:11 2008 UTC

299 299
300/* for Coro.pm */ 300/* for Coro.pm */
301static SV *coro_current; 301static SV *coro_current;
302static SV *coro_readyhook; 302static SV *coro_readyhook;
303static AV *coro_ready [PRIO_MAX - PRIO_MIN + 1]; 303static AV *coro_ready [PRIO_MAX - PRIO_MIN + 1];
304static int coro_nready;
305static struct coro *coro_first; 304static struct coro *coro_first;
305#define coro_nready coroapi.nready
306 306
307/** lowlevel stuff **********************************************************/ 307/** lowlevel stuff **********************************************************/
308 308
309static SV * 309static SV *
310coro_get_sv (pTHX_ const char *name, int create) 310coro_get_sv (pTHX_ const char *name, int create)
716 return rss; 716 return rss;
717} 717}
718 718
719/** set stacklevel support **************************************************/ 719/** set stacklevel support **************************************************/
720 720
721/* we sometimes need to create the effect of pp_set_stacklevel calling us */ 721/* we sometimes need to create the effect of pp_slf calling us */
722#define SSL_HEAD (void)0 722#define SLF_HEAD (void)0
723/* we sometimes need to create the effect of leaving via pp_set_stacklevel */ 723/* we sometimes need to create the effect of leaving via pp_slf */
724#define SSL_TAIL set_stacklevel_tail (aTHX) 724#define SLF_TAIL slf_tail (aTHX)
725 725
726INLINE void 726INLINE void
727set_stacklevel_tail (pTHX) 727slf_tail (pTHX)
728{ 728{
729 dSP; 729 dSP;
730 SV **bot = SP; 730 SV **bot = SP;
731 731
732 int gimme = GIMME_V; 732 int gimme = GIMME_V;
885 885
886 /* this newly created coroutine might be run on an existing cctx which most 886 /* this newly created coroutine might be run on an existing cctx which most
887 * likely was suspended in set_stacklevel, called from pp_set_stacklevel, 887 * likely was suspended in set_stacklevel, called from pp_set_stacklevel,
888 * so we have to emulate entering pp_set_stacklevel here. 888 * so we have to emulate entering pp_set_stacklevel here.
889 */ 889 */
890 SSL_HEAD; 890 SLF_HEAD;
891} 891}
892 892
893static void 893static void
894coro_destruct (pTHX_ struct coro *coro) 894coro_destruct (pTHX_ struct coro *coro)
895{ 895{
1131 { 1131 {
1132 dTHX; 1132 dTHX;
1133 1133
1134 /* we are the alternative tail to pp_set_stacklevel */ 1134 /* we are the alternative tail to pp_set_stacklevel */
1135 /* so do the same things here */ 1135 /* so do the same things here */
1136 SSL_TAIL; 1136 SLF_TAIL;
1137 1137
1138 /* we now skip the op that did lead to transfer() */ 1138 /* we now skip the op that did lead to transfer() */
1139 PL_op = PL_op->op_next; 1139 PL_op = PL_op->op_next;
1140 1140
1141 /* inject a fake subroutine call to cctx_init */ 1141 /* inject a fake subroutine call to cctx_init */
1505 ta->next = SvSTATE (next_sv); 1505 ta->next = SvSTATE (next_sv);
1506 TRANSFER_CHECK (*ta); 1506 TRANSFER_CHECK (*ta);
1507} 1507}
1508 1508
1509static void 1509static void
1510api_transfer (SV *prev_sv, SV *next_sv) 1510api_transfer (pTHX_ SV *prev_sv, SV *next_sv)
1511{ 1511{
1512 dTHX;
1513 struct transfer_args ta; 1512 struct transfer_args ta;
1514 1513
1515 prepare_transfer (aTHX_ &ta, prev_sv, next_sv); 1514 prepare_transfer (aTHX_ &ta, prev_sv, next_sv);
1516 TRANSFER (ta, 1); 1515 TRANSFER (ta, 1);
1517} 1516}
1535 1534
1536 return 0; 1535 return 0;
1537} 1536}
1538 1537
1539static int 1538static int
1540api_ready (SV *coro_sv) 1539api_ready (pTHX_ SV *coro_sv)
1541{ 1540{
1542 dTHX;
1543 struct coro *coro; 1541 struct coro *coro;
1544 SV *sv_hook; 1542 SV *sv_hook;
1545 void (*xs_hook)(void); 1543 void (*xs_hook)(void);
1546 1544
1547 if (SvROK (coro_sv)) 1545 if (SvROK (coro_sv))
1585 1583
1586 return 1; 1584 return 1;
1587} 1585}
1588 1586
1589static int 1587static int
1590api_is_ready (SV *coro_sv) 1588api_is_ready (pTHX_ SV *coro_sv)
1591{ 1589{
1592 dTHX;
1593
1594 return !!(SvSTATE (coro_sv)->flags & CF_READY); 1590 return !!(SvSTATE (coro_sv)->flags & CF_READY);
1595} 1591}
1596 1592
1597INLINE void 1593INLINE void
1598prepare_schedule (pTHX_ struct transfer_args *ta) 1594prepare_schedule (pTHX_ struct transfer_args *ta)
1654} 1650}
1655 1651
1656INLINE void 1652INLINE void
1657prepare_cede (pTHX_ struct transfer_args *ta) 1653prepare_cede (pTHX_ struct transfer_args *ta)
1658{ 1654{
1659 api_ready (coro_current); 1655 api_ready (aTHX_ coro_current);
1660 prepare_schedule (aTHX_ ta); 1656 prepare_schedule (aTHX_ ta);
1661} 1657}
1662 1658
1663static void 1659static void
1664prepare_cede_notself (pTHX_ struct transfer_args *ta) 1660prepare_cede_notself (pTHX_ struct transfer_args *ta)
1666 SV *prev = SvRV (coro_current); 1662 SV *prev = SvRV (coro_current);
1667 1663
1668 if (coro_nready) 1664 if (coro_nready)
1669 { 1665 {
1670 prepare_schedule (aTHX_ ta); 1666 prepare_schedule (aTHX_ ta);
1671 api_ready (prev); 1667 api_ready (aTHX_ prev);
1672 } 1668 }
1673 else 1669 else
1674 ta->prev = ta->next = SvSTATE (prev); 1670 ta->prev = ta->next = SvSTATE (prev);
1675} 1671}
1676 1672
1677static void 1673static void
1678api_schedule (void) 1674api_schedule (pTHX)
1679{ 1675{
1680 dTHX;
1681 struct transfer_args ta; 1676 struct transfer_args ta;
1682 1677
1683 prepare_schedule (aTHX_ &ta); 1678 prepare_schedule (aTHX_ &ta);
1684 TRANSFER (ta, 1); 1679 TRANSFER (ta, 1);
1685} 1680}
1686 1681
1687static int 1682static int
1688api_cede (void) 1683api_cede (pTHX)
1689{ 1684{
1690 dTHX;
1691 struct transfer_args ta; 1685 struct transfer_args ta;
1692 1686
1693 prepare_cede (aTHX_ &ta); 1687 prepare_cede (aTHX_ &ta);
1694 1688
1695 if (expect_true (ta.prev != ta.next)) 1689 if (expect_true (ta.prev != ta.next))
1700 else 1694 else
1701 return 0; 1695 return 0;
1702} 1696}
1703 1697
1704static int 1698static int
1705api_cede_notself (void) 1699api_cede_notself (pTHX)
1706{ 1700{
1707 if (coro_nready) 1701 if (coro_nready)
1708 { 1702 {
1709 dTHX;
1710 struct transfer_args ta; 1703 struct transfer_args ta;
1711 1704
1712 prepare_cede_notself (aTHX_ &ta); 1705 prepare_cede_notself (aTHX_ &ta);
1713 TRANSFER (ta, 1); 1706 TRANSFER (ta, 1);
1714 return 1; 1707 return 1;
1716 else 1709 else
1717 return 0; 1710 return 0;
1718} 1711}
1719 1712
1720static void 1713static void
1721api_trace (SV *coro_sv, int flags) 1714api_trace (pTHX_ SV *coro_sv, int flags)
1722{ 1715{
1723 dTHX;
1724 struct coro *coro = SvSTATE (coro_sv); 1716 struct coro *coro = SvSTATE (coro_sv);
1725 1717
1726 if (flags & CC_TRACE) 1718 if (flags & CC_TRACE)
1727 { 1719 {
1728 if (!coro->cctx) 1720 if (!coro->cctx)
1795 PerlIOCede *self = PerlIOSelf (f, PerlIOCede); 1787 PerlIOCede *self = PerlIOSelf (f, PerlIOCede);
1796 double now = nvtime (); 1788 double now = nvtime ();
1797 1789
1798 if (now >= self->next) 1790 if (now >= self->next)
1799 { 1791 {
1800 api_cede (); 1792 api_cede (aTHX);
1801 self->next = now + self->every; 1793 self->next = now + self->every;
1802 } 1794 }
1803 1795
1804 return PerlIOBuf_flush (aTHX_ f); 1796 return PerlIOBuf_flush (aTHX_ f);
1805} 1797}
1836 PerlIOBuf_set_ptrcnt, 1828 PerlIOBuf_set_ptrcnt,
1837}; 1829};
1838 1830
1839/*****************************************************************************/ 1831/*****************************************************************************/
1840 1832
1841static const CV *ssl_cv; /* for quick consistency check */ 1833static const CV *slf_cv; /* for quick consistency check */
1842 1834
1843static UNOP ssl_restore; /* restore stack as entersub did, for first-re-run */ 1835static UNOP slf_restore; /* restore stack as entersub did, for first-re-run */
1844static SV *ssl_arg0; 1836static SV *slf_arg0;
1845static SV *ssl_arg1; 1837static SV *slf_arg1;
1846 1838
1847/* this restores the stack in the case we patched the entersub, to */ 1839/* this restores the stack in the case we patched the entersub, to */
1848/* recreate the stack frame as perl will on following calls */ 1840/* recreate the stack frame as perl will on following calls */
1849/* since entersub cleared the stack */ 1841/* since entersub cleared the stack */
1850static OP * 1842static OP *
1853 dSP; 1845 dSP;
1854 1846
1855 PUSHMARK (SP); 1847 PUSHMARK (SP);
1856 1848
1857 EXTEND (SP, 3); 1849 EXTEND (SP, 3);
1858 if (ssl_arg0) PUSHs (sv_2mortal (ssl_arg0)), ssl_arg0 = 0; 1850 if (slf_arg0) PUSHs (sv_2mortal (slf_arg0));
1859 if (ssl_arg1) PUSHs (sv_2mortal (ssl_arg1)), ssl_arg1 = 0; 1851 if (slf_arg1) PUSHs (sv_2mortal (slf_arg1));
1860 PUSHs ((SV *)CvGV (ssl_cv)); 1852 PUSHs ((SV *)CvGV (slf_cv));
1861 1853
1862 RETURNOP (ssl_restore.op_first); 1854 RETURNOP (slf_restore.op_first);
1863} 1855}
1864 1856
1865#define OPpENTERSUB_SSL 15 /* the part of op_private entersub hopefully doesn't use */ 1857#define OPpENTERSUB_SLF 15 /* the part of op_private entersub hopefully doesn't use */
1858
1859enum {
1860 CORO_SLF_CUSTOM = 0,
1861 CORO_SLF_SET_STACKLEVEL = 1,
1862 CORO_SLF_TRANSFER = 2
1863};
1866 1864
1867/* declare prototype */ 1865/* declare prototype */
1868XS(XS_Coro__State__set_stacklevel); 1866XS(XS_Coro__State__set_stacklevel);
1869 1867
1870/* 1868/*
1871 * these not obviously related functions are all rolled into one 1869 * these not obviously related functions are all rolled into one
1872 * function to increase chances that they all will call transfer with the same 1870 * function to increase chances that they all will call transfer with the same
1873 * stack offset 1871 * stack offset
1872 * SLF stands for "schedule-like-function".
1874 */ 1873 */
1875static OP * 1874static OP *
1876pp_set_stacklevel (pTHX) 1875pp_slf (pTHX)
1877{ 1876{
1878 dSP; 1877 dSP;
1879 struct transfer_args ta; 1878 struct transfer_args ta;
1880 SV **arg = PL_stack_base + TOPMARK + 1; 1879 SV **arg = PL_stack_base + TOPMARK + 1;
1881 int items = SP - arg; /* args without function object */ 1880 int items = SP - arg; /* args without function object */
1881 int ix = PL_op->op_private & OPpENTERSUB_SLF;
1882 struct CoroSLF *slf = 0;
1882 1883
1883 /* do a quick consistency check on the "function" object, and if it isn't */ 1884 /* do a quick consistency check on the "function" object, and if it isn't */
1884 /* for us, divert to the real entersub */ 1885 /* for us, divert to the real entersub */
1885 if (SvTYPE (*sp) != SVt_PVGV || CvXSUB (GvCV (*sp)) != XS_Coro__State__set_stacklevel) 1886 if (SvTYPE (*sp) != SVt_PVGV || CvXSUB (GvCV (*sp)) != XS_Coro__State__set_stacklevel)
1886 return PL_ppaddr[OP_ENTERSUB](aTHX); 1887 return PL_ppaddr[OP_ENTERSUB](aTHX);
1895 arg = AvARRAY (av); 1896 arg = AvARRAY (av);
1896 items = AvFILLp (av) + 1; 1897 items = AvFILLp (av) + 1;
1897 } 1898 }
1898 1899
1899 PUTBACK; 1900 PUTBACK;
1900 switch (PL_op->op_private & OPpENTERSUB_SSL) 1901
1902 if (!ix)
1903 {
1904 slf = (struct CoroSLF *)CvSTART (GvCV (*sp));
1905 ix = slf->prepare (aTHX_ arg, items);
1901 { 1906 }
1902 case 0: 1907
1908 switch (ix)
1909 {
1910 case CORO_SLF_SET_STACKLEVEL:
1903 prepare_set_stacklevel (&ta, (struct coro_cctx *)SvIV (arg [0])); 1911 prepare_set_stacklevel (&ta, (struct coro_cctx *)SvIV (arg [0]));
1904 break; 1912 break;
1905 1913
1906 case 1: 1914 case CORO_SLF_TRANSFER:
1907 if (items != 2) 1915 if (items != 2)
1908 croak ("Coro::State::transfer (prev, next) expects two arguments, not %d.", items); 1916 croak ("Coro::State::transfer (prev, next) expects two arguments, not %d.", items);
1909 1917
1910 prepare_transfer (aTHX_ &ta, arg [0], arg [1]); 1918 prepare_transfer (aTHX_ &ta, arg [0], arg [1]);
1911 break; 1919 break;
1912 1920
1913 case 2: 1921 case CORO_SLF_SCHEDULE:
1914 prepare_schedule (aTHX_ &ta); 1922 prepare_schedule (aTHX_ &ta);
1915 break; 1923 break;
1916 1924
1917 case 3: 1925 case CORO_SLF_CEDE:
1918 prepare_cede (aTHX_ &ta); 1926 prepare_cede (aTHX_ &ta);
1919 break; 1927 break;
1920 1928
1921 case 4: 1929 case CORO_SLF_CEDE_NOTSELF:
1922 prepare_cede_notself (aTHX_ &ta); 1930 prepare_cede_notself (aTHX_ &ta);
1923 break; 1931 break;
1924 }
1925 1932
1933 default:
1934 abort ();
1935 }
1936
1937 do
1926 TRANSFER (ta, 0); 1938 TRANSFER (ta, 0);
1939 while (slf && slf->check (aTHX));
1940
1927 SPAGAIN; 1941 SPAGAIN;
1928 1942
1929skip:
1930 PUTBACK; 1943 PUTBACK;
1931 SSL_TAIL; 1944 SLF_TAIL;
1932 SPAGAIN; 1945 SPAGAIN;
1933 RETURN; 1946 RETURN;
1934} 1947}
1935 1948
1936static void 1949static void
1937coro_ssl_patch (pTHX_ CV *cv, int ix, SV **args, int items) 1950coro_slf_patch (pTHX_ CV *cv, int ix, SV **args, int items)
1938{ 1951{
1939 assert (("FATAL: ssl call recursion in Coro module (please report)", PL_op->op_ppaddr != pp_set_stacklevel)); 1952 assert (("FATAL: SLF call recursion in Coro module (please report)", PL_op->op_ppaddr != pp_slf));
1940 1953
1941 assert (("FATAL: ssl call with illegal CV value", CvGV (cv))); 1954 assert (("FATAL: SLF call with illegal CV value", CvGV (cv)));
1942 ssl_cv = cv; 1955 slf_cv = cv;
1943 1956
1944 /* we patch the op, and then re-run the whole call */ 1957 /* we patch the op, and then re-run the whole call */
1945 /* we have to put some dummy argument on the stack for this to work */ 1958 /* we have to put the same argument on the stack for this to work */
1959 /* and this will be done by pp_restore */
1946 ssl_restore.op_next = (OP *)&ssl_restore; 1960 slf_restore.op_next = (OP *)&slf_restore;
1947 ssl_restore.op_type = OP_NULL; 1961 slf_restore.op_type = OP_NULL;
1948 ssl_restore.op_ppaddr = pp_restore; 1962 slf_restore.op_ppaddr = pp_restore;
1949 ssl_restore.op_first = PL_op; 1963 slf_restore.op_first = PL_op;
1950 1964
1951 ssl_arg0 = items > 0 ? SvREFCNT_inc (args [0]) : 0; 1965 slf_arg0 = items > 0 ? SvREFCNT_inc (args [0]) : 0;
1952 ssl_arg1 = items > 1 ? SvREFCNT_inc (args [1]) : 0; 1966 slf_arg1 = items > 1 ? SvREFCNT_inc (args [1]) : 0;
1953 1967
1954 PL_op->op_ppaddr = pp_set_stacklevel; 1968 PL_op->op_ppaddr = pp_slf;
1955 PL_op->op_private = PL_op->op_private & ~OPpENTERSUB_SSL | ix; /* we potentially share our private flags with entersub */ 1969 PL_op->op_private = PL_op->op_private & ~OPpENTERSUB_SLF | ix; /* we potentially share our private flags with entersub */
1956 1970
1957 PL_op = (OP *)&ssl_restore; 1971 PL_op = (OP *)&slf_restore;
1958} 1972}
1959 1973
1960MODULE = Coro::State PACKAGE = Coro::State PREFIX = api_ 1974MODULE = Coro::State PACKAGE = Coro::State PREFIX = api_
1961 1975
1962PROTOTYPES: DISABLE 1976PROTOTYPES: DISABLE
2041 RETVAL 2055 RETVAL
2042 2056
2043void 2057void
2044_set_stacklevel (...) 2058_set_stacklevel (...)
2045 ALIAS: 2059 ALIAS:
2060 _set_stacklevel = CORO_SLF_SET_STACKLEVEL
2046 Coro::State::transfer = 1 2061 Coro::State::transfer = CORO_SLF_TRANSFER
2047 Coro::schedule = 2 2062 Coro::schedule = CORO_SLF_SCHEDULE
2048 Coro::cede = 3 2063 Coro::cede = CORO_SLF_CEDE
2049 Coro::cede_notself = 4 2064 Coro::cede_notself = CORO_SLF_CEDE_NOTSELF
2050 CODE: 2065 CODE:
2051 coro_ssl_patch (aTHX_ cv, ix, &ST (0), items); 2066 coro_slf_patch (aTHX_ cv, ix, &ST (0), items);
2052 2067
2053bool 2068bool
2054_destroy (SV *coro_sv) 2069_destroy (SV *coro_sv)
2055 CODE: 2070 CODE:
2056 RETVAL = coro_state_destroy (aTHX_ SvSTATE (coro_sv)); 2071 RETVAL = coro_state_destroy (aTHX_ SvSTATE (coro_sv));
2174 SvREFCNT_dec (self->throw); 2189 SvREFCNT_dec (self->throw);
2175 self->throw = SvOK (throw) ? newSVsv (throw) : 0; 2190 self->throw = SvOK (throw) ? newSVsv (throw) : 0;
2176 2191
2177void 2192void
2178api_trace (SV *coro, int flags = CC_TRACE | CC_TRACE_SUB) 2193api_trace (SV *coro, int flags = CC_TRACE | CC_TRACE_SUB)
2194 C_ARGS: aTHX_ coro, flags
2179 2195
2180SV * 2196SV *
2181has_cctx (Coro::State coro) 2197has_cctx (Coro::State coro)
2182 PROTOTYPE: $ 2198 PROTOTYPE: $
2183 CODE: 2199 CODE:
2260 coroapi.schedule = api_schedule; 2276 coroapi.schedule = api_schedule;
2261 coroapi.cede = api_cede; 2277 coroapi.cede = api_cede;
2262 coroapi.cede_notself = api_cede_notself; 2278 coroapi.cede_notself = api_cede_notself;
2263 coroapi.ready = api_ready; 2279 coroapi.ready = api_ready;
2264 coroapi.is_ready = api_is_ready; 2280 coroapi.is_ready = api_is_ready;
2265 coroapi.nready = &coro_nready; 2281 coroapi.nready = coro_nready;
2266 coroapi.current = coro_current; 2282 coroapi.current = coro_current;
2267 2283
2268 GCoroAPI = &coroapi; 2284 GCoroAPI = &coroapi;
2269 sv_setiv (sv, (IV)&coroapi); 2285 sv_setiv (sv, (IV)&coroapi);
2270 SvREADONLY_on (sv); 2286 SvREADONLY_on (sv);
2311 2327
2312SV * 2328SV *
2313ready (SV *self) 2329ready (SV *self)
2314 PROTOTYPE: $ 2330 PROTOTYPE: $
2315 CODE: 2331 CODE:
2316 RETVAL = boolSV (api_ready (self)); 2332 RETVAL = boolSV (api_ready (aTHX_ self));
2317 OUTPUT: 2333 OUTPUT:
2318 RETVAL 2334 RETVAL
2319 2335
2320int 2336int
2321nready (...) 2337nready (...)
2391 newSVpvn ("[async_pool idle]", sizeof ("[async_pool idle]") - 1), 0); 2407 newSVpvn ("[async_pool idle]", sizeof ("[async_pool idle]") - 1), 0);
2392 2408
2393 coro->prio = 0; 2409 coro->prio = 0;
2394 2410
2395 if (coro->cctx && (coro->cctx->flags & CC_TRACE)) 2411 if (coro->cctx && (coro->cctx->flags & CC_TRACE))
2396 api_trace (coro_current, 0); 2412 api_trace (aTHX_ coro_current, 0);
2397 2413
2398 av_push (av_async_pool, newSVsv (coro_current)); 2414 av_push (av_async_pool, newSVsv (coro_current));
2399} 2415}
2400 2416
2401#if 0 2417#if 0
2473 2489
2474 av_push (av, data_sv); 2490 av_push (av, data_sv);
2475 2491
2476 XPUSHs (sv_2mortal (newRV_noinc ((SV *)av))); 2492 XPUSHs (sv_2mortal (newRV_noinc ((SV *)av)));
2477 2493
2478 api_ready (self); 2494 api_ready (aTHX_ self);
2479} 2495}
2480 2496
2481void 2497void
2482_set_state (SV *state) 2498_set_state (SV *state)
2483 PROTOTYPE: $ 2499 PROTOTYPE: $
2508 PROTOTYPE: @ 2524 PROTOTYPE: @
2509 CODE: 2525 CODE:
2510{ 2526{
2511 static int incede; 2527 static int incede;
2512 2528
2513 api_cede_notself (); 2529 api_cede_notself (aTHX);
2514 2530
2515 ++incede; 2531 ++incede;
2516 while (coro_nready >= incede && api_cede ()) 2532 while (coro_nready >= incede && api_cede (aTHX))
2517 ; 2533 ;
2518 2534
2519 sv_setsv (sv_activity, &PL_sv_undef); 2535 sv_setsv (sv_activity, &PL_sv_undef);
2520 if (coro_nready >= incede) 2536 if (coro_nready >= incede)
2521 { 2537 {

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines