From 96fbc29f09c903be078862effa115644412f9fe3 Mon Sep 17 00:00:00 2001 From: eldritch horrors Date: Mon, 30 Jun 2025 22:22:20 +0200 Subject: [PATCH] libutil: checkInterrupt in AsyncIoRoot::blockOn checkInterrupt is cheap, waiting for a promise isn't. checking for interruptions before any top-level promise is awaited lets us drop a bunch of checkInterrupt calls elsewhere, such as in thread pools Change-Id: Id543edf9411e53b2a5bbec77d3084a8f65aaea46 --- lix/libutil/async.hh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lix/libutil/async.hh b/lix/libutil/async.hh index fa3a93ce8..453e65df1 100644 --- a/lix/libutil/async.hh +++ b/lix/libutil/async.hh @@ -141,6 +141,13 @@ static constexpr std::optional lixAsyncTaskContext() template inline auto nix::AsyncIoRoot::blockOn(kj::Promise && promise, std::source_location call_site) try { + // always check for user interrupts. since this is c++ we must always be prepared for + // random exceptions out of literally nowhere, which is why RAII is such an important + // idiom. interruptions are also exceptions, so all exception-safe (and for promises, + // cancellation-safe) code is automatically interruption-safe. in this code base with + // its very creative approach to exception usage all promises *must* be cancellation- + // safe to not wreck system state constantly, so calling checkInterrupt is safe here. + checkInterrupt(); return detail::runAsyncUnwrap(promise.wait(kj.waitScope)); } catch (BaseException & e) { e.addAsyncTrace(call_site);