Configuration
The io_context_options struct provides runtime tuning knobs for the
I/O context and its backend scheduler. The defaults listed in the
table below are the struct field defaults — the values you get from a
freshly default-constructed io_context_options.
|
The inline budget defaults in the table are not what an
|
#include <boost/corosio/io_context.hpp>
corosio::io_context_options opts;
opts.max_events_per_poll = 256;
opts.inline_budget_max = 32;
corosio::io_context ioc(opts);
Both io_context and native_io_context accept options:
#include <boost/corosio/native/native_io_context.hpp>
corosio::io_context_options opts;
opts.max_events_per_poll = 512;
corosio::native_io_context<corosio::epoll> ioc(opts);
Available Options
| Option | Default | Backends | Description |
|---|---|---|---|
128 |
epoll, kqueue |
Number of events fetched per reactor poll call. Larger values reduce syscall frequency under high load; smaller values improve fairness between connections. |
|
2 |
epoll, kqueue, select |
Starting inline completion budget per handler chain. After a posted handler executes, the reactor grants this many speculative inline completions before forcing a re-queue. |
|
16 |
epoll, kqueue, select |
Hard ceiling on adaptive inline budget ramp-up. The budget doubles each cycle it is fully consumed, up to this limit. |
|
4 |
epoll, kqueue, select |
Inline budget when no other thread is running the event loop. Prevents a single-threaded context from starving connections. |
|
1 |
POSIX (epoll, kqueue, select) |
Number of worker threads in the shared thread pool used for blocking file I/O and DNS resolution. Ignored on IOCP where file I/O uses native overlapped I/O. |
|
all |
Locking-safety tier: |
||
false |
io_uring |
Enable |
|
0 |
io_uring |
Idle timeout of the SQ-poll kernel thread, in milliseconds. After
that many milliseconds without submissions the thread sleeps, and the
next submit re-wakes it. |
|
-1 |
io_uring |
CPU to pin the SQ-poll kernel thread to; |
Options that do not apply to the active backend are silently ignored.
Three options are validated on some I/O backends.
On POSIX, a thread_pool_size
less than 1 causes construction to throw std::invalid_argument.
On the epoll, kqueue, and select I/O backends, construction throws
std::out_of_range when
max_events_per_poll is
outside [1, INT_MAX] or
inline_budget_max exceeds
INT_MAX.
Tuning Guidelines
Event Buffer Size (max_events_per_poll)
The event buffer controls how many I/O events are fetched in a single
epoll_wait() or kevent() call.
-
High-throughput streaming (few connections, high bandwidth): increase to 256-512 to reduce syscall overhead.
-
Many idle connections (chat servers, WebSocket hubs): keep at 128 or lower for better fairness.
Inline Completion Budget
The inline budget controls how many I/O completions the reactor completes speculatively within a single handler chain before forcing a re-queue through the scheduler.
-
Streaming workloads (file transfer, video):
inline_budget_max = 32or higher reduces context switches. -
Request-response workloads (HTTP, RPC): keep at 16 to prevent one connection from monopolizing a thread.
-
Single-threaded contexts:
unassisted_budgetcaps the budget when only one thread is running the event loop, preserving fairness. -
Disable the fast path entirely: set all three options to 0 to force a re-queue on every completion. This is useful as a baseline, or when a workload is dominated by cross-thread work-stealing.
|
The struct defaults are |
Thread Pool Size (thread_pool_size)
On POSIX platforms, DNS resolution uses a shared thread pool. On the
epoll, kqueue, and select I/O backends, file I/O (stream_file,
random_access_file) uses it too.
-
Concurrent file operations: increase to match expected parallelism (e.g. 4 for four concurrent file reads). The whole set starts at once on the first file or resolver call. A larger pool therefore makes that one call more expensive and no other.
-
No file I/O: leave at 1. The pool is created with the context, but its workers start on the first file or resolver operation, so a pool nothing uses costs nothing.
Locking Tiers (locking)
The locking option selects which internal locks the scheduler and
reactor elide, trading thread-safety guarantees for reduced
synchronization overhead. It governs the thread-safety contract,
independently of the concurrency_hint (see
Concurrency hint and locking tier).
| Tier | Behavior |
|---|---|
|
Full thread safety. All locks enabled; any thread may use the context. |
|
Disables only the per-descriptor I/O locks; scheduler locking stays on. A single thread must run and drive the context, but DNS resolution and POSIX file I/O remain available (they rely on scheduler locking). |
|
Disables all locking. Eliminates 15-25% of overhead on the post-and-dispatch hot path. Imposes the full restrictions below. |
corosio::io_context_options opts;
opts.locking = corosio::locking_mode::unsafe;
corosio::io_context ioc(opts);
ioc.run(); // only one thread may call this
The unsafe and unsafe_io tiers impose hard restrictions.
Violating them is undefined behavior.
|
-
Only one thread may call
run()(or any run/poll variant). -
Posting work from another thread is undefined behavior.
-
Signal sets should not be shared across contexts.
-
Delay and timeout cancellation via
stop_tokenfrom another thread is not permitted. The cancel path posts into the scheduler, and these tiers permit no cross-thread posting. Cross-thread cancellation requires thesafetier.
The unsafe tier additionally makes:
-
DNS resolution on POSIX return
operation_not_supported. -
File I/O (
stream_file,random_access_file) on the epoll, kqueue, and select I/O backends returnoperation_not_supportedonopen(). -
win_object_handlereturnoperation_not_supportedonassign(). The Windows thread pool completes its waits from a foreign thread.
These stay available under unsafe_io because they rely
on scheduler locking, which that tier keeps enabled.
|
These tiers correspond to Boost.Asio’s |
Concurrency hint and locking tier
The concurrency_hint is a performance tuning value indicating how many
threads are expected to call run(). It tunes the reactor inline-completion
budget defaults and, on IOCP, the completion-port concurrency. The
unsafe_io and unsafe tiers are single-threaded, so their effective hint
for that tuning is 1 regardless of the value passed.