| ... | @@ -1682,19 +1682,27 @@ pub const Condition = struct { | ... | @@ -1682,19 +1682,27 @@ pub const Condition = struct { |
| 1682 | }; | 1682 | }; |
| 1683 | | 1683 | |
| 1684 | pub fn wait(cond: *Condition, io: Io, mutex: *Mutex) Cancelable!void { | 1684 | pub fn wait(cond: *Condition, io: Io, mutex: *Mutex) Cancelable!void { |
| 1685 | try waitInner(cond, io, mutex, false); | 1685 | waitInner(cond, io, mutex, .{ .timeout = .none }) catch |err| switch (err) { |
| | 1686 | error.Timeout => unreachable, |
| | 1687 | error.Canceled => return error.Canceled, |
| | 1688 | }; |
| | 1689 | } |
| | 1690 | |
| | 1691 | pub fn waitTimeout(cond: *Condition, io: Io, mutex: *Mutex, timeout: Timeout) (Cancelable || Timeout.Error)!void { |
| | 1692 | return waitInner(cond, io, mutex, .{ .timeout = timeout.toDeadline(io) }); |
| 1686 | } | 1693 | } |
| 1687 | | 1694 | |
| 1688 | /// Same as `wait`, except does not introduce a cancelation point. | 1695 | /// Same as `wait`, except does not introduce a cancelation point. |
| 1689 | /// | 1696 | /// |
| 1690 | /// For a description of cancelation and cancelation points, see `Future.cancel`. | 1697 | /// For a description of cancelation and cancelation points, see `Future.cancel`. |
| 1691 | pub fn waitUncancelable(cond: *Condition, io: Io, mutex: *Mutex) void { | 1698 | pub fn waitUncancelable(cond: *Condition, io: Io, mutex: *Mutex) void { |
| 1692 | waitInner(cond, io, mutex, true) catch |err| switch (err) { | 1699 | waitInner(cond, io, mutex, .uncancelable) catch |err| switch (err) { |
| | 1700 | error.Timeout => unreachable, |
| 1693 | error.Canceled => unreachable, | 1701 | error.Canceled => unreachable, |
| 1694 | }; | 1702 | }; |
| 1695 | } | 1703 | } |
| 1696 | | 1704 | |
| 1697 | fn waitInner(cond: *Condition, io: Io, mutex: *Mutex, uncancelable: bool) Cancelable!void { | 1705 | fn waitInner(cond: *Condition, io: Io, mutex: *Mutex, mode: union(enum) { uncancelable, timeout: Timeout }) (Cancelable || Timeout.Error)!void { |
| 1698 | var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load | 1706 | var epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before state load |
| 1699 | | 1707 | |
| 1700 | { | 1708 | { |
| ... | @@ -1706,10 +1714,10 @@ pub const Condition = struct { | ... | @@ -1706,10 +1714,10 @@ pub const Condition = struct { |
| 1706 | defer mutex.lockUncancelable(io); | 1714 | defer mutex.lockUncancelable(io); |
| 1707 | | 1715 | |
| 1708 | while (true) { | 1716 | while (true) { |
| 1709 | const result = if (uncancelable) | 1717 | const result = switch (mode) { |
| 1710 | io.futexWaitUncancelable(u32, &cond.epoch.raw, epoch) | 1718 | .uncancelable => io.futexWaitUncancelable(u32, &cond.epoch.raw, epoch), |
| 1711 | else | 1719 | .timeout => |t| io.futexWaitTimeout(u32, &cond.epoch.raw, epoch, t), |
| 1712 | io.futexWait(u32, &cond.epoch.raw, epoch); | 1720 | }; |
| 1713 | | 1721 | |
| 1714 | epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before `state` laod | 1722 | epoch = cond.epoch.load(.acquire); // `.acquire` to ensure ordered before `state` laod |
| 1715 | | 1723 | |
| ... | @@ -1729,13 +1737,21 @@ pub const Condition = struct { | ... | @@ -1729,13 +1737,21 @@ pub const Condition = struct { |
| 1729 | } | 1737 | } |
| 1730 | | 1738 | |
| 1731 | // There are no more signals available; this was a spurious wakeup or an error. If it | 1739 | // There are no more signals available; this was a spurious wakeup or an error. If it |
| 1732 | // was an error, we will remove ourselves as a waiter and return that error. Otherwise, | 1740 | // was an error, we will remove ourselves as a waiter and return that error. If a |
| 1733 | // we'll loop back to the futex wait. | 1741 | // timeout was specified and the deadline has passed, we remove ourselves as a waiter |
| | 1742 | // and return `error.Timeout`. Otherwise, we'll loop back to the futex wait. |
| 1734 | result catch |err| { | 1743 | result catch |err| { |
| 1735 | const prev_state = cond.state.fetchSub(.{ .waiters = 1, .signals = 0 }, .monotonic); | 1744 | const prev_state = cond.state.fetchSub(.{ .waiters = 1, .signals = 0 }, .monotonic); |
| 1736 | assert(prev_state.waiters > 0); // underflow caused by illegal state | 1745 | assert(prev_state.waiters > 0); // underflow caused by illegal state |
| 1737 | return err; | 1746 | return err; |
| 1738 | }; | 1747 | }; |
| | 1748 | if (mode == .timeout and mode.timeout != .none) { |
| | 1749 | if (mode.timeout.deadline.untilNow(io).raw.nanoseconds >= 0) { |
| | 1750 | const prev_state = cond.state.fetchSub(.{ .waiters = 1, .signals = 0 }, .monotonic); |
| | 1751 | assert(prev_state.waiters > 0); // underflow caused by illegal state |
| | 1752 | return error.Timeout; |
| | 1753 | } |
| | 1754 | } |
| 1739 | } | 1755 | } |
| 1740 | } | 1756 | } |
| 1741 | | 1757 | |