| 1519 | |
| 1520 | template <typename T> |
| 1521 | void expired( |
| 1522 | const std::shared_ptr<lambda::CallableOnce<Future<T>(const Future<T>&)>>& f, |
| 1523 | const std::shared_ptr<Latch>& latch, |
| 1524 | const std::shared_ptr<Promise<T>>& promise, |
| 1525 | const std::shared_ptr<Option<Timer>>& timer, |
| 1526 | const Future<T>& future) |
| 1527 | { |
| 1528 | if (latch->trigger()) { |
| 1529 | // If this callback executed first (i.e., we triggered the latch) |
| 1530 | // then we want to clear out the timer so that we don't hold a |
| 1531 | // circular reference to `future` in it's own `onAny` |
| 1532 | // callbacks. See the comment in `Future::after`. |
| 1533 | *timer = None(); |
| 1534 | |
| 1535 | // Note that we don't bother checking if 'future' has been |
| 1536 | // discarded (i.e., 'future.isDiscarded()' returns true) since |
| 1537 | // there is a race between when we make that check and when we |
| 1538 | // would invoke 'f(future)' so the callee 'f' should ALWAYS check |
| 1539 | // if the future has been discarded and rather than hiding a |
| 1540 | // non-deterministic bug we always call 'f' if the timer has |
| 1541 | // expired. |
| 1542 | promise->associate(std::move(*f)(future)); |
| 1543 | } |
| 1544 | } |
| 1545 | |
| 1546 | |
| 1547 | template <typename T> |