… | |
… | |
131 | #else |
131 | #else |
132 | # define LOCK (void)0 |
132 | # define LOCK (void)0 |
133 | # define UNLOCK (void)0 |
133 | # define UNLOCK (void)0 |
134 | #endif |
134 | #endif |
135 | |
135 | |
136 | #define strpair(const) const, sizeof (const) - 1 |
|
|
137 | |
|
|
138 | /* helper storage struct for Coro::AIO */ |
136 | /* helper storage struct for Coro::AIO */ |
139 | struct io_state |
137 | struct io_state |
140 | { |
138 | { |
141 | int errorno; |
139 | int errorno; |
142 | I32 laststype; |
140 | I32 laststype; |
… | |
… | |
161 | /* async_pool helper stuff */ |
159 | /* async_pool helper stuff */ |
162 | static SV *sv_pool_rss; |
160 | static SV *sv_pool_rss; |
163 | static SV *sv_pool_size; |
161 | static SV *sv_pool_size; |
164 | static AV *av_async_pool; |
162 | static AV *av_async_pool; |
165 | |
163 | |
166 | static struct coro_cctx *cctx_first[3]; /* index by GIMME_V type, void, scalar, array */ |
164 | static struct coro_cctx *cctx_first; |
167 | static int cctx_count, cctx_idle[3]; |
165 | static int cctx_count, cctx_idle; |
168 | |
166 | |
169 | enum { |
167 | enum { |
170 | CC_MAPPED = 0x01, |
168 | CC_MAPPED = 0x01, |
171 | CC_NOREUSE = 0x02, /* throw this away after tracing */ |
169 | CC_NOREUSE = 0x02, /* throw this away after tracing */ |
172 | CC_TRACE = 0x04, |
170 | CC_TRACE = 0x04, |
… | |
… | |
217 | |
215 | |
218 | /* this is a structure representing a perl-level coroutine */ |
216 | /* this is a structure representing a perl-level coroutine */ |
219 | struct coro { |
217 | struct coro { |
220 | /* the c coroutine allocated to this perl coroutine, if any */ |
218 | /* the c coroutine allocated to this perl coroutine, if any */ |
221 | coro_cctx *cctx; |
219 | coro_cctx *cctx; |
222 | int gimme; |
|
|
223 | |
220 | |
224 | /* process data */ |
221 | /* process data */ |
225 | AV *mainstack; |
222 | AV *mainstack; |
226 | perl_slots *slot; /* basically the saved sp */ |
223 | perl_slots *slot; /* basically the saved sp */ |
227 | |
224 | |
… | |
… | |
454 | |
451 | |
455 | #define VAR(name,type) PL_ ## name = slot->name; |
452 | #define VAR(name,type) PL_ ## name = slot->name; |
456 | # include "state.h" |
453 | # include "state.h" |
457 | #undef VAR |
454 | #undef VAR |
458 | |
455 | |
459 | /*hv_store (hv_sig, strpair ("__DIE__" ), SvREFCNT_inc (sv_diehook ), 0);*/ |
456 | /*hv_store (hv_sig, "__DIE__" , sizeof ("__DIE__" ) - 1, SvREFCNT_inc (sv_diehook ), 0);*/ |
460 | /*hv_store (hv_sig, strpair ("__WARN__"), SvREFCNT_inc (sv_warnhook), 0);*/ |
457 | /*hv_store (hv_sig, "__WARN__", sizeof ("__WARN__") - 1, SvREFCNT_inc (sv_warnhook), 0);*/ |
461 | |
458 | |
462 | { |
459 | { |
463 | dSP; |
460 | dSP; |
464 | |
461 | |
465 | CV *cv; |
462 | CV *cv; |
… | |
… | |
688 | PL_curpm = 0; |
685 | PL_curpm = 0; |
689 | PL_curpad = 0; |
686 | PL_curpad = 0; |
690 | PL_localizing = 0; |
687 | PL_localizing = 0; |
691 | PL_dirty = 0; |
688 | PL_dirty = 0; |
692 | PL_restartop = 0; |
689 | PL_restartop = 0; |
693 | PL_diehook = 0; hv_store (hv_sig, strpair ("__DIE__" ), SvREFCNT_inc (sv_diehook ), 0); |
690 | PL_diehook = 0; hv_store (hv_sig, "__DIE__" , sizeof ("__DIE__" ) - 1, SvREFCNT_inc (sv_diehook ), 0); |
694 | PL_warnhook = 0; hv_store (hv_sig, strpair ("__WARN__"), SvREFCNT_inc (sv_warnhook), 0); |
691 | PL_warnhook = 0; hv_store (hv_sig, "__WARN__", sizeof ("__WARN__") - 1, SvREFCNT_inc (sv_warnhook), 0); |
695 | |
692 | |
696 | GvSV (PL_defgv) = newSV (0); |
693 | GvSV (PL_defgv) = newSV (0); |
697 | GvAV (PL_defgv) = coro->args; coro->args = 0; |
694 | GvAV (PL_defgv) = coro->args; coro->args = 0; |
698 | GvSV (PL_errgv) = newSV (0); |
695 | GvSV (PL_errgv) = newSV (0); |
699 | GvSV (irsgv) = newSVpvn ("\n", 1); sv_magic (GvSV (irsgv), (SV *)irsgv, PERL_MAGIC_sv, "/", 0); |
696 | GvSV (irsgv) = newSVpvn ("\n", 1); sv_magic (GvSV (irsgv), (SV *)irsgv, PERL_MAGIC_sv, "/", 0); |
… | |
… | |
712 | XPUSHs (sv_2mortal (av_shift (GvAV (PL_defgv)))); |
709 | XPUSHs (sv_2mortal (av_shift (GvAV (PL_defgv)))); |
713 | PUTBACK; |
710 | PUTBACK; |
714 | PL_op = (OP *)&myop; |
711 | PL_op = (OP *)&myop; |
715 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
712 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
716 | SPAGAIN; |
713 | SPAGAIN; |
717 | |
|
|
718 | /* |
|
|
719 | * now its very tricky. the "tail" of the next transfer might end up |
|
|
720 | * either in a new cctx, or an existing one. |
|
|
721 | * in case of an existing one we have to take care of whatever |
|
|
722 | * entersub and transfer do to the perl stack. |
|
|
723 | */ |
|
|
724 | ENTER; |
|
|
725 | EXTEND (SP, 4); |
|
|
726 | PUSHs ((SV *)0); /* items */ |
|
|
727 | PUSHs ((SV *)0); /* ix, set_stacklevel */ |
|
|
728 | PUSHs ((SV *)(sp - PL_stack_base + 1)); /* ax */ |
|
|
729 | PUSHs ((SV *)0); /* again */ |
|
|
730 | PUTBACK; |
|
|
731 | } |
714 | } |
732 | |
715 | |
733 | /* this newly created coroutine might be run on an existing cctx which most |
716 | /* this newly created coroutine might be run on an existing cctx which most |
734 | * likely was suspended in set_stacklevel, called from entersub. |
717 | * likely was suspended in set_stacklevel, called from entersub. |
735 | * set_stacklevl doesn't do anything on return, but entersub does LEAVE, |
718 | * set_stacklevl doesn't do anything on return, but entersub does LEAVE, |
… | |
… | |
827 | PUSHMARK (SP); |
810 | PUSHMARK (SP); |
828 | PUSHs (&PL_sv_no); |
811 | PUSHs (&PL_sv_no); |
829 | PUSHs (fullname); |
812 | PUSHs (fullname); |
830 | PUSHs (sv_2mortal (newRV_noinc ((SV *)av))); |
813 | PUSHs (sv_2mortal (newRV_noinc ((SV *)av))); |
831 | PUTBACK; |
814 | PUTBACK; |
832 | cb = hv_fetch ((HV *)SvRV (coro_current), strpair ("_trace_sub_cb"), 0); |
815 | cb = hv_fetch ((HV *)SvRV (coro_current), "_trace_sub_cb", sizeof ("_trace_sub_cb") - 1, 0); |
833 | if (cb) call_sv (*cb, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
816 | if (cb) call_sv (*cb, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
834 | SPAGAIN; |
817 | SPAGAIN; |
835 | FREETMPS; |
818 | FREETMPS; |
836 | LEAVE; |
819 | LEAVE; |
837 | PL_runops = runops_trace; |
820 | PL_runops = runops_trace; |
… | |
… | |
866 | PUSHMARK (SP); |
849 | PUSHMARK (SP); |
867 | PUSHs (&PL_sv_yes); |
850 | PUSHs (&PL_sv_yes); |
868 | PUSHs (fullname); |
851 | PUSHs (fullname); |
869 | PUSHs (cx->blk_sub.hasargs ? sv_2mortal (newRV_inc ((SV *)cx->blk_sub.argarray)) : &PL_sv_undef); |
852 | PUSHs (cx->blk_sub.hasargs ? sv_2mortal (newRV_inc ((SV *)cx->blk_sub.argarray)) : &PL_sv_undef); |
870 | PUTBACK; |
853 | PUTBACK; |
871 | cb = hv_fetch ((HV *)SvRV (coro_current), strpair ("_trace_sub_cb"), 0); |
854 | cb = hv_fetch ((HV *)SvRV (coro_current), "_trace_sub_cb", sizeof ("_trace_sub_cb") - 1, 0); |
872 | if (cb) call_sv (*cb, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
855 | if (cb) call_sv (*cb, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
873 | SPAGAIN; |
856 | SPAGAIN; |
874 | FREETMPS; |
857 | FREETMPS; |
875 | LEAVE; |
858 | LEAVE; |
876 | PL_runops = runops_trace; |
859 | PL_runops = runops_trace; |
… | |
… | |
890 | PL_runops = RUNOPS_DEFAULT; |
873 | PL_runops = RUNOPS_DEFAULT; |
891 | PUSHMARK (SP); |
874 | PUSHMARK (SP); |
892 | PUSHs (sv_2mortal (newSVpv (OutCopFILE (oldcop), 0))); |
875 | PUSHs (sv_2mortal (newSVpv (OutCopFILE (oldcop), 0))); |
893 | PUSHs (sv_2mortal (newSViv (CopLINE (oldcop)))); |
876 | PUSHs (sv_2mortal (newSViv (CopLINE (oldcop)))); |
894 | PUTBACK; |
877 | PUTBACK; |
895 | cb = hv_fetch ((HV *)SvRV (coro_current), strpair ("_trace_line_cb"), 0); |
878 | cb = hv_fetch ((HV *)SvRV (coro_current), "_trace_line_cb", sizeof ("_trace_line_cb") - 1, 0); |
896 | if (cb) call_sv (*cb, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
879 | if (cb) call_sv (*cb, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
897 | SPAGAIN; |
880 | SPAGAIN; |
898 | FREETMPS; |
881 | FREETMPS; |
899 | LEAVE; |
882 | LEAVE; |
900 | PL_runops = runops_trace; |
883 | PL_runops = runops_trace; |
… | |
… | |
1039 | |
1022 | |
1040 | /* wether this cctx should be destructed */ |
1023 | /* wether this cctx should be destructed */ |
1041 | #define CCTX_EXPIRED(cctx) ((cctx)->ssize < coro_stacksize || ((cctx)->flags & CC_NOREUSE)) |
1024 | #define CCTX_EXPIRED(cctx) ((cctx)->ssize < coro_stacksize || ((cctx)->flags & CC_NOREUSE)) |
1042 | |
1025 | |
1043 | static coro_cctx * |
1026 | static coro_cctx * |
1044 | cctx_get (pTHX_ int gimme) |
1027 | cctx_get (pTHX) |
1045 | { |
1028 | { |
1046 | while (expect_true (cctx_first[gimme])) |
1029 | while (expect_true (cctx_first)) |
1047 | { |
1030 | { |
1048 | coro_cctx *cctx = cctx_first[gimme]; |
1031 | coro_cctx *cctx = cctx_first; |
1049 | cctx_first[gimme] = cctx->next; |
1032 | cctx_first = cctx->next; |
1050 | --cctx_idle[gimme]; |
1033 | --cctx_idle; |
1051 | |
1034 | |
1052 | if (expect_true (!CCTX_EXPIRED (cctx))) |
1035 | if (expect_true (!CCTX_EXPIRED (cctx))) |
1053 | return cctx; |
1036 | return cctx; |
1054 | |
1037 | |
1055 | cctx_destroy (cctx); |
1038 | cctx_destroy (cctx); |
1056 | } |
1039 | } |
1057 | |
1040 | |
1058 | assert (!gimme); |
|
|
1059 | return cctx_new (); |
1041 | return cctx_new (); |
1060 | } |
1042 | } |
1061 | |
1043 | |
1062 | static void |
1044 | static void |
1063 | cctx_put (coro_cctx *cctx, int gimme) |
1045 | cctx_put (coro_cctx *cctx) |
1064 | { |
1046 | { |
1065 | /* free another cctx if overlimit */ |
1047 | /* free another cctx if overlimit */ |
1066 | if (expect_false (cctx_idle[gimme] >= MAX_IDLE_CCTX)) |
1048 | if (expect_false (cctx_idle >= MAX_IDLE_CCTX)) |
1067 | { |
1049 | { |
1068 | coro_cctx *first = cctx_first[gimme]; |
1050 | coro_cctx *first = cctx_first; |
1069 | cctx_first[gimme] = first->next; |
1051 | cctx_first = first->next; |
1070 | --cctx_idle[gimme]; |
1052 | --cctx_idle; |
1071 | |
1053 | |
1072 | cctx_destroy (first); |
1054 | cctx_destroy (first); |
1073 | } |
1055 | } |
1074 | |
1056 | |
1075 | ++cctx_idle[gimme]; |
1057 | ++cctx_idle; |
1076 | cctx->next = cctx_first[gimme]; |
1058 | cctx->next = cctx_first; |
1077 | cctx_first[gimme] = cctx; |
1059 | cctx_first = cctx; |
1078 | } |
1060 | } |
1079 | |
1061 | |
1080 | /** coroutine switching *****************************************************/ |
1062 | /** coroutine switching *****************************************************/ |
1081 | |
1063 | |
1082 | static void |
1064 | static void |
… | |
… | |
1161 | |
1143 | |
1162 | /* if the cctx is about to be destroyed we need to make sure we won't see it in cctx_get */ |
1144 | /* if the cctx is about to be destroyed we need to make sure we won't see it in cctx_get */ |
1163 | /* without this the next cctx_get might destroy the prev__cctx while still in use */ |
1145 | /* without this the next cctx_get might destroy the prev__cctx while still in use */ |
1164 | if (expect_false (CCTX_EXPIRED (prev__cctx))) |
1146 | if (expect_false (CCTX_EXPIRED (prev__cctx))) |
1165 | if (!next->cctx) |
1147 | if (!next->cctx) |
1166 | next->cctx = cctx_get (aTHX_ next->gimme); |
1148 | next->cctx = cctx_get (aTHX); |
1167 | |
1149 | |
1168 | cctx_put (prev__cctx, prev->gimme); |
1150 | cctx_put (prev__cctx); |
1169 | } |
1151 | } |
1170 | |
1152 | |
1171 | ++next->usecount; |
1153 | ++next->usecount; |
1172 | |
1154 | |
1173 | if (expect_true (!next->cctx)) |
1155 | if (expect_true (!next->cctx)) |
1174 | next->cctx = cctx_get (aTHX_ next->gimme); |
1156 | next->cctx = cctx_get (aTHX); |
1175 | |
1157 | |
1176 | if (expect_false (prev__cctx != next->cctx)) |
1158 | if (expect_false (prev__cctx != next->cctx)) |
1177 | { |
1159 | { |
1178 | prev__cctx->top_env = PL_top_env; |
1160 | prev__cctx->top_env = PL_top_env; |
1179 | PL_top_env = next->cctx->top_env; |
1161 | PL_top_env = next->cctx->top_env; |
… | |
… | |
1528 | |
1510 | |
1529 | hv_sig = coro_get_hv ("SIG", TRUE); |
1511 | hv_sig = coro_get_hv ("SIG", TRUE); |
1530 | sv_diehook = coro_get_sv ("Coro::State::DIEHOOK" , TRUE); |
1512 | sv_diehook = coro_get_sv ("Coro::State::DIEHOOK" , TRUE); |
1531 | sv_warnhook = coro_get_sv ("Coro::State::WARNHOOK", TRUE); |
1513 | sv_warnhook = coro_get_sv ("Coro::State::WARNHOOK", TRUE); |
1532 | |
1514 | |
1533 | if (!PL_diehook ) hv_store (hv_sig, strpair ("__DIE__" ), SvREFCNT_inc (sv_diehook ), 0); |
1515 | if (!PL_diehook ) hv_store (hv_sig, "__DIE__" , sizeof ("__DIE__" ) - 1, SvREFCNT_inc (sv_diehook ), 0); |
1534 | if (!PL_warnhook) hv_store (hv_sig, strpair ("__WARN__"), SvREFCNT_inc (sv_warnhook), 0); |
1516 | if (!PL_warnhook) hv_store (hv_sig, "__WARN__", sizeof ("__WARN__") - 1, SvREFCNT_inc (sv_warnhook), 0); |
1535 | |
1517 | |
1536 | coro_state_stash = gv_stashpv ("Coro::State", TRUE); |
1518 | coro_state_stash = gv_stashpv ("Coro::State", TRUE); |
1537 | |
1519 | |
1538 | newCONSTSUB (coro_state_stash, "CC_TRACE" , newSViv (CC_TRACE)); |
1520 | newCONSTSUB (coro_state_stash, "CC_TRACE" , newSViv (CC_TRACE)); |
1539 | newCONSTSUB (coro_state_stash, "CC_TRACE_SUB" , newSViv (CC_TRACE_SUB)); |
1521 | newCONSTSUB (coro_state_stash, "CC_TRACE_SUB" , newSViv (CC_TRACE_SUB)); |
… | |
… | |
1661 | RETVAL |
1643 | RETVAL |
1662 | |
1644 | |
1663 | int |
1645 | int |
1664 | cctx_idle () |
1646 | cctx_idle () |
1665 | CODE: |
1647 | CODE: |
1666 | RETVAL = cctx_idle[0] + cctx_idle[1] + cctx_idle[2]; |
1648 | RETVAL = cctx_idle; |
1667 | OUTPUT: |
1649 | OUTPUT: |
1668 | RETVAL |
1650 | RETVAL |
1669 | |
1651 | |
1670 | void |
1652 | void |
1671 | list () |
1653 | list () |
… | |
… | |
1705 | eval_sv (coderef, 0); |
1687 | eval_sv (coderef, 0); |
1706 | else |
1688 | else |
1707 | call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
1689 | call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
1708 | |
1690 | |
1709 | POPSTACK; |
1691 | POPSTACK; |
|
|
1692 | SPAGAIN; |
1710 | FREETMPS; |
1693 | FREETMPS; |
1711 | LEAVE; |
1694 | LEAVE; |
1712 | PUTBACK; |
1695 | PUTBACK; |
1713 | } |
1696 | } |
1714 | |
1697 | |
… | |
… | |
1868 | CODE: |
1851 | CODE: |
1869 | { |
1852 | { |
1870 | struct coro *coro = SvSTATE (coro_current); |
1853 | struct coro *coro = SvSTATE (coro_current); |
1871 | HV *hv = (HV *)SvRV (coro_current); |
1854 | HV *hv = (HV *)SvRV (coro_current); |
1872 | AV *defav = GvAV (PL_defgv); |
1855 | AV *defav = GvAV (PL_defgv); |
1873 | SV *invoke = hv_delete (hv, strpair ("_invoke"), 0); |
1856 | SV *invoke = hv_delete (hv, "_invoke", sizeof ("_invoke") - 1, 0); |
1874 | AV *invoke_av; |
1857 | AV *invoke_av; |
1875 | int i, len; |
1858 | int i, len; |
1876 | |
1859 | |
1877 | if (!invoke) |
1860 | if (!invoke) |
1878 | croak ("\3async_pool terminate\2\n"); |
1861 | croak ("\3async_pool terminate\2\n"); |
1879 | |
1862 | |
1880 | SvREFCNT_dec (coro->saved_deffh); |
1863 | SvREFCNT_dec (coro->saved_deffh); |
1881 | coro->saved_deffh = SvREFCNT_inc ((SV *)PL_defoutgv); |
1864 | coro->saved_deffh = SvREFCNT_inc ((SV *)PL_defoutgv); |
1882 | |
1865 | |
1883 | hv_store (hv, "desc", sizeof ("desc") - 1, |
1866 | hv_store (hv, "desc", sizeof ("desc") - 1, |
1884 | newSVpvn (strpair ("[async_pool]")), 0); |
1867 | newSVpvn ("[async_pool]", sizeof ("[async_pool]") - 1), 0); |
1885 | |
1868 | |
1886 | invoke_av = (AV *)SvRV (invoke); |
1869 | invoke_av = (AV *)SvRV (invoke); |
1887 | len = av_len (invoke_av); |
1870 | len = av_len (invoke_av); |
1888 | |
1871 | |
1889 | sv_setsv (cb, AvARRAY (invoke_av)[0]); |
1872 | sv_setsv (cb, AvARRAY (invoke_av)[0]); |
… | |
… | |
1912 | if (coro_rss (aTHX_ coro) > SvIV (sv_pool_rss) |
1895 | if (coro_rss (aTHX_ coro) > SvIV (sv_pool_rss) |
1913 | || av_len (av_async_pool) + 1 >= SvIV (sv_pool_size)) |
1896 | || av_len (av_async_pool) + 1 >= SvIV (sv_pool_size)) |
1914 | croak ("\3async_pool terminate\2\n"); |
1897 | croak ("\3async_pool terminate\2\n"); |
1915 | |
1898 | |
1916 | av_clear (GvAV (PL_defgv)); |
1899 | av_clear (GvAV (PL_defgv)); |
1917 | hv_store ((HV *)SvRV (coro_current), strpair ("desc"), |
1900 | hv_store ((HV *)SvRV (coro_current), "desc", sizeof ("desc") - 1, |
1918 | newSVpvn (strpair ("[async_pool idle]")), 0); |
1901 | newSVpvn ("[async_pool idle]", sizeof ("[async_pool idle]") - 1), 0); |
1919 | |
1902 | |
1920 | coro->prio = 0; |
1903 | coro->prio = 0; |
1921 | |
1904 | |
1922 | if (coro->cctx && (coro->cctx->flags & CC_TRACE)) |
1905 | if (coro->cctx && (coro->cctx->flags & CC_TRACE)) |
1923 | api_trace (coro_current, 0); |
1906 | api_trace (coro_current, 0); |