Nix 2.93.3
Lix: A modern, delicious implementation of the Nix package manager; unstable internal interfaces
Loading...
Searching...
No Matches
async.hh
Go to the documentation of this file.
1#pragma once
3
6#include "lix/libutil/signals.hh"
7#include <future>
8#include <kj/async-io.h>
9#include <kj/async.h>
10#include <optional>
11#include <source_location>
12
13namespace nix {
14
15struct AsyncContext
16{
17 static inline thread_local AsyncContext * current = nullptr;
18
19 kj::AsyncIoProvider & provider;
20 kj::UnixEventPort & unixEventPort;
21
22 explicit AsyncContext(kj::AsyncIoContext & aio)
23 : provider(*aio.provider)
24 , unixEventPort(aio.unixEventPort)
25 {
26 assert(current == nullptr);
27 current = this;
28 }
29
30 ~AsyncContext()
31 {
32 current = nullptr;
33 }
34
35 KJ_DISALLOW_COPY_AND_MOVE(AsyncContext);
36};
37
38struct AsyncIoRoot
39{
40 kj::AsyncIoContext kj;
41 AsyncContext context;
42
43 AsyncIoRoot() : kj(kj::setupAsyncIo()), context(kj) {}
44 KJ_DISALLOW_COPY_AND_MOVE(AsyncIoRoot);
45
46 template<typename T>
47 auto blockOn(kj::Promise<T> && promise);
48};
49
50inline AsyncContext & AIO()
51{
52 assert(AsyncContext::current != nullptr);
53 return *AsyncContext::current;
54}
55
56namespace detail {
57inline void materializeResult(Result<void> r)
58{
59 r.value();
60}
61
62template<typename T>
63inline T materializeResult(Result<T> r)
64{
65 return std::move(r.value());
66}
67
68template<typename T>
69T runAsyncUnwrap(T t)
70{
71 return t;
72}
73template<typename T>
74T runAsyncUnwrap(Result<T> t)
75{
76 return std::move(t).value();
77}
78
79auto runAsyncInNewThread(std::invocable<AsyncIoRoot &> auto fn)
80{
81 auto future = std::async(std::launch::async, [&] {
82 ReceiveInterrupts ri;
83 AsyncIoRoot aioRoot;
84 if constexpr (!std::is_void_v<decltype(fn(aioRoot))>) {
85 return runAsyncUnwrap(fn(aioRoot));
86 } else {
87 fn(aioRoot);
88 }
89 });
90 return future.get();
91}
92}
93}
94
95#define LIX_RUN_ASYNC_IN_NEW_THREAD(...) \
96 ::nix::detail::runAsyncInNewThread([&](AsyncIoRoot & AIOROOT) { \
97 return AIOROOT.blockOn(__VA_ARGS__); \
98 })
99
100#define LIX_TRY_AWAIT_CONTEXT(ctx, ...) \
101 ({ \
102 auto _lix_awaited = co_await (__VA_ARGS__); \
103 if (_lix_awaited.has_error()) { \
104 try { \
105 _lix_awaited.value(); \
106 } catch (::nix::BaseException & e) { \
107 e.addAsyncTrace(::std::source_location::current(), ctx()); \
108 throw; \
109 } catch (::std::exception & e) { /* NOLINT(lix-foreign-exceptions) */ \
110 ::nix::ForeignException fe(e); \
111 fe.addAsyncTrace(::std::source_location::current(), ctx()); \
112 throw fe; \
113 } \
114 } \
115 ::nix::detail::materializeResult(std::move(_lix_awaited)); \
116 })
117
124static constexpr std::optional<std::string> lixAsyncTaskContext()
125{
126 return std::nullopt;
127}
128
129// force materialization of the value. result::value() returns only an rvalue reference
130// and is thus unsuitable for use in e.g. range for without materialization. ideally we
131// would wrap the expression in `auto()`, but apple clang fails when given `auto(void)`
132#define LIX_TRY_AWAIT(...) LIX_TRY_AWAIT_CONTEXT(lixAsyncTaskContext, __VA_ARGS__)
133
134#if LIX_UR_COMPILER_UWU
135#define RUN_ASYNC_IN_NEW_THREAD LIX_RUN_ASYNC_IN_NEW_THREAD
136#define TRY_AWAIT LIX_TRY_AWAIT
137#endif
138
139template<typename T>
140inline auto nix::AsyncIoRoot::blockOn(kj::Promise<T> && promise)
141{
142 return detail::runAsyncUnwrap(promise.wait(kj.waitScope));
143}
This file defines two main structs/classes used in nix error handling.
Definition async.hh:16