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.209 by root, Wed Oct 10 02:58:17 2007 UTC vs.
Revision 1.211 by root, Wed Oct 10 03:37:58 2007 UTC

161/* async_pool helper stuff */ 161/* async_pool helper stuff */
162static SV *sv_pool_rss; 162static SV *sv_pool_rss;
163static SV *sv_pool_size; 163static SV *sv_pool_size;
164static AV *av_async_pool; 164static AV *av_async_pool;
165 165
166static struct coro_cctx *cctx_first[3]; /* index by GIMME_V type, void, scalar, array */ 166static struct coro_cctx *cctx_first;
167static int cctx_count, cctx_idle[3]; 167static int cctx_count, cctx_idle;
168 168
169enum { 169enum {
170 CC_MAPPED = 0x01, 170 CC_MAPPED = 0x01,
171 CC_NOREUSE = 0x02, /* throw this away after tracing */ 171 CC_NOREUSE = 0x02, /* throw this away after tracing */
172 CC_TRACE = 0x04, 172 CC_TRACE = 0x04,
217 217
218/* this is a structure representing a perl-level coroutine */ 218/* this is a structure representing a perl-level coroutine */
219struct coro { 219struct coro {
220 /* the c coroutine allocated to this perl coroutine, if any */ 220 /* the c coroutine allocated to this perl coroutine, if any */
221 coro_cctx *cctx; 221 coro_cctx *cctx;
222 int gimme;
223 222
224 /* process data */ 223 /* process data */
225 AV *mainstack; 224 AV *mainstack;
226 perl_slots *slot; /* basically the saved sp */ 225 perl_slots *slot; /* basically the saved sp */
227 226
712 XPUSHs (sv_2mortal (av_shift (GvAV (PL_defgv)))); 711 XPUSHs (sv_2mortal (av_shift (GvAV (PL_defgv))));
713 PUTBACK; 712 PUTBACK;
714 PL_op = (OP *)&myop; 713 PL_op = (OP *)&myop;
715 PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); 714 PL_op = PL_ppaddr[OP_ENTERSUB](aTHX);
716 SPAGAIN; 715 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 } 716 }
717
718 /* this newly created coroutine might be run on an existing cctx which most
719 * likely was suspended in set_stacklevel, called from entersub.
720 * set_stacklevl doesn't do anything on return, but entersub does LEAVE,
721 * so we ENTER here for symmetry
722 */
723 ENTER;
732} 724}
733 725
734static void 726static void
735coro_destroy (pTHX_ struct coro *coro) 727coro_destroy (pTHX_ struct coro *coro)
736{ 728{
1032 1024
1033/* wether this cctx should be destructed */ 1025/* wether this cctx should be destructed */
1034#define CCTX_EXPIRED(cctx) ((cctx)->ssize < coro_stacksize || ((cctx)->flags & CC_NOREUSE)) 1026#define CCTX_EXPIRED(cctx) ((cctx)->ssize < coro_stacksize || ((cctx)->flags & CC_NOREUSE))
1035 1027
1036static coro_cctx * 1028static coro_cctx *
1037cctx_get (pTHX_ int gimme) 1029cctx_get (pTHX)
1038{ 1030{
1039 while (expect_true (cctx_first[gimme])) 1031 while (expect_true (cctx_first))
1040 { 1032 {
1041 coro_cctx *cctx = cctx_first[gimme]; 1033 coro_cctx *cctx = cctx_first;
1042 cctx_first[gimme] = cctx->next; 1034 cctx_first = cctx->next;
1043 --cctx_idle[gimme]; 1035 --cctx_idle;
1044 1036
1045 if (expect_true (!CCTX_EXPIRED (cctx))) 1037 if (expect_true (!CCTX_EXPIRED (cctx)))
1046 return cctx; 1038 return cctx;
1047 1039
1048 cctx_destroy (cctx); 1040 cctx_destroy (cctx);
1049 } 1041 }
1050 1042
1051 assert (!gimme);
1052 return cctx_new (); 1043 return cctx_new ();
1053} 1044}
1054 1045
1055static void 1046static void
1056cctx_put (coro_cctx *cctx, int gimme) 1047cctx_put (coro_cctx *cctx)
1057{ 1048{
1058 /* free another cctx if overlimit */ 1049 /* free another cctx if overlimit */
1059 if (expect_false (cctx_idle[gimme] >= MAX_IDLE_CCTX)) 1050 if (expect_false (cctx_idle >= MAX_IDLE_CCTX))
1060 { 1051 {
1061 coro_cctx *first = cctx_first[gimme]; 1052 coro_cctx *first = cctx_first;
1062 cctx_first[gimme] = first->next; 1053 cctx_first = first->next;
1063 --cctx_idle[gimme]; 1054 --cctx_idle;
1064 1055
1065 cctx_destroy (first); 1056 cctx_destroy (first);
1066 } 1057 }
1067 1058
1068 ++cctx_idle[gimme]; 1059 ++cctx_idle;
1069 cctx->next = cctx_first[gimme]; 1060 cctx->next = cctx_first;
1070 cctx_first[gimme] = cctx; 1061 cctx_first = cctx;
1071} 1062}
1072 1063
1073/** coroutine switching *****************************************************/ 1064/** coroutine switching *****************************************************/
1074 1065
1075static void 1066static void
1154 1145
1155 /* if the cctx is about to be destroyed we need to make sure we won't see it in cctx_get */ 1146 /* if the cctx is about to be destroyed we need to make sure we won't see it in cctx_get */
1156 /* without this the next cctx_get might destroy the prev__cctx while still in use */ 1147 /* without this the next cctx_get might destroy the prev__cctx while still in use */
1157 if (expect_false (CCTX_EXPIRED (prev__cctx))) 1148 if (expect_false (CCTX_EXPIRED (prev__cctx)))
1158 if (!next->cctx) 1149 if (!next->cctx)
1159 next->cctx = cctx_get (aTHX_ next->gimme); 1150 next->cctx = cctx_get (aTHX);
1160 1151
1161 cctx_put (prev__cctx, prev->gimme); 1152 cctx_put (prev__cctx);
1162 } 1153 }
1163 1154
1164 ++next->usecount; 1155 ++next->usecount;
1165 1156
1166 if (expect_true (!next->cctx)) 1157 if (expect_true (!next->cctx))
1167 next->cctx = cctx_get (aTHX_ next->gimme); 1158 next->cctx = cctx_get (aTHX);
1168 1159
1169 if (expect_false (prev__cctx != next->cctx)) 1160 if (expect_false (prev__cctx != next->cctx))
1170 { 1161 {
1171 prev__cctx->top_env = PL_top_env; 1162 prev__cctx->top_env = PL_top_env;
1172 PL_top_env = next->cctx->top_env; 1163 PL_top_env = next->cctx->top_env;
1538 1529
1539 while (main_top_env->je_prev) 1530 while (main_top_env->je_prev)
1540 main_top_env = main_top_env->je_prev; 1531 main_top_env = main_top_env->je_prev;
1541 1532
1542 coroapi.ver = CORO_API_VERSION; 1533 coroapi.ver = CORO_API_VERSION;
1534 coroapi.rev = CORO_API_REVISION;
1543 coroapi.transfer = api_transfer; 1535 coroapi.transfer = api_transfer;
1544 1536
1545 assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); 1537 assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL));
1546} 1538}
1547 1539
1576# function to increase chances that they all will call transfer with the same 1568# function to increase chances that they all will call transfer with the same
1577# stack offset 1569# stack offset
1578void 1570void
1579_set_stacklevel (...) 1571_set_stacklevel (...)
1580 ALIAS: 1572 ALIAS:
1581 Coro::State::transfer = 1 1573 Coro::State::transfer = 1
1582 Coro::schedule = 2 1574 Coro::schedule = 2
1583 Coro::cede = 3 1575 Coro::cede = 3
1584 Coro::cede_notself = 4 1576 Coro::cede_notself = 4
1585 Coro::Event::next = 5
1586 Coro::Event::next_cancel = 6
1587 PPCODE: 1577 CODE:
1588{ 1578{
1589 struct transfer_args ta; 1579 struct transfer_args ta;
1590 int again = 0;
1591 1580
1592 do 1581 switch (ix)
1593 { 1582 {
1594 switch (ix)
1595 {
1596 case 0: 1583 case 0:
1597 ta.prev = (struct coro *)INT2PTR (coro_cctx *, SvIV (ST (0))); 1584 ta.prev = (struct coro *)INT2PTR (coro_cctx *, SvIV (ST (0)));
1598 ta.next = 0; 1585 ta.next = 0;
1599 break; 1586 break;
1600 1587
1601 case 1: 1588 case 1:
1602 if (items != 2) 1589 if (items != 2)
1603 croak ("Coro::State::transfer (prev,next) expects two arguments, not %d", items); 1590 croak ("Coro::State::transfer (prev,next) expects two arguments, not %d", items);
1604 1591
1605 prepare_transfer (aTHX_ &ta, ST(0), ST(1)); 1592 prepare_transfer (aTHX_ &ta, ST (0), ST (1));
1606 break; 1593 break;
1607 1594
1608 case 2: 1595 case 2:
1609 prepare_schedule (aTHX_ &ta); 1596 prepare_schedule (aTHX_ &ta);
1610 break; 1597 break;
1611 1598
1612 case 3: 1599 case 3:
1613 prepare_cede (aTHX_ &ta); 1600 prepare_cede (aTHX_ &ta);
1614 break; 1601 break;
1615 1602
1616 case 4: 1603 case 4:
1617 if (!prepare_cede_notself (aTHX_ &ta)) 1604 if (!prepare_cede_notself (aTHX_ &ta))
1618 XSRETURN_EMPTY; 1605 XSRETURN_EMPTY;
1619 1606
1620 break; 1607 break;
1621
1622 case 5:
1623 case 6:
1624 if (items != 1)
1625 croak ("Coro::Event::next (watcher) expects one argument, not %d", items);
1626
1627 {
1628 SV *ev = coroapi.coro_event_next (ST (0), ix == 6, GIMME_V != G_VOID);
1629
1630 if (ev)
1631 {
1632 if (GIMME_V != G_VOID)
1633 {
1634 XPUSHs (ev);
1635 XSRETURN (1);
1636 }
1637 else
1638 XSRETURN_EMPTY;
1639 }
1640 }
1641
1642 prepare_schedule (aTHX_ &ta);
1643 again = 1;
1644 break;
1645 }
1646
1647 /* our caller, entersub, caches *only* this value */
1648 ta.prev->gimme = GIMME_V == G_VOID ? 0
1649 : GIMME_V == G_SCALAR ? 1
1650 : 2;
1651
1652 /* we need to save all local variables, as we might execute a different coroutine when transfer returns */
1653 sp += 2; /* save args */
1654 EXTEND (SP, 4);
1655 PUSHs ((SV *)(intptr_t)items);
1656 PUSHs ((SV *)(intptr_t)ix);
1657 PUSHs ((SV *)(intptr_t)ax);
1658 PUSHs ((SV *)(intptr_t)again);
1659 PUTBACK;
1660 BARRIER;
1661 TRANSFER (ta);
1662 BARRIER;
1663 SPAGAIN;
1664 again = (intptr_t)POPs;
1665 ax = (intptr_t)POPs;
1666 ix = (intptr_t)POPs;
1667 items = (intptr_t)POPs;
1668 sp -= 2; /* restore args */
1669 } 1608 }
1670 while (again);
1671 1609
1672 if (expect_false (GIMME_V != G_VOID && ta.next != ta.prev)) 1610 BARRIER;
1673 XSRETURN_YES; 1611 PUTBACK;
1674 1612 TRANSFER (ta);
1675 XSRETURN_EMPTY; /* not understood why this is necessary, likely some stack handling bug */ 1613 SPAGAIN; /* might be the sp of a different coroutine now */
1614 /* be extra careful not to ever do anything after TRANSFER */
1676} 1615}
1677 1616
1678bool 1617bool
1679_destroy (SV *coro_sv) 1618_destroy (SV *coro_sv)
1680 CODE: 1619 CODE:
1706 RETVAL 1645 RETVAL
1707 1646
1708int 1647int
1709cctx_idle () 1648cctx_idle ()
1710 CODE: 1649 CODE:
1711 RETVAL = cctx_idle[0] + cctx_idle[1] + cctx_idle[2]; 1650 RETVAL = cctx_idle;
1712 OUTPUT: 1651 OUTPUT:
1713 RETVAL 1652 RETVAL
1714 1653
1715void 1654void
1716list () 1655list ()
1750 eval_sv (coderef, 0); 1689 eval_sv (coderef, 0);
1751 else 1690 else
1752 call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); 1691 call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD);
1753 1692
1754 POPSTACK; 1693 POPSTACK;
1694 SPAGAIN;
1755 FREETMPS; 1695 FREETMPS;
1756 LEAVE; 1696 LEAVE;
1697 PUTBACK;
1757 } 1698 }
1758 1699
1759 if (!(coro->flags & CF_RUNNING)) 1700 if (!(coro->flags & CF_RUNNING))
1760 { 1701 {
1761 save_perl (aTHX_ coro); 1702 save_perl (aTHX_ coro);

Diff Legend

Removed lines
+ Added lines
< Changed lines
> Changed lines