Nix  2.93.0-dev
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
5#include "lix/libutil/signals.hh"
6#include <future>
7#include <kj/async-io.h>
8#include <kj/async.h>
9
10namespace nix {
11
13{
14 static inline thread_local AsyncContext * current = nullptr;
15
16 kj::AsyncIoProvider & provider;
17 kj::UnixEventPort & unixEventPort;
18
19 explicit AsyncContext(kj::AsyncIoContext & aio)
20 : provider(*aio.provider)
21 , unixEventPort(aio.unixEventPort)
22 {
23 assert(current == nullptr);
24 current = this;
25 }
26
28 {
29 current = nullptr;
30 }
31
32 KJ_DISALLOW_COPY_AND_MOVE(AsyncContext);
33};
34
36{
37 kj::AsyncIoContext kj;
38 AsyncContext context;
39
40 AsyncIoRoot() : kj(kj::setupAsyncIo()), context(kj) {}
41 KJ_DISALLOW_COPY_AND_MOVE(AsyncIoRoot);
42
43 template<typename T>
44 auto blockOn(kj::Promise<T> && promise);
45};
46
47inline AsyncContext & AIO()
48{
49 assert(AsyncContext::current != nullptr);
50 return *AsyncContext::current;
51}
52
53namespace detail {
54inline void materializeResult(Result<void> r)
55{
56 r.value();
57}
58
59template<typename T>
60inline T materializeResult(Result<T> r)
61{
62 return std::move(r.value());
63}
64
65template<typename T>
66T runAsyncUnwrap(T t)
67{
68 return t;
69}
70template<typename T>
71T runAsyncUnwrap(Result<T> t)
72{
73 return std::move(t).value();
74}
75
76auto runAsyncInNewThread(std::invocable<AsyncIoRoot &> auto fn)
77{
78 auto future = std::async(std::launch::async, [&] {
79 ReceiveInterrupts ri;
80 AsyncIoRoot aioRoot;
81 if constexpr (!std::is_void_v<decltype(fn(aioRoot))>) {
82 return runAsyncUnwrap(fn(aioRoot));
83 } else {
84 fn(aioRoot);
85 }
86 });
87 return future.get();
88}
89}
90}
91
92#define LIX_RUN_ASYNC_IN_NEW_THREAD(...) \
93 ::nix::detail::runAsyncInNewThread([&](AsyncIoRoot & AIOROOT) { \
94 return AIOROOT.blockOn(__VA_ARGS__); \
95 })
96
97// force materialization of the value. result::value() returns only an rvalue reference
98// and is thus unsuitable for use in e.g. range for without materialization. ideally we
99// would wrap the expression in `auto()`, but apple clang fails when given `auto(void)`
100#define LIX_TRY_AWAIT(...) (::nix::detail::materializeResult(co_await (__VA_ARGS__)))
101
102#if LIX_UR_COMPILER_UWU
103# define RUN_ASYNC_IN_NEW_THREAD LIX_RUN_ASYNC_IN_NEW_THREAD
104# define TRY_AWAIT LIX_TRY_AWAIT
105#endif
106
107template<typename T>
108inline auto nix::AsyncIoRoot::blockOn(kj::Promise<T> && promise)
109{
110 return detail::runAsyncUnwrap(promise.wait(kj.waitScope));
111}
Definition async.hh:13
Definition async.hh:36