Nursery: Don't pass exceptions to main loop

This commit is contained in:
2026-06-09 10:43:20 -04:00
parent 565e339a8b
commit 5689ac3914
2 changed files with 17 additions and 27 deletions
+5 -7
View File
@@ -190,11 +190,10 @@ nursery.openAdmission();
auto lease = nursery.getNewSlotLease(); auto lease = nursery.getNewSlotLease();
lease.getSyncCanceler().startAcceptingWork(); lease.getSyncCanceler().startAcceptingWork();
std::exception_ptr &exceptionStorage = lease.getExceptionStorage();
lease.setOnSettledHook( lease.setOnSettledHook(
[&exceptionStorage]() [](std::exception_ptr &exceptionPtr)
{ {
sscl::co::NonViralCompletion nvc(exceptionStorage); sscl::co::NonViralCompletion nvc(exceptionPtr);
nvc.checkAndRethrowException(); nvc.checkAndRethrowException();
}); });
lease.fillSlot( lease.fillSlot(
@@ -221,10 +220,9 @@ all slots have retired naturally and throw if admission is still open.
`Slot::Lease` is commit-required: an uncommitted lease removes its reservation on `Slot::Lease` is commit-required: an uncommitted lease removes its reservation on
destruction. `fillSlot()` takes an invoker factory (deferred construction) because destruction. `fillSlot()` takes an invoker factory (deferred construction) because
non-viral coroutines may complete synchronously during invoker construction. non-viral coroutines may complete synchronously during invoker construction.
The factory may capture `lease` by reference; `setOnSettledHook()` may not. The factory may capture `lease` by reference; `setOnSettledHook()` may not
The hook runs after the lease is destroyed, so capture slot-owned state such as capture `lease` itself. The nursery passes the slot's `exceptionPtr` into the
`lease.getExceptionStorage()` (a reference to the slot's `exceptionPtr`), not hook at retirement.
`lease` itself.
`Slot::Handle` is an opaque slot pointer valid only while the slot remains in the `Slot::Handle` is an opaque slot pointer valid only while the slot remains in the
nursery. nursery.
+12 -20
View File
@@ -4,7 +4,6 @@
#include <cstddef> #include <cstddef>
#include <exception> #include <exception>
#include <functional> #include <functional>
#include <iostream>
#include <list> #include <list>
#include <memory> #include <memory>
#include <stdexcept> #include <stdexcept>
@@ -116,7 +115,8 @@ public:
sscl::SyncCancelerForAsyncWork &getSyncCanceler() sscl::SyncCancelerForAsyncWork &getSyncCanceler()
{ return slot.syncCanceler; } { return slot.syncCanceler; }
void setOnSettledHook(std::function<void()> hook) void setOnSettledHook(
std::function<void(std::exception_ptr &exceptionPtr)> hook)
{ {
if (slot.leaseStatus != SlotLeaseStatus::RESERVED) if (slot.leaseStatus != SlotLeaseStatus::RESERVED)
{ {
@@ -214,7 +214,7 @@ public:
std::exception_ptr exceptionPtr = nullptr; std::exception_ptr exceptionPtr = nullptr;
sscl::SyncCancelerForAsyncWork syncCanceler; sscl::SyncCancelerForAsyncWork syncCanceler;
std::unique_ptr<detail::MemberInvokerBase> memberInvoker; std::unique_ptr<detail::MemberInvokerBase> memberInvoker;
std::function<void()> onSettledHook; std::function<void(std::exception_ptr &exceptionPtr)> onSettledHook;
}; };
void openAdmission() void openAdmission()
@@ -411,6 +411,8 @@ private:
void retireSlot(Slot &slot) void retireSlot(Slot &slot)
{ {
std::function<void()> waiterToInvoke; std::function<void()> waiterToInvoke;
std::function<void(std::exception_ptr &exceptionPtr)> onSettledHook;
std::exception_ptr settledExceptionPtr;
{ {
sscl::SpinLock::Guard guard(s.lock); sscl::SpinLock::Guard guard(s.lock);
@@ -430,33 +432,23 @@ private:
return; return;
} }
try { settledExceptionPtr = slot.exceptionPtr;
if (slot.onSettledHook) { slot.onSettledHook(); } if (settledExceptionPtr) {
}
catch (const std::exception &e)
{
std::cerr
<< "NonViralTaskNursery: onSettled hook exception: "
<< e.what() << std::endl;
}
catch (...)
{
std::cerr
<< "NonViralTaskNursery: onSettled hook unknown exception"
<< std::endl;
}
if (slot.exceptionPtr) {
slot.settlementStatus = SlotSettlementStatus::EXCEPTION_THROWN; slot.settlementStatus = SlotSettlementStatus::EXCEPTION_THROWN;
} else { } else {
slot.settlementStatus = SlotSettlementStatus::COMPLETED; slot.settlementStatus = SlotSettlementStatus::COMPLETED;
} }
onSettledHook = std::move(slot.onSettledHook);
slot.leaseStatus = SlotLeaseStatus::RETIRED; slot.leaseStatus = SlotLeaseStatus::RETIRED;
slot.memberInvoker.reset(); slot.memberInvoker.reset();
waiterToInvoke = takeDrainWaiterIfDrainedUnlocked(); waiterToInvoke = takeDrainWaiterIfDrainedUnlocked();
} }
if (onSettledHook) {
onSettledHook(settledExceptionPtr);
}
if (waiterToInvoke) { waiterToInvoke(); } if (waiterToInvoke) { waiterToInvoke(); }
} }