You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
-**Utilities** — Timers, concurrent queues, signal handling
26
26
27
27
> [!NOTE]
28
-
> Some network and async-io facilities are currently only implemented using epoll and io_uring on Linux, and IOCP on Windows.
28
+
> Some network and async-io facilities are currently only implemented using epoll and io_uring on Linux (the io_uring backend requires kernel 5.19 or newer), and IOCP on Windows.
Copy file name to clipboardExpand all lines: docs/reference.md
+21-14Lines changed: 21 additions & 14 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -43,7 +43,9 @@ This document describes the public API of **coio**. It is intended to be a stabl
43
43
### Stop tokens and cancellation
44
44
45
45
- Many async operations support cooperative cancellation by [stop token](https://eel.is/c++draft/thread.stoptoken).
46
-
- Cancellation follows the sender/receiver contract: cancellation completes with `set_stopped()`.
46
+
- A stop request asks the backend to cancel; it does not overwrite an actual target-operation result.
47
+
- The receiver gets `set_stopped()` only when the cancellation path wins, for example when a pending operation is synchronously removed or the target backend reports cancellation. A target success or ordinary error remains `set_value()` or `set_error()` even if stop was requested first.
48
+
- A stop request that already exists at `start()` does not skip backend initiation. An immediate target result wins; if the operation remains pending, coio then asks the backend to cancel it.
47
49
48
50
---
49
51
@@ -131,14 +133,12 @@ auto fibonacci(std::size_t n) -> coio::generator<int> {
131
133
132
134
### 4.1 Thread-safety model
133
135
134
-
All execution contexts (`time_loop`, `epoll_context`, `uring_context` and `iocp_context`) share these guarantees:
136
+
All execution contexts (`time_loop`, `epoll_context`, `uring_context` and `iocp_context`) are **MPSC** (multi-producer, single-consumer):
135
137
136
-
- `run()` / `run_one()` can be called concurrently from multiple threads.
137
-
- `poll()` / `poll_one()` can be called concurrently from multiple threads.
138
-
- `get_scheduler()` is thread-safe.
139
-
- `request_stop()` is thread-safe.
138
+
- **Multi-producer**: any thread may concurrently start operations on a context (`schedule()`, `schedule_at()`/`schedule_after()`, and the `async_*` operations of its io objects), and `get_scheduler()`, `work_started()`/`work_finished()` and `request_stop()` are thread-safe.
139
+
- **Single-consumer**: at most one thread may be inside `run()`, `run_one()`, `poll()` or `poll_one()` for a context at a time. This is a precondition and is not checked at runtime: concurrent consumer calls are undefined behavior. The consumer thread may change over the context's lifetime (e.g. `poll()` from one thread, later `run()` from another), provided the earlier call happens-before the later one (thread join, mutex, or similar synchronization).
140
140
141
-
Work submitted to the context may be executed by **any** thread currently calling `run()`/`poll()`.
141
+
Work submitted to the context is completed by its active `run()`/`poll()` consumer thread.
142
142
143
143
### 4.2 time_loop
144
144
@@ -283,8 +283,8 @@ Be careful with the term "concurrency":
283
283
284
284
Like Asio sockets/streams, coio socket/acceptor objects are **not thread-safe**. In other words, **member functions must not be called concurrently** on the same socket/acceptor from multiple threads unless you provide external synchronization.
285
285
286
-
If you drive the owning execution context from a single thread, and ensure all socket/acceptor
287
-
operations are initiated from work running on that thread, that thread acts as an
286
+
If all socket/acceptor operations are initiated from work running on the owning execution
287
+
context's consumer thread, that thread acts as an
288
288
"implicit strand" (operations are serialized by construction).
289
289
290
290
This thread-safety rule is independent of how many operations may be outstanding.
@@ -295,6 +295,13 @@ The async interface supports the following **outstanding-operation** limits (Asi
295
295
- **Not allowed**: two reads outstanding simultaneously; likewise for writes.
296
296
- **Acceptors**: at most one outstanding `accept` / `async_accept` per acceptor.
297
297
298
+
**Lifetime**: an I/O object must outlive all of its operations. A sender obtained from an
299
+
I/O object (`async_read_some`, `async_receive`, ...) must be connected and started **before**
300
+
the object is closed or destroyed; starting it afterwards is undefined behavior. On
301
+
`epoll_context` in particular, `close()` returns the object's per-descriptor bookkeeping
302
+
entry to an internal pool, so a stale start may silently corrupt the state of an unrelated
303
+
I/O object that has since reused the entry, rather than failing cleanly with `EBADF`.
304
+
298
305
Example: the following is **malformed** because it starts two reads without waiting for the first to complete:
299
306
300
307
```cpp
@@ -315,9 +322,9 @@ co_await when_all(
315
322
);
316
323
```
317
324
318
-
If you drive an execution context from multiple threads, ensure**all initiating calls for a
319
-
given socket/acceptor are serialized** (e.g. a mutex, or funneling initiation through a single
320
-
owning thread/task).
325
+
Operations may be initiated from threads other than the context consumer, but**all initiating
326
+
calls for a given socket/acceptor must still be serialized** (e.g. a mutex, or funneling
327
+
initiation through a single owning thread/task).
321
328
322
329
### EOF behavior
323
330
@@ -347,7 +354,7 @@ These primitives suspend coroutines instead of blocking threads.
- Execution contexts: **MPSC** — one active `run/poll` consumer per context; `get_scheduler`, operation initiation, and `request_stop` may be used concurrently from other threads.
351
358
- Sync primitives: safe across coroutines potentially running on different threads.
352
359
-`async_scope`: safe to `spawn()` from multiple threads.
353
-
- Sockets/acceptors: **not thread-safe**; do not call member functions concurrently on the same object without external synchronization. Also follow the per-object outstanding-operation limits described above.
360
+
- Sockets/acceptors: **not thread-safe**; do not call member functions concurrently on the same object without external synchronization. Also follow the per-object outstanding-operation limits described above.
0 commit comments