@@ -5,14 +5,14 @@ asynchronous libuv operations as sequential C++ code using `co_await`.
55
66The primary goal is to allow multi-step async operations (such as
77open + stat + read + close) to be written as straight-line C++ instead of
8- callback chains, while maintaining full integration with Node.js async_hooks ,
8+ callback chains, while maintaining full integration with Node.js async \_ hooks ,
99AsyncLocalStorage, microtask draining, and environment lifecycle management.
1010
1111## File overview
1212
1313* ` uv_task.h ` -- ` UvTask<T> ` : The lightweight, untracked coroutine return type.
1414 No V8 or Node.js dependencies. Suitable for internal C++ coroutines that do
15- not need async_hooks visibility or task queue draining.
15+ not need async \_ hooks visibility or task queue draining.
1616
1717* ` uv_tracked_task.h ` -- ` UvTrackedTask<T, Name> ` : The fully-integrated
1818 coroutine return type. Each resume-to-suspend segment is wrapped in an
@@ -64,8 +64,8 @@ static void Access(const FunctionCallbackInfo<Value>& args) {
6464
6565### Multi-step operations
6666
67- Multiple libuv calls within a single coroutine are sequential co_await
68- expressions. The intermediate steps (between two co_await points) are pure C++
67+ Multiple libuv calls within a single coroutine are sequential co\_await
68+ expressions. The intermediate steps (between two co\_await points) are pure C++
6969with no V8 overhead:
7070
7171```cpp
@@ -85,7 +85,7 @@ static coro::UvTrackedTask<void, "COROREADFILE"> ReadFileImpl(
8585
8686### Coroutine composition
8787
88- ` UvTask<T> ` and ` UvTrackedTask<T, Name> ` can be co_awaited from other
88+ ` UvTask<T> ` and ` UvTrackedTask<T, Name> ` can be co \_ awaited from other
8989coroutines. This allows factoring common operations into reusable helpers:
9090
9191``` cpp
@@ -104,7 +104,7 @@ UvTrackedTask<void, "MYOP"> OuterCoroutine(Environment* env, ...) {
104104### UvTask (untracked)
105105
106106`UvTask<T>` uses lazy initialization. The coroutine does not run until it is
107- either co_awaited from another coroutine (symmetric transfer) or explicitly
107+ either co\_awaited from another coroutine (symmetric transfer) or explicitly
108108started with `Start()`. When `Start()` is called, the coroutine runs until its
109109first `co_await`, then control returns to the caller. The coroutine frame
110110self-destructs when the coroutine completes.
@@ -119,20 +119,20 @@ adds three phases around `Start()`:
119119
1201202. **`InitTracking(env)`**: Assigns an `async_id`, captures the current
121121 `async_context_frame` (for AsyncLocalStorage propagation), creates a
122- resource object for `executionAsyncResource()`, emits the async_hooks
122+ resource object for `executionAsyncResource()`, emits the async\_hooks
123123 `init` event and a trace event, registers in the Environment's coroutine
124124 task list, and reports external memory to V8.
125125
1261263. **`Start()`**: Marks the task as detached (fire-and-forget) and resumes
127127 the coroutine. Each resume-to-suspend segment is wrapped in an
128128 `InternalCallbackScope` that provides:
129- * async_hooks `before`/`after` events
129+ * async\_hooks `before`/`after` events
130130 * `async_context_frame` save/restore (AsyncLocalStorage)
131131 * Microtask and `process.nextTick` draining on close
132132 * `request_waiting_` counter management for event loop liveness
133133
1341344. **Completion**: At `final_suspend`, the last `InternalCallbackScope` is
135- closed (draining task queues), the async_hooks `destroy` event is emitted,
135+ closed (draining task queues), the async\_hooks `destroy` event is emitted,
136136 the task is unregistered from the Environment, external memory accounting
137137 is released, and the coroutine frame is freed.
138138
@@ -170,22 +170,22 @@ coroutine I/O to finish before destroying the Environment.
170170
171171For a single async operation (e.g., `fsPromises.access`):
172172
173- | | ReqWrap pattern | Coroutine pattern |
174- |---| ---| ---|
175- | C++ heap allocations | 3 | 1 (coroutine frame) |
176- | V8 heap objects | 7 | 3 (resource + resolver + promise) |
177- | Total allocations | 10 | 4 |
173+ | | ReqWrap pattern | Coroutine pattern |
174+ | -------------------- | --------------- | --------------------------------- |
175+ | C++ heap allocations | 3 | 1 (coroutine frame) |
176+ | V8 heap objects | 7 | 3 (resource + resolver + promise) |
177+ | Total allocations | 10 | 4 |
178178
179179For a multi-step operation (open + stat + read + close):
180180
181- | | 4x ReqWrap | Single coroutine |
182- |---| ---| ---|
183- | C++ heap allocations | 12 | 1 |
184- | V8 heap objects | 28 | 3 |
185- | Total allocations | 40 | 4 |
186- | InternalCallbackScope entries | 4 | 5 (one per segment + initial) |
181+ | | 4x ReqWrap | Single coroutine |
182+ | ----------------------------- | ---------- | ----------------------------- |
183+ | C++ heap allocations | 12 | 1 |
184+ | V8 heap objects | 28 | 3 |
185+ | Total allocations | 40 | 4 |
186+ | InternalCallbackScope entries | 4 | 5 (one per segment + initial) |
187187
188- The coroutine frame embeds the `uv_fs_t` (~440 bytes) directly. The compiler
188+ The coroutine frame embeds the `uv_fs_t` (\ ~440 bytes) directly. The compiler
189189may overlay non-simultaneously-live awaitables in the frame, so a multi-step
190190coroutine does not necessarily pay N times the `uv_fs_t` cost.
191191
0 commit comments