CX Framework
Cross-platform C utility framework
Loading...
Searching...
No Matches
queue_select.h
1#pragma once
2// This header file is auto-generated!
3// Do not make changes to this file or they will be overwritten.
4// clang-format off
5#include <cx/obj.h>
6#include <cx/struct.h>
7#include <cx/net/queue.h>
8
9CX_C_BEGIN
10
11typedef struct NetQueueSelect NetQueueSelect;
12typedef struct NetQueueSelect_WeakRef NetQueueSelect_WeakRef;
13saDeclarePtr(NetQueueSelect);
14saDeclarePtr(NetQueueSelect_WeakRef);
15#define _sti_NetQueueSelect _sti_object
16#define SType_NetQueueSelect NetQueueSelect*
17#define STStorageType_NetQueueSelect NetQueueSelect*
18#define STypeArg_NetQueueSelect(type, val) stgeneric(object, (ObjInst*)objInstCheckClass(NetQueueSelect, val))
19#define STypeArgPtr_NetQueueSelect(type, val) (stgeneric*)objInstCheckClassPtr(NetQueueSelect, val)
20#define STypeCheckedArg_NetQueueSelect(type, val) stType(type), stArg(type, val)
21#define STypeCheckedPtrArg_NetQueueSelect(type, val) stType(type), stArgPtr(type, val)
22
23typedef struct NetQueueSelect_ClassIf {
24 ObjIface* _implements;
25 ObjIface* _parent;
26 size_t _size;
27
28 bool (*addSocket)(_In_ void* self, NetSocket* socket);
29 bool (*removeSocket)(_In_ void* self, NetSocket* socket);
30 NetSocket* (*socket)(_In_ void* self, NetSocketType type);
31 // Begin one outbound connect attempt against a single resolved address
32 // // The one backend-specific piece of connect. By the time this is called, the portable state
33 // machine has already picked the address and armed the deadline; this just gets a fresh OS
34 // handle of the address's family and starts the attempt. A readiness backend resets the
35 // handle, issues a non-blocking connect(), and watches it for writability (and the except
36 // set, where Windows signals a failed connect). A completion backend resets and binds the
37 // handle and posts an overlapped ConnectEx.
38 // // The outcome is reported back through netsocket_connectResult() -- immediately for a
39 // synchronous result, or later from readiness, a completion, or the timeout sweep.
40 // // @param sock Socket to connect (a stream socket in NS_Connecting)
41 // @param addr Address to attempt
42 // @return true if the attempt was initiated or resolved, false if it could not be started
43 bool (*connectBegin)(_In_ void* self, NetSocket* sock, const NetAddr* addr);
44 // React to a socket having just become connected
45 // // Called once, after a successful connect has transitioned the socket to NS_Connected and
46 // its NET_Connection event has been queued. The backend starts servicing the socket for
47 // receive here -- select rebuilds its watch set to read-watch it, IOCP posts the first
48 // WSARecv -- the same thing addSocket() does for a socket that was already connected when it
49 // joined the queue.
50 // // @param sock Socket that just connected
51 void (*connectArm)(_In_ void* self, NetSocket* sock);
52 // Begin (or resume) accepting connections on a now-listening socket
53 // // The accept-side counterpart of connectArm. Called once the socket enters NS_Listening --
54 // from the platform listen(), or from addSocket() if the socket was already listening when
55 // it joined the queue. A readiness backend wakes its loop so the next rebuild read-watches
56 // the listener; a completion backend posts its initial batch of overlapped AcceptEx
57 // operations. Each accepted connection is wrapped and handed to netsocket_accepted().
58 // // @param sock Listening socket (a stream socket in NS_Listening)
59 void (*acceptArm)(_In_ void* self, NetSocket* sock);
60 bool (*shutdown)(_In_ void* self, int64 timeout);
61 bool (*tick)(_In_ void* self, int64 wait);
62} NetQueueSelect_ClassIf;
63extern NetQueueSelect_ClassIf NetQueueSelect_ClassIf_tmpl;
64
65typedef struct NetQueueSelect {
66 union {
67 NetQueueSelect_ClassIf* _;
68 void* _is_NetQueueSelect;
69 void* _is_NetQueue;
70 void* _is_ObjInst;
71 };
72 ObjClassInfo* _clsinfo;
73 atomic(uintptr) _ref;
74 atomic(ptr) _weakref;
75
76 NetQueueConfig conf;
82 NetHandlers handlers;
83 void* handlerCtx;
86 Weak(ObjInst)* handlerWeak;
87 RWLock handlerLock;
88 hashtable sockets;
89 RWLock lock;
95 PrQueue runq;
101 NetPool* pool;
107 atomic(uint32) gcLastLo;
112 atomic(uint32) droppedNoBuf;
113 atomic(uint32) nflows;
117 NetTimerEntry* timers;
118 uint32 ntimers;
119 uint32 timersCap;
120 uint64 timerSerial;
121 hashtable timerIdx;
125 Mutex timerLock;
126 atomic(uint32) timersLive;
132 sa_Thread workers;
133 Semaphore runqSema;
134 atomic(uint32) shutdownReq;
141 NetSendPumpFn sendPump;
142 void* sendCtx;
147 NetWakeFn wake;
148 void* wakeCtx;
149 // NetSelectSet* (opaque), created and destroyed by hand
150 // // Held as void* so the private NetSelectSet declaration does not have to leak into this
151 // generated header. Cast back in the implementation.
152 void* selset;
153 // Handle -> socket for the current tick, each entry holding a strong reference
154 // // Rebuilt every tick under the socket lock. Holding a reference means a socket removed by
155 // another thread mid-tick stays alive until the map is cleared at the top of the next tick,
156 // so ingest never touches freed memory. The object value type manages the references.
157 hashtable fdmap;
158 // Dedicated select-loop thread in threaded mode (NULL in polled mode)
159 // // select() cannot usefully be shared across threads -- one fd_set, one wait -- so threaded
160 // mode runs exactly one ingest thread here that fills the runqueue, plus the base class's N
161 // dispatch workers that drain it. In polled mode this stays NULL and tick() runs the loop on
162 // the caller's thread. Joined (via nselWake + thrWait) before it is released, in shutdown or as
163 // a destroy-time safety net.
164 Thread* ingest;
165} NetQueueSelect;
166extern ObjClassInfo NetQueueSelect_clsinfo;
167#define NetQueueSelect(inst) objInstCheckClass(NetQueueSelect, inst)
168#define NetQueueSelectNone ((NetQueueSelect*)NULL)
169
170typedef struct NetQueueSelect_WeakRef {
171 union {
172 ObjInst* _inst;
173 void* _is_NetQueueSelect_WeakRef;
174 void* _is_NetQueue_WeakRef;
175 void* _is_ObjInst_WeakRef;
176 };
177 atomic(uintptr) _ref;
178 RWLock _lock;
179} NetQueueSelect_WeakRef;
180#define NetQueueSelect_WeakRef(inst) objWeakRefCheckClass(NetQueueSelect, inst)
181
182_objfactory_guaranteed NetQueueSelect* NetQueueSelect_create(NetQueueConfig* conf);
183// NetQueueSelect* netqueueselectCreate(NetQueueConfig* conf);
184#define netqueueselectCreate(conf) NetQueueSelect_create(conf)
185
186// NetSocket* netqueueselectConnect(NetQueueSelect* self, strref host, uint16 port, const NetHandlers* handlers, void* ctx);
187#define netqueueselectConnect(self, host, port, handlers, ctx) NetQueue_connect(NetQueue(self), host, port, handlers, ctx)
188
189// NetSocket* netqueueselectConnectPrep(NetQueueSelect* self, strref host, uint16 port, const NetHandlers* handlers, void* ctx, NetConnectPrepCB prep, void* prepctx);
190#define netqueueselectConnectPrep(self, host, port, handlers, ctx, prep, prepctx) NetQueue_connectPrep(NetQueue(self), host, port, handlers, ctx, prep, prepctx)
191
192// NetSocket* netqueueselectListen(NetQueueSelect* self, const NetAddr* addr, int backlog, const NetHandlers* handlers, void* ctx);
193#define netqueueselectListen(self, addr, backlog, handlers, ctx) NetQueue_listen(NetQueue(self), addr, backlog, handlers, ctx)
194
195// void netqueueselectSetHandlers(NetQueueSelect* self, const NetHandlers* handlers, void* ctx);
196#define netqueueselectSetHandlers(self, handlers, ctx) NetQueue_setHandlers(NetQueue(self), handlers, ctx)
197
198// void netqueueselectSetHandlersObj(NetQueueSelect* self, const NetHandlers* handlers, ObjInst* ctx);
199#define netqueueselectSetHandlersObj(self, handlers, ctx) NetQueue_setHandlersObj(NetQueue(self), handlers, ObjInst(ctx))
200
201// NetFlow* netqueueselectPromoteFlow(NetQueueSelect* self, NetSocket* sock, const NetAddr* peer);
202#define netqueueselectPromoteFlow(self, sock, peer) NetQueue_promoteFlow(NetQueue(self), sock, peer)
203
204// uint32 netqueueselectDroppedNoBuf(NetQueueSelect* self);
205#define netqueueselectDroppedNoBuf(self) NetQueue_droppedNoBuf(NetQueue(self))
206
207// void netqueueselect_applyConfig(NetQueueSelect* self, const NetQueueConfig* conf);
208//
209// -----------------------------------------------------------------------------------------
210// PRIVATE IMPLEMENTATION DETAILS
211// // Everything below this point is internal plumbing between the net module's own translation
212// units and the platform backends. It is not a stable API and carries no compatibility
213// promise -- signatures and semantics change whenever the implementation needs them to.
214// -----------------------------------------------------------------------------------------
215// Construction (queue.c)
216// Apply a configuration to a queue under construction. Called by a backend's factory before
217// objInstInit(), so that the sizes everything else is built from are already in place when the
218// base class initializes. `conf` is NULL for the client preset.
219#define netqueueselect_applyConfig(self, conf) NetQueue__applyConfig(NetQueue(self), conf)
220
221// void netqueueselect_startWorkers(NetQueueSelect* self, int32 n);
222//
223// Worker pool (queue.c)
224// // The generic dispatch pool the base class owns: N threads that drain the runqueue and block
225// on runqSema when it is empty. A backend's factory starts them in threaded mode; polled
226// queues never call these and run everything on the caller's tick() thread.
227// Start n dispatch worker threads. Fewer may end up running if thread creation fails; the
228// actual count lands in self->workers.
229#define netqueueselect_startWorkers(self, n) NetQueue__startWorkers(NetQueue(self), n)
230
231// void netqueueselect_stopWorkers(NetQueueSelect* self, int64 timeout);
232//
233// Ask every dispatch worker to exit and join it. Each worker drains the runqueue one last time
234// on its way out, so terminal events queued during shutdown are still delivered. `timeout`
235// <= 0 waits indefinitely. Idempotent -- safe to call when no workers are running.
236#define netqueueselect_stopWorkers(self, timeout) NetQueue__stopWorkers(NetQueue(self), timeout)
237
238// bool netqueueselect_ingestDatagram(NetQueueSelect* self, NetSocket* sock, NetAddr* peer, const NetPktInfo* info, Buffer* buf);
239//
240// Ingest (queue.c)
241// // Where a packet enters the core. _ingestDatagram is the datagram front door and belongs to the
242// queue; _submit is the runqueue's producer half and lives beside its consumer in dispatch.c.
243// Hand a received datagram to the core for demultiplexing and dispatch. Takes ownership of
244// `buf`, which must have come from the queue's own buffer pool. Resolves the flow for the
245// source address (creating one, reclaiming under cap pressure, or falling back to the
246// flowRefused handler), pushes the packet onto that flow's inbox, and enqueues the flow if it
247// was idle. Returns true if the packet was queued to a flow, false if it was dropped or handed
248// to a NET_FlowRefused handler instead.
249#define netqueueselect_ingestDatagram(self, sock, peer, info, buf) NetQueue__ingestDatagram(NetQueue(self), sock, peer, info, buf)
250
251// void netqueueselect_submit(NetQueueSelect* self, NetFlow* flow, NetMessage* msg);
252//
253// Hand a message to a flow and make sure something will come along to run it. Takes ownership
254// of the message. `self` may be NULL, in which case the message is simply released.
255#define netqueueselect_submit(self, flow, msg) NetQueue__submit(NetQueue(self), flow, msg)
256
257// bool netqueueselect_dispatch(NetQueueSelect* self);
258//
259// Dispatch (dispatch.c)
260// // The runqueue and the event delivery it feeds. _submit above is the producer half of the same
261// claim protocol _dispatch consumes.
262// Claim one flow from the runqueue and drain it. This is the body of a worker thread, and it
263// is also what tick() runs inline in polled mode -- the same code either way, just without the
264// threads. Returns false if the runqueue was empty.
265#define netqueueselect_dispatch(self) NetQueue__dispatch(NetQueue(self))
266
267// void netqueueselect_deliver(NetQueueSelect* self, NetSocket* sock, NetFlow* flow, NetEvent* ev);
268//
269// Resolve and invoke the handler for an event, filling in the event's queue/socket/flow/ctx
270// fields; a no-op when no level supplies a handler. In dev builds the callback is timed, and
271// one that holds its worker past the warning threshold gets logged with the socket and event
272// type -- handlers are expected to return quickly, and this is how we notice when one doesn't.
273// Every callback invocation should go through here so timing stays consistent. `self` may be
274// NULL, in which case only the socket and flow levels are consulted.
275#define netqueueselect_deliver(self, sock, flow, ev) NetQueue__deliver(NetQueue(self), sock, flow, ev)
276
277// void netqueueselect_maint(NetQueueSelect* self);
278//
279// Maintenance (queue.c)
280// Opportunistic GC of the queue's dynamic PrQueues (runqueue and receive pool). Call it from a
281// thread that has just drained the runqueue and is about to idle -- the moment the PrQueue
282// docs recommend for collection. Time-gated and single-runner, so a whole worker pool or a
283// tight poll loop costs one GC attempt per interval; safe to call as often as convenient.
284#define netqueueselect_maint(self) NetQueue__maint(NetQueue(self))
285
286// NetTimerId netqueueselect_addTimer(NetQueueSelect* self, NetFlow* flow, int64 delay, flags_t flags, NetTimerFn fn, void* ctx);
287//
288// Timers (timer.c)
289// // The queue-wide deadline heap behind netflowAddTimer(). Backends drive it with two calls per
290// wait: _nextDeadline() to bound the sleep, and _timerSweep() to fire whatever came due.
291// Arm a timer on a flow, `delay` microseconds from now. `fn` is NULL for an application timer
292// (delivered as NET_Timer through the flow's inbox) or a framework hook fired inline on the
293// sweeping thread. Returns the new id, or 0 if the flow is already dying or has no queue.
294#define netqueueselect_addTimer(self, flow, delay, flags, fn, ctx) NetQueue__addTimer(NetQueue(self), flow, delay, flags, fn, ctx)
295
296// bool netqueueselect_cancelTimer(NetQueueSelect* self, NetTimerId id);
297//
298// Cancel an armed timer. Returns true only if this call removed it from the heap -- a timer
299// already popped for delivery answers false. A successful cancel means the caller is the one
300// that gets to act on it. Cancelling an unknown or already-fired id is a harmless false.
301#define netqueueselect_cancelTimer(self, id) NetQueue__cancelTimer(NetQueue(self), id)
302
303// bool netqueueselect_rearmTimer(NetQueueSelect* self, NetTimerId id, int64 delay);
304//
305// Move an armed timer's deadline to `delay` microseconds from now. Returns false if the timer
306// is not armed (cancelled, or already popped for delivery).
307#define netqueueselect_rearmTimer(self, id, delay) NetQueue__rearmTimer(NetQueue(self), id, delay)
308
309// void netqueueselect_cancelFlowTimers(NetQueueSelect* self, NetFlow* flow);
310//
311// Cancel every timer armed on a flow. Called on the flow's terminal path so a long deadline on
312// a dead connection cannot keep the flow object alive until it expires.
313#define netqueueselect_cancelFlowTimers(self, flow) NetQueue__cancelFlowTimers(NetQueue(self), flow)
314
315// void netqueueselect_timerSweep(NetQueueSelect* self);
316//
317// Fire every timer whose deadline has passed. A no-op on one relaxed load while nothing is
318// armed. Entries are popped under timerLock and fired outside it, so a callback is free to arm,
319// cancel, or send. Called by every backend right after its wait returns, beside _maint().
320#define netqueueselect_timerSweep(self) NetQueue__timerSweep(NetQueue(self))
321
322// int64 netqueueselect_nextDeadline(NetQueueSelect* self);
323//
324// The nearest armed deadline in absolute clockTimer() microseconds, or 0 if nothing is armed.
325// Backends cap their wait to this so a timer fires close to when it is due rather than on the
326// next unrelated wakeup.
327#define netqueueselect_nextDeadline(self) NetQueue__nextDeadline(NetQueue(self))
328
329// NetFlow* netqueueselect_findFlow(NetQueueSelect* self, NetSocket* sock, NetAddr* peer, bool create);
330//
331// Flow table and lifecycle (flow.c)
332// Find the flow for a peer address, creating one if there is room under the cap. Returns a
333// strong reference the caller must release, or NULL if the queue is at its cap and nothing
334// could be reclaimed -- in which case the caller should fall back to the flowRefused handler.
335// A stream or QUIC socket has no address-keyed table, so `peer` is ignored there and the
336// socket's single control flow is returned.
337#define netqueueselect_findFlow(self, sock, peer, create) NetQueue__findFlow(NetQueue(self), sock, peer, create)
338
339// NetFlow* netqueueselect_admitFlow(NetQueueSelect* self, NetSocket* sock, NetAddr* peer);
340//
341// Create a flow for a peer and register it with the socket, bypassing the cap check. Returns a
342// strong reference the caller must release. A thin wrapper over _admitFlowObj below.
343#define netqueueselect_admitFlow(self, sock, peer) NetQueue__admitFlow(NetQueue(self), sock, peer)
344
345// NetFlow* netqueueselect_admitFlowObj(NetQueueSelect* self, NetSocket* sock, NetFlow* flow);
346//
347// Register an already-constructed flow with its socket: build its filter chain, publish it in
348// the socket's table (keyed on `peer` for a datagram socket, `key` for a QUIC one), count it
349// against the queue, queue its NET_FlowOpen ahead of anything else that could land in its
350// inbox, and prime the chain. Split out of _admitFlow so cxquic can register a NetFlow
351// subclass of its own for a QUIC stream.
352// // Consumes the caller's reference and returns the one to use, which is normally the same flow
353// -- but is the winner's flow when another thread inserted the same key first, and NULL if the
354// table lost it. Do not use `flow` after the call; use the return value.
355#define netqueueselect_admitFlowObj(self, sock, flow) NetQueue__admitFlowObj(NetQueue(self), sock, flow)
356
357// uint32 netqueueselect_reclaimFlows(NetQueueSelect* self, NetSocket* sock);
358//
359// Mark up to reclaimBatch least-recently-active flows on this socket for teardown, skipping
360// flows active more recently than reclaimMinIdle allows. Runs inline on the ingest path at the
361// moment of a cap hit; there is no timer thread.
362#define netqueueselect_reclaimFlows(self, sock) NetQueue__reclaimFlows(NetQueue(self), sock)
363
364// bool netqueueselectAddSocket(NetQueueSelect* self, NetSocket* socket);
365#define netqueueselectAddSocket(self, socket) (self)->_->addSocket(NetQueueSelect(self), socket)
366// bool netqueueselectRemoveSocket(NetQueueSelect* self, NetSocket* socket);
367#define netqueueselectRemoveSocket(self, socket) (self)->_->removeSocket(NetQueueSelect(self), socket)
368// NetSocket* netqueueselectSocket(NetQueueSelect* self, NetSocketType type);
369#define netqueueselectSocket(self, type) (self)->_->socket(NetQueueSelect(self), type)
370// bool netqueueselectConnectBegin(NetQueueSelect* self, NetSocket* sock, const NetAddr* addr);
371//
372// Begin one outbound connect attempt against a single resolved address
373// // The one backend-specific piece of connect. By the time this is called, the portable state
374// machine has already picked the address and armed the deadline; this just gets a fresh OS
375// handle of the address's family and starts the attempt. A readiness backend resets the
376// handle, issues a non-blocking connect(), and watches it for writability (and the except
377// set, where Windows signals a failed connect). A completion backend resets and binds the
378// handle and posts an overlapped ConnectEx.
379// // The outcome is reported back through netsocket_connectResult() -- immediately for a
380// synchronous result, or later from readiness, a completion, or the timeout sweep.
381// // @param sock Socket to connect (a stream socket in NS_Connecting)
382// @param addr Address to attempt
383// @return true if the attempt was initiated or resolved, false if it could not be started
384#define netqueueselectConnectBegin(self, sock, addr) (self)->_->connectBegin(NetQueueSelect(self), sock, addr)
385// void netqueueselectConnectArm(NetQueueSelect* self, NetSocket* sock);
386//
387// React to a socket having just become connected
388// // Called once, after a successful connect has transitioned the socket to NS_Connected and
389// its NET_Connection event has been queued. The backend starts servicing the socket for
390// receive here -- select rebuilds its watch set to read-watch it, IOCP posts the first
391// WSARecv -- the same thing addSocket() does for a socket that was already connected when it
392// joined the queue.
393// // @param sock Socket that just connected
394#define netqueueselectConnectArm(self, sock) (self)->_->connectArm(NetQueueSelect(self), sock)
395// void netqueueselectAcceptArm(NetQueueSelect* self, NetSocket* sock);
396//
397// Begin (or resume) accepting connections on a now-listening socket
398// // The accept-side counterpart of connectArm. Called once the socket enters NS_Listening --
399// from the platform listen(), or from addSocket() if the socket was already listening when
400// it joined the queue. A readiness backend wakes its loop so the next rebuild read-watches
401// the listener; a completion backend posts its initial batch of overlapped AcceptEx
402// operations. Each accepted connection is wrapped and handed to netsocket_accepted().
403// // @param sock Listening socket (a stream socket in NS_Listening)
404#define netqueueselectAcceptArm(self, sock) (self)->_->acceptArm(NetQueueSelect(self), sock)
405// bool netqueueselectShutdown(NetQueueSelect* self, int64 timeout);
406#define netqueueselectShutdown(self, timeout) (self)->_->shutdown(NetQueueSelect(self), timeout)
407// bool netqueueselectTick(NetQueueSelect* self, int64 wait);
408#define netqueueselectTick(self, wait) (self)->_->tick(NetQueueSelect(self), wait)
409
410CX_C_END
#define saDeclarePtr(name)
Definition sarray.h:100
NetSocketType
Socket types.
Definition net_shared.h:134
#define Weak(clsname)
Definition objclass.h:162
#define _objfactory_guaranteed
Definition objimpl.h:106
CX Struct System - Introspectable, serializable POD structures in C.
CX Object System - Object-oriented programming in C.
Definition mutex.h:60
Set of event handlers, registered per flow, per socket, or queue-wide.
Definition net_shared.h:678
Shared, capped pool of network message buffers and headers.
Definition pool.h:51
Counting semaphore synchronization primitive.
Definition sema.h:46