wired
libc-free QUIC/HTTP3 SDK in C for x86_64-linux
Loading...
Searching...
No Matches
srvworkers.h File Reference

Multi-process worker fan-out over the single-process wired_server_run: fork N shared-nothing child processes, each optionally pinned to one CPU, each running its own copy of the existing server loop unmodified. More...

Go to the source code of this file.

Data Structures

struct  wired_srvworkers_opt
 Worker fan-out policy. More...

Macros

#define WIRED_SRVWORKERS_MAX   64
 Upper bound on concurrent workers (matches the CPU pin range srvpin supports: 64 bits in an 8-byte sched_setaffinity mask).

Functions

int wired_srvworkers_run (u16 port, wired_srvboot_id *id, wired_srvrun_handler h, wired_srvrun_obs obs, const wired_srvworkers_opt *opt)
 Fork opt->workers (or CPU count if opt->workers == 0) child processes.

Detailed Description

Multi-process worker fan-out over the single-process wired_server_run: fork N shared-nothing child processes, each optionally pinned to one CPU, each running its own copy of the existing server loop unmodified.

The parent becomes a supervisor that restarts any worker that crashes.

ponytail: for N workers to actually share one UDP port, the socket wired_server_run binds must have SO_REUSEPORT enabled before bind — that wiring lives in srvrun.c's listen path (wired_udp_reuseport_enable, already implemented in transport/io/socket/io/udp.h), not here. srvworkers only forks/pins/supervises; verify separately that srvrun.c's bind path calls wired_udp_reuseport_enable before relying on multiple workers sharing a port.

KNOWN LIMITATION (workers > 1): SO_REUSEPORT's kernel-side 4-tuple hash is the ONLY thing routing a client's packets to one of the N listening sockets; unlike the AF_XDP driver (srvdriver.c WIRED_SRVDRIVER_XDP), no CID is used to steer a flow to a specific worker here. A new connection's Initial/Handshake datagrams are not guaranteed to keep landing on the worker that answered the first one – observed in practice as intermittent handshake failures / stateless resets that get MORE frequent as workers grows (measured locally: workers=1 always succeeds, workers=4 fails on roughly half of single-request attempts). This is the same class of problem as the connection-migration gap (see tasks/core-pinning-plan.md PIN-005): steering packets to the right process needs either eBPF (PIN-006, out of scope – see AF_XDP's xdpbpf.c for what that requires) or an inter-worker forwarding channel, neither of which this shared-nothing fork model has. Prefer workers=1 (or the AF_XDP driver) for anything that must reliably complete a handshake; workers>1 here is only safe for already-established, sticky-by-4-tuple traffic on a kernel/NIC combo whose reuseport hash never rebalances mid-connection.

Function Documentation

◆ wired_srvworkers_run()

int wired_srvworkers_run ( u16 port,
wired_srvboot_id * id,
wired_srvrun_handler h,
wired_srvrun_obs obs,
const wired_srvworkers_opt * opt )

Fork opt->workers (or CPU count if opt->workers == 0) child processes.

Each child, if opt->pin_cores, pins itself to CPU == its worker index via wired_srvpin_bind_self before doing anything else, then calls wired_server_run(port, id, h, obs) unmodified. wired_server_run does not return under normal operation; if it ever does, the child exits cleanly (exit_group) rather than falling into the parent's supervisor code.

The parent enters a wait4 supervisor loop: it re-forks a replacement with the SAME worker index (so pinning stays consistent) whenever a worker crashes (killed by a signal or a non-zero exit); a worker that exits 0 is not replaced. On SIGTERM the parent forwards SIGTERM once to every live worker, stops respawning, and keeps reaping. Each worker arms PR_SET_PDEATHSIG(SIGTERM), so it drains if the parent dies. The parent returns once every worker has been reaped.

Call it at most once per process, from a single-threaded caller: the SIGTERM handler and its flag are process-wide, and PR_SET_PDEATHSIG fires on the death of the forking THREAD, not the process.

Parameters
portUDP port passed through to each worker's wired_server_run
idthe fixed server identity, passed through to every worker
hthe application's request responder, passed through
obsoptional qlog/keylog/cert-reload settings, passed through
optworker count / pinning policy; 0 workers means auto-detect
Returns
negative if the initial fork() fails; 0 once every worker has been reaped (after SIGTERM, or when all exited 0).