… | |
… | |
10 | #include "patchlevel.h" |
10 | #include "patchlevel.h" |
11 | |
11 | |
12 | #include <stdio.h> |
12 | #include <stdio.h> |
13 | #include <errno.h> |
13 | #include <errno.h> |
14 | #include <assert.h> |
14 | #include <assert.h> |
|
|
15 | #include <inttypes.h> /* portable stdint.h */ |
15 | |
16 | |
16 | #ifdef HAVE_MMAP |
17 | #ifdef HAVE_MMAP |
17 | # include <unistd.h> |
18 | # include <unistd.h> |
18 | # include <sys/mman.h> |
19 | # include <sys/mman.h> |
19 | # ifndef MAP_ANONYMOUS |
20 | # ifndef MAP_ANONYMOUS |
… | |
… | |
712 | PL_op = (OP *)&myop; |
713 | PL_op = (OP *)&myop; |
713 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
714 | PL_op = PL_ppaddr[OP_ENTERSUB](aTHX); |
714 | SPAGAIN; |
715 | SPAGAIN; |
715 | } |
716 | } |
716 | |
717 | |
717 | ENTER; /* necessary e.g. for dounwind and to balance the xsub-entersub */ |
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; |
718 | } |
724 | } |
719 | |
725 | |
720 | static void |
726 | static void |
721 | coro_destroy (pTHX_ struct coro *coro) |
727 | coro_destroy (pTHX_ struct coro *coro) |
722 | { |
728 | { |
… | |
… | |
1523 | |
1529 | |
1524 | while (main_top_env->je_prev) |
1530 | while (main_top_env->je_prev) |
1525 | main_top_env = main_top_env->je_prev; |
1531 | main_top_env = main_top_env->je_prev; |
1526 | |
1532 | |
1527 | coroapi.ver = CORO_API_VERSION; |
1533 | coroapi.ver = CORO_API_VERSION; |
|
|
1534 | coroapi.rev = CORO_API_REVISION; |
1528 | coroapi.transfer = api_transfer; |
1535 | coroapi.transfer = api_transfer; |
1529 | |
1536 | |
1530 | assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); |
1537 | assert (("PRIO_NORMAL must be 0", !PRIO_NORMAL)); |
1531 | } |
1538 | } |
1532 | |
1539 | |
… | |
… | |
1561 | # 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 |
1562 | # stack offset |
1569 | # stack offset |
1563 | void |
1570 | void |
1564 | _set_stacklevel (...) |
1571 | _set_stacklevel (...) |
1565 | ALIAS: |
1572 | ALIAS: |
1566 | Coro::State::transfer = 1 |
1573 | Coro::State::transfer = 1 |
1567 | Coro::schedule = 2 |
1574 | Coro::schedule = 2 |
1568 | Coro::cede = 3 |
1575 | Coro::cede = 3 |
1569 | Coro::cede_notself = 4 |
1576 | Coro::cede_notself = 4 |
1570 | Coro::Event::next = 5 |
|
|
1571 | Coro::Event::next_cancel = 6 |
|
|
1572 | PPCODE: |
1577 | CODE: |
1573 | { |
1578 | { |
1574 | struct transfer_args ta; |
1579 | struct transfer_args ta; |
1575 | int again = 0; |
|
|
1576 | |
1580 | |
1577 | do |
1581 | switch (ix) |
1578 | { |
1582 | { |
1579 | switch (ix) |
|
|
1580 | { |
|
|
1581 | case 0: |
1583 | case 0: |
1582 | ta.prev = (struct coro *)INT2PTR (coro_cctx *, SvIV (ST (0))); |
1584 | ta.prev = (struct coro *)INT2PTR (coro_cctx *, SvIV (ST (0))); |
1583 | ta.next = 0; |
1585 | ta.next = 0; |
1584 | break; |
1586 | break; |
1585 | |
1587 | |
1586 | case 1: |
1588 | case 1: |
1587 | if (items != 2) |
1589 | if (items != 2) |
1588 | 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); |
1589 | |
1591 | |
1590 | prepare_transfer (aTHX_ &ta, ST (0), ST (1)); |
1592 | prepare_transfer (aTHX_ &ta, ST (0), ST (1)); |
1591 | break; |
1593 | break; |
1592 | |
1594 | |
1593 | case 2: |
1595 | case 2: |
1594 | prepare_schedule (aTHX_ &ta); |
1596 | prepare_schedule (aTHX_ &ta); |
1595 | break; |
1597 | break; |
1596 | |
1598 | |
1597 | case 3: |
1599 | case 3: |
1598 | prepare_cede (aTHX_ &ta); |
1600 | prepare_cede (aTHX_ &ta); |
1599 | break; |
1601 | break; |
1600 | |
1602 | |
1601 | case 4: |
1603 | case 4: |
1602 | if (!prepare_cede_notself (aTHX_ &ta)) |
1604 | if (!prepare_cede_notself (aTHX_ &ta)) |
1603 | XSRETURN_EMPTY; |
1605 | XSRETURN_EMPTY; |
1604 | |
1606 | |
1605 | break; |
1607 | break; |
1606 | |
|
|
1607 | case 5: |
|
|
1608 | case 6: |
|
|
1609 | if (items != 1) |
|
|
1610 | croak ("Coro::Event::next (watcher) expects one argument, not %d", items); |
|
|
1611 | |
|
|
1612 | { |
|
|
1613 | SV *ev = coroapi.coro_event_next (ST (0), ix == 6, GIMME_V != G_VOID); |
|
|
1614 | |
|
|
1615 | if (ev) |
|
|
1616 | { |
|
|
1617 | if (GIMME_V != G_VOID) |
|
|
1618 | { |
|
|
1619 | XPUSHs (ev); |
|
|
1620 | XSRETURN (1); |
|
|
1621 | } |
|
|
1622 | else |
|
|
1623 | XSRETURN_EMPTY; |
|
|
1624 | } |
|
|
1625 | } |
|
|
1626 | |
|
|
1627 | prepare_schedule (aTHX_ &ta); |
|
|
1628 | again = 1; |
|
|
1629 | break; |
|
|
1630 | } |
|
|
1631 | |
|
|
1632 | BARRIER; |
|
|
1633 | TRANSFER (ta); |
|
|
1634 | BARRIER; |
|
|
1635 | } |
1608 | } |
1636 | while (again); |
|
|
1637 | |
1609 | |
1638 | if (expect_false (GIMME_V != G_VOID && ta.next != ta.prev)) |
1610 | BARRIER; |
1639 | XSRETURN_YES; |
1611 | PUTBACK; |
1640 | |
1612 | TRANSFER (ta); |
1641 | 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 */ |
|
|
1615 | } |
1642 | |
1616 | |
1643 | bool |
1617 | bool |
1644 | _destroy (SV *coro_sv) |
1618 | _destroy (SV *coro_sv) |
1645 | CODE: |
1619 | CODE: |
1646 | RETVAL = coro_state_destroy (aTHX_ SvSTATE (coro_sv)); |
1620 | RETVAL = coro_state_destroy (aTHX_ SvSTATE (coro_sv)); |
… | |
… | |
1715 | eval_sv (coderef, 0); |
1689 | eval_sv (coderef, 0); |
1716 | else |
1690 | else |
1717 | call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
1691 | call_sv (coderef, G_KEEPERR | G_EVAL | G_VOID | G_DISCARD); |
1718 | |
1692 | |
1719 | POPSTACK; |
1693 | POPSTACK; |
|
|
1694 | SPAGAIN; |
1720 | FREETMPS; |
1695 | FREETMPS; |
1721 | LEAVE; |
1696 | LEAVE; |
|
|
1697 | PUTBACK; |
1722 | } |
1698 | } |
1723 | |
1699 | |
1724 | if (!(coro->flags & CF_RUNNING)) |
1700 | if (!(coro->flags & CF_RUNNING)) |
1725 | { |
1701 | { |
1726 | save_perl (aTHX_ coro); |
1702 | save_perl (aTHX_ coro); |