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();
lease.getSyncCanceler().startAcceptingWork();
std::exception_ptr &exceptionStorage = lease.getExceptionStorage();
lease.setOnSettledHook(
[&exceptionStorage]()
[](std::exception_ptr &exceptionPtr)
{
sscl::co::NonViralCompletion nvc(exceptionStorage);
sscl::co::NonViralCompletion nvc(exceptionPtr);
nvc.checkAndRethrowException();
});
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
destruction. `fillSlot()` takes an invoker factory (deferred construction) because
non-viral coroutines may complete synchronously during invoker construction.
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
`lease.getExceptionStorage()` (a reference to the slot's `exceptionPtr`), not
`lease` itself.
The factory may capture `lease` by reference; `setOnSettledHook()` may not
capture `lease` itself. The nursery passes the slot's `exceptionPtr` into the
hook at retirement.
`Slot::Handle` is an opaque slot pointer valid only while the slot remains in the
nursery.
+12 -20
View File
@@ -4,7 +4,6 @@
#include <cstddef>
#include <exception>
#include <functional>
#include <iostream>
#include <list>
#include <memory>
#include <stdexcept>
@@ -116,7 +115,8 @@ public:
sscl::SyncCancelerForAsyncWork &getSyncCanceler()
{ return slot.syncCanceler; }
void setOnSettledHook(std::function<void()> hook)
void setOnSettledHook(
std::function<void(std::exception_ptr &exceptionPtr)> hook)
{
if (slot.leaseStatus != SlotLeaseStatus::RESERVED)
{
@@ -214,7 +214,7 @@ public:
std::exception_ptr exceptionPtr = nullptr;
sscl::SyncCancelerForAsyncWork syncCanceler;
std::unique_ptr<detail::MemberInvokerBase> memberInvoker;
std::function<void()> onSettledHook;
std::function<void(std::exception_ptr &exceptionPtr)> onSettledHook;
};
void openAdmission()
@@ -411,6 +411,8 @@ private:
void retireSlot(Slot &slot)
{
std::function<void()> waiterToInvoke;
std::function<void(std::exception_ptr &exceptionPtr)> onSettledHook;
std::exception_ptr settledExceptionPtr;
{
sscl::SpinLock::Guard guard(s.lock);
@@ -430,33 +432,23 @@ private:
return;
}
try {
if (slot.onSettledHook) { slot.onSettledHook(); }
}
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) {
settledExceptionPtr = slot.exceptionPtr;
if (settledExceptionPtr) {
slot.settlementStatus = SlotSettlementStatus::EXCEPTION_THROWN;
} else {
slot.settlementStatus = SlotSettlementStatus::COMPLETED;
}
onSettledHook = std::move(slot.onSettledHook);
slot.leaseStatus = SlotLeaseStatus::RETIRED;
slot.memberInvoker.reset();
waiterToInvoke = takeDrainWaiterIfDrainedUnlocked();
}
if (onSettledHook) {
onSettledHook(settledExceptionPtr);
}
if (waiterToInvoke) { waiterToInvoke(); }
}