ascii-chat
Binary v0.15.83-53-gb711d8720
Library lib/v0.3.2-701-gb711d8720
Video chat in your terminal
Loading...
Searching...
No Matches
event.c File Reference

Go to the source code of this file.

Data Structures

struct  event_command_t
struct  platform_event_loop
struct  platform_event_stream
 The useful part of event write is in request, stream, done, arg: together they describe what is pending, who owns it, and how much data is valid. Keep the object with its parent operation and use the parent cleanup path. More...
struct  platform_event_listener
 platform event stream is intentionally a small, concrete record. Fields such as listener, owner, tcp, timer give callers the identity and current value they need. It is normally borrowed from, or owned by, the surrounding subsystem—not independently managed. More...
struct  event_write
struct  event_work_t
 event command keeps the values that move through the subsystem: fn, arg. Some members are pointers into caller- or subsystem-owned memory, so lifetime follows the API that populated them rather than the struct copy itself. More...
struct  loop_work_t
 This is the handoff point for event work. Callers fill work, stream, run, done before passing it on; consumers read the values during the operation and return ownership only where the member contract explicitly says they do. More...

Macros

#define EVENT_COMMAND_LIMIT   1024
#define EVENT_WRITE_LIMIT   (16U * 1024U * 1024U)
#define EVENT_WRITE_COUNT_LIMIT   4096
#define EVENT_READ_SIZE   65536

Typedefs

typedef struct event_write event_write_t

Functions

void platform_event_stream_close (platform_event_stream_t *stream, asciichat_error_t reason)
void platform_event_listener_close (platform_event_listener_t *listener)
asciichat_error_t platform_event_loop_create (platform_event_loop_t **out)
asciichat_error_t platform_event_loop_run (platform_event_loop_t *loop)
asciichat_error_t platform_event_loop_post (platform_event_loop_t *loop, platform_event_task_fn fn, void *arg)
void platform_event_loop_stop (platform_event_loop_t *loop)
asciichat_error_t platform_event_loop_destroy (platform_event_loop_t *loop)
const char * platform_event_backend (void)
asciichat_error_t platform_event_loop_tick (platform_event_loop_t *loop, uint64_t interval, platform_event_task_fn fn, void *arg)
asciichat_error_t platform_event_stream_start (platform_event_stream_t *stream, platform_event_read_fn read, platform_event_close_fn close, void *arg)
void platform_event_stream_pause (platform_event_stream_t *stream)
asciichat_error_t platform_event_stream_resume (platform_event_stream_t *stream)
asciichat_error_t platform_event_stream_deadline (platform_event_stream_t *stream, uint64_t timeout_ms)
asciichat_error_t platform_event_stream_adopt (platform_event_loop_t *loop, socket_t *socket, platform_event_stream_t **out)
asciichat_error_t platform_event_listen (platform_event_loop_t *loop, socket_t *socket, platform_event_accept_fn accept, void *arg, platform_event_listener_t **out)
void platform_event_stream_set_zerocopy (platform_event_stream_t *stream, bool enabled)
void platform_event_stream_request_close (platform_event_stream_t *stream, asciichat_error_t reason)
asciichat_error_t platform_event_stream_write (platform_event_stream_t *stream, const socket_buffer_t *buffers, size_t count, platform_event_write_fn done, void *arg)
size_t platform_event_stream_queued_bytes (const platform_event_stream_t *stream)
void platform_event_stream_observe_queue (platform_event_stream_t *stream, platform_event_queue_fn observer, void *context)
asciichat_error_t platform_event_loop_work (platform_event_loop_t *loop, platform_event_task_fn run, platform_event_task_fn done, void *arg)
asciichat_error_t platform_event_stream_work (platform_event_stream_t *stream, platform_event_work_fn run, platform_event_work_done_fn done, void *arg)
asciichat_error_t platform_event_stream_peer (platform_event_stream_t *stream, struct sockaddr_storage *address, socklen_t *length)

Macro Definition Documentation

◆ EVENT_COMMAND_LIMIT

#define EVENT_COMMAND_LIMIT   1024

Definition at line 7 of file event.c.

Referenced by platform_event_loop_post().

◆ EVENT_READ_SIZE

#define EVENT_READ_SIZE   65536

Definition at line 10 of file event.c.

◆ EVENT_WRITE_COUNT_LIMIT

#define EVENT_WRITE_COUNT_LIMIT   4096

Definition at line 9 of file event.c.

Referenced by platform_event_stream_write().

◆ EVENT_WRITE_LIMIT

#define EVENT_WRITE_LIMIT   (16U * 1024U * 1024U)

Definition at line 8 of file event.c.

Referenced by platform_event_stream_write().

Typedef Documentation

◆ event_write_t

typedef struct event_write event_write_t

Function Documentation

◆ platform_event_backend()

const char * platform_event_backend ( void )

Definition at line 279 of file event.c.

279 {
280#ifdef _WIN32
281 return "iocp";
282#elif defined(__linux__)
283 return "epoll";
284#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
285 return "kqueue";
286#else
287 return "libuv";
288#endif
289}

◆ platform_event_listen()

asciichat_error_t platform_event_listen ( platform_event_loop_t * loop,
socket_t * socket,
platform_event_accept_fn accept,
void * arg,
platform_event_listener_t ** out )

Sets *socket to INVALID_SOCKET_VALUE when ownership transfers, including if listen subsequently fails. Accepted streams are owned by the loop until their close callback returns. Set callbacks in the accept callback.

Definition at line 451 of file event.c.

452 {
453 if (!loop || !socket || !accept || !out)
454 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid event listener");
455 *out = NULL;
456 platform_event_listener_t *listener = SAFE_CALLOC(1, sizeof(*listener), platform_event_listener_t *);
457 int status = uv_tcp_init(&loop->uv, &listener->tcp);
458 if (status < 0) {
459 SAFE_FREE(listener);
460 return event_error(status, "Initialize listener");
461 }
462 listener->tcp.data = listener;
463 listener->listener = true;
464 listener->accept = accept;
465 listener->arg = arg;
466 status = uv_tcp_open(&listener->tcp, (uv_os_sock_t)*socket);
467 if (status < 0) {
468 uv_close((uv_handle_t *)&listener->tcp, listener_closed);
469 return event_error(status, "Adopt listener");
470 }
471 *socket = INVALID_SOCKET_VALUE;
472 status = uv_listen((uv_stream_t *)&listener->tcp, 128, accepted);
473 if (status < 0) {
474 // Adoption has succeeded: the loop owns the descriptor even if listen fails.
475 uv_close((uv_handle_t *)&listener->tcp, listener_closed);
476 return event_error(status, "Listen");
477 }
478 *out = listener;
479 return ASCIICHAT_OK;
480}
#define SET_ERRNO(code,...)
struct platform_event_listener platform_event_listener_t
Definition event.h:13
#define SAFE_FREE(ptr)
Definition common.h:377
#define SAFE_CALLOC(count, size, cast)
Definition common.h:275
@ ASCIICHAT_OK
Definition error_codes.h:46
@ ERROR_INVALID_PARAM
static bool size_t gotel_query_t * out
Definition queries.h:8
platform_event_accept_fn accept
Definition event.c:79
uv_loop_t uv
Definition event.c:22

References platform_event_listener::accept, platform_event_listener::arg, ASCIICHAT_OK, ERROR_INVALID_PARAM, platform_event_listener::listener, out, SAFE_CALLOC, SAFE_FREE, SET_ERRNO, platform_event_listener::tcp, and platform_event_loop::uv.

◆ platform_event_listener_close()

void platform_event_listener_close ( platform_event_listener_t * listener)

Definition at line 165 of file event.c.

165 {
166 if (listener && !uv_is_closing((uv_handle_t *)&listener->tcp))
167 uv_close((uv_handle_t *)&listener->tcp, listener_closed);
168}

References platform_event_listener::tcp.

◆ platform_event_loop_create()

asciichat_error_t platform_event_loop_create ( platform_event_loop_t ** out)

Definition at line 205 of file event.c.

205 {
206 if (!out)
207 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing event loop output");
208 *out = NULL;
209 platform_event_loop_t *loop = SAFE_CALLOC(1, sizeof(*loop), platform_event_loop_t *);
210 int status = uv_loop_init(&loop->uv);
211 if (status < 0) {
212 SAFE_FREE(loop);
213 return event_error(status, "Initialize event loop");
214 }
215 status = uv_mutex_init(&loop->mutex);
216 if (status < 0) {
217 uv_loop_close(&loop->uv);
218 SAFE_FREE(loop);
219 return event_error(status, "Initialize event queue");
220 }
221 status = uv_async_init(&loop->uv, &loop->wake, wake_loop);
222 if (status < 0) {
223 uv_mutex_destroy(&loop->mutex);
224 uv_loop_close(&loop->uv);
225 SAFE_FREE(loop);
226 return event_error(status, "Initialize event wakeup");
227 }
228 loop->wake.data = loop;
229 loop->uv.data = loop;
230 *out = loop;
231 return ASCIICHAT_OK;
232}
struct platform_event_loop platform_event_loop_t
Definition event.h:11
uv_mutex_t mutex
Definition event.c:29
uv_async_t wake
Definition event.c:23

References ASCIICHAT_OK, ERROR_INVALID_PARAM, platform_event_loop::mutex, out, SAFE_CALLOC, SAFE_FREE, SET_ERRNO, platform_event_loop::uv, and platform_event_loop::wake.

Referenced by acip_async_tcp_client_create().

◆ platform_event_loop_destroy()

asciichat_error_t platform_event_loop_destroy ( platform_event_loop_t * loop)

Definition at line 268 of file event.c.

268 {
269 if (!loop)
270 return ASCIICHAT_OK;
271 int status = uv_loop_close(&loop->uv);
272 if (status < 0)
273 return event_error(status, "Destroy event loop (stop and join first)");
274 uv_mutex_destroy(&loop->mutex);
275 SAFE_FREE(loop);
276 return ASCIICHAT_OK;
277}

References ASCIICHAT_OK, platform_event_loop::mutex, SAFE_FREE, and platform_event_loop::uv.

◆ platform_event_loop_post()

asciichat_error_t platform_event_loop_post ( platform_event_loop_t * loop,
platform_event_task_fn fn,
void * arg )

Definition at line 241 of file event.c.

241 {
242 if (!loop || !fn)
243 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing event command");
244 uv_mutex_lock(&loop->mutex);
245 if (loop->stopping || loop->count == EVENT_COMMAND_LIMIT) {
246 uv_mutex_unlock(&loop->mutex);
247 return SET_ERRNO(ERROR_INVALID_STATE, "Event queue stopped or full");
248 }
249 loop->commands[(loop->head + loop->count) % EVENT_COMMAND_LIMIT] = (event_command_t){fn, arg};
250 ++loop->count;
251 // Keep the wake handle alive until this send has finished.
252 uv_async_send(&loop->wake);
253 uv_mutex_unlock(&loop->mutex);
254 return ASCIICHAT_OK;
255}
#define EVENT_COMMAND_LIMIT
Definition event.c:7
@ ERROR_INVALID_STATE
event_command_t commands[1024]
Definition event.c:30

References ASCIICHAT_OK, platform_event_loop::commands, platform_event_loop::count, ERROR_INVALID_PARAM, ERROR_INVALID_STATE, EVENT_COMMAND_LIMIT, platform_event_loop::head, platform_event_loop::mutex, SET_ERRNO, platform_event_loop::stopping, and platform_event_loop::wake.

◆ platform_event_loop_run()

asciichat_error_t platform_event_loop_run ( platform_event_loop_t * loop)

Definition at line 234 of file event.c.

234 {
235 if (!loop)
236 return SET_ERRNO(ERROR_INVALID_PARAM, "Missing event loop");
237 uv_run(&loop->uv, UV_RUN_DEFAULT);
238 return ASCIICHAT_OK;
239}

References ASCIICHAT_OK, ERROR_INVALID_PARAM, SET_ERRNO, and platform_event_loop::uv.

◆ platform_event_loop_stop()

void platform_event_loop_stop ( platform_event_loop_t * loop)

Definition at line 257 of file event.c.

257 {
258 if (!loop)
259 return;
260 uv_mutex_lock(&loop->mutex);
261 if (!loop->stopping) {
262 loop->stopping = true;
263 uv_async_send(&loop->wake);
264 }
265 uv_mutex_unlock(&loop->mutex);
266}

References platform_event_loop::mutex, platform_event_loop::stopping, and platform_event_loop::wake.

◆ platform_event_loop_tick()

asciichat_error_t platform_event_loop_tick ( platform_event_loop_t * loop,
uint64_t interval,
platform_event_task_fn fn,
void * arg )

Definition at line 296 of file event.c.

297 {
298 if (!loop || !interval || !fn || loop->tick_initialized)
299 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid event loop tick");
300 int status = uv_timer_init(&loop->uv, &loop->tick);
301 if (status < 0)
302 return event_error(status, "Initialize loop timer");
303 loop->tick_initialized = true;
304 loop->tick.data = loop;
305 loop->tick_fn = fn;
306 loop->tick_arg = arg;
307 status = uv_timer_start(&loop->tick, tick_loop, interval, interval);
308 return status < 0 ? event_error(status, "Start loop timer") : ASCIICHAT_OK;
309}
platform_event_task_fn tick_fn
Definition event.c:25
void * tick_arg
Definition event.c:26
bool tick_initialized
Definition event.c:27
uv_timer_t tick
Definition event.c:24

References ASCIICHAT_OK, ERROR_INVALID_PARAM, SET_ERRNO, platform_event_loop::tick, platform_event_loop::tick_arg, platform_event_loop::tick_fn, platform_event_loop::tick_initialized, and platform_event_loop::uv.

Referenced by acip_async_tcp_client_create().

◆ platform_event_loop_work()

asciichat_error_t platform_event_loop_work ( platform_event_loop_t * loop,
platform_event_task_fn run,
platform_event_task_fn done,
void * arg )

Definition at line 768 of file event.c.

769 {
770 if (!loop || !run || !done)
771 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid event worker");
772 loop_work_t *work = SAFE_CALLOC(1, sizeof(*work), loop_work_t *);
773 work->request.data = work;
774 work->work = run;
775 work->done = done;
776 work->arg = arg;
777 int status = uv_queue_work(&loop->uv, &work->request, loop_work_run, loop_work_done);
778 if (status < 0) {
779 SAFE_FREE(work);
780 return event_error(status, "Queue loop work");
781 }
782 return ASCIICHAT_OK;
783}
This is the handoff point for event work. Callers fill work, stream, run, done before passing it on; ...
Definition event.c:747
platform_event_task_fn done
Definition event.c:749
void * arg
Definition event.c:750
uv_work_t request
Definition event.c:748
platform_event_task_fn work
Definition event.c:749

References loop_work_t::arg, ASCIICHAT_OK, loop_work_t::done, ERROR_INVALID_PARAM, loop_work_t::request, SAFE_CALLOC, SAFE_FREE, SET_ERRNO, platform_event_loop::uv, and loop_work_t::work.

◆ platform_event_stream_adopt()

asciichat_error_t platform_event_stream_adopt ( platform_event_loop_t * loop,
socket_t * socket,
platform_event_stream_t ** out )

Adopt an already-connected socket, setting it invalid on ownership transfer.

Definition at line 410 of file event.c.

411 {
412 if (!loop || !socket || !out)
413 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid socket adoption");
414 *out = NULL;
415 platform_event_stream_t *stream = create_stream(&loop->uv);
416 if (!stream)
417 return SET_ERRNO(ERROR_MEMORY, "Cannot initialize event stream");
418 int status = uv_tcp_open(&stream->tcp, (uv_os_sock_t)*socket);
419 if (status < 0) {
421 return event_error(status, "Adopt TCP stream");
422 }
423 *socket = INVALID_SOCKET_VALUE;
424 uv_tcp_nodelay(&stream->tcp, 1);
425 uv_tcp_keepalive(&stream->tcp, 1, 60);
426 *out = stream;
427 return ASCIICHAT_OK;
428}
void platform_event_stream_close(platform_event_stream_t *stream, asciichat_error_t reason)
Definition event.c:120
struct platform_event_stream platform_event_stream_t
Definition event.h:12
@ ERROR_NETWORK
Definition error_codes.h:72
@ ERROR_MEMORY
Definition error_codes.h:51

References ASCIICHAT_OK, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK, out, platform_event_stream_close(), SET_ERRNO, event_write::stream, platform_event_stream::tcp, and platform_event_loop::uv.

Referenced by acip_async_tcp_client_create().

◆ platform_event_stream_close()

void platform_event_stream_close ( platform_event_stream_t * stream,
asciichat_error_t reason )

Definition at line 120 of file event.c.

120 {
121 if (!stream)
122 return;
123 uv_mutex_lock(&stream->mutex);
124 if (stream->closing) {
125 uv_mutex_unlock(&stream->mutex);
126 return;
127 }
128 stream->closing = true;
129 event_write_t *pending = stream->first;
130 stream->first = stream->last = NULL;
131 uv_mutex_unlock(&stream->mutex);
132 while (pending) {
133 event_write_t *next = pending->next;
134 uv_mutex_lock(&stream->mutex);
135 stream->queued -= pending->size;
136 if (stream->queue_changed)
137 stream->queue_changed(stream->queue_context, stream->queued);
138 --stream->writes;
139 uv_mutex_unlock(&stream->mutex);
140 if (pending->done)
141 pending->done(pending->arg, ERROR_NETWORK);
142 socket_send_buffer_free(&pending->storage);
143 SAFE_FREE(pending);
144 pending = next;
145 }
146 stream->reason = reason;
147 // Submitted uv_write requests complete during TCP close. A raw zerocopy
148 // submission has no libuv request; discard its mapping without recycling it.
149 if (stream->active && stream->active->waiting)
150 write_complete(&stream->active->request, UV_ECANCELED);
151 uv_timer_stop(&stream->output_timer);
152 uv_close((uv_handle_t *)&stream->output_timer, stream_closed);
153 uv_read_stop((uv_stream_t *)&stream->tcp);
154 uv_timer_stop(&stream->timer);
155 uv_close((uv_handle_t *)&stream->timer, stream_closed);
156 uv_close((uv_handle_t *)&stream->tcp, stream_closed);
157 uv_close((uv_handle_t *)&stream->output, stream_closed);
158}
struct event_write event_write_t
socket_send_buffer_t storage
Definition event.c:90
size_t size
Definition event.c:88
uv_write_t request
Definition event.c:84
bool waiting
Definition event.c:93
platform_event_write_fn done
Definition event.c:86
void * arg
Definition event.c:87
struct event_write * next
Definition event.c:89
struct event_write * active
Definition event.c:51
platform_event_queue_fn queue_changed
Definition event.c:59
asciichat_error_t reason
Definition event.c:67
void * queue_context
Definition event.c:60
struct event_write * first
Definition event.c:51
uv_timer_t output_timer
Definition event.c:48
uv_async_t output
Definition event.c:49
uv_mutex_t mutex
Definition event.c:50
uv_timer_t timer
Definition event.c:47
struct event_write * last
Definition event.c:51

References platform_event_stream::active, event_write::arg, platform_event_stream::closing, event_write::done, ERROR_NETWORK, platform_event_stream::first, platform_event_stream::last, platform_event_stream::mutex, event_write::next, platform_event_stream::output, platform_event_stream::output_timer, platform_event_stream::queue_changed, platform_event_stream::queue_context, platform_event_stream::queued, platform_event_stream::reason, event_write::request, SAFE_FREE, event_write::size, event_write::storage, event_write::stream, platform_event_stream::tcp, platform_event_stream::timer, event_write::waiting, and platform_event_stream::writes.

Referenced by acip_async_tcp_accepted_create(), and platform_event_stream_adopt().

◆ platform_event_stream_deadline()

asciichat_error_t platform_event_stream_deadline ( platform_event_stream_t * stream,
uint64_t timeout_ms )

Relative timeout converted to an absolute deadline; zero disables it.

Definition at line 357 of file event.c.

357 {
358 if (!stream || stream->closing)
359 return SET_ERRNO(ERROR_INVALID_STATE, "Stream is closing");
360 uv_timer_stop(&stream->timer);
361 int status = timeout_ms ? uv_timer_start(&stream->timer, deadline_expired, timeout_ms, 0) : 0;
362 return status < 0 ? event_error(status, "Set stream deadline") : ASCIICHAT_OK;
363}

References ASCIICHAT_OK, platform_event_stream::closing, ERROR_INVALID_STATE, SET_ERRNO, event_write::stream, and platform_event_stream::timer.

◆ platform_event_stream_observe_queue()

void platform_event_stream_observe_queue ( platform_event_stream_t * stream,
platform_event_queue_fn observer,
void * context )

Publish queued-byte changes without polling the stream. Configure before producers start. Invoked under the stream lock; only publish atomic state, never call stream/transport APIs. Context remains alive through on_close.

Definition at line 712 of file event.c.

713 {
714 if (!stream)
715 return;
716 uv_mutex_lock(&stream->mutex);
717 stream->queue_changed = observer;
718 stream->queue_context = context;
719 if (observer)
720 observer(context, stream->queued);
721 uv_mutex_unlock(&stream->mutex);
722}

References platform_event_stream::mutex, platform_event_stream::queue_changed, platform_event_stream::queue_context, platform_event_stream::queued, and event_write::stream.

Referenced by acip_async_tcp_accepted_create(), acip_async_tcp_client_create(), acip_async_tcp_transport_create(), and acip_async_tcp_transport_detach().

◆ platform_event_stream_pause()

void platform_event_stream_pause ( platform_event_stream_t * stream)

Definition at line 341 of file event.c.

341 {
342 if (stream && !stream->closing)
343 uv_read_stop((uv_stream_t *)&stream->tcp);
344}

References platform_event_stream::closing, event_write::stream, and platform_event_stream::tcp.

Referenced by platform_event_stream_work().

◆ platform_event_stream_peer()

asciichat_error_t platform_event_stream_peer ( platform_event_stream_t * stream,
struct sockaddr_storage * address,
socklen_t * length )

Definition at line 822 of file event.c.

823 {
824 if (!stream || !address || !length)
825 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid peer address output");
826 int size = (int)*length;
827 int status = uv_tcp_getpeername(&stream->tcp, (struct sockaddr *)address, &size);
828 *length = (socklen_t)size;
829 return status < 0 ? event_error(status, "Get stream peer") : ASCIICHAT_OK;
830}

References ASCIICHAT_OK, ERROR_INVALID_PARAM, SET_ERRNO, and platform_event_stream::tcp.

◆ platform_event_stream_queued_bytes()

size_t platform_event_stream_queued_bytes ( const platform_event_stream_t * stream)

Definition at line 703 of file event.c.

703 {
704 if (!stream)
705 return 0;
706 uv_mutex_lock((uv_mutex_t *)&stream->mutex);
707 size_t bytes = stream->queued;
708 uv_mutex_unlock((uv_mutex_t *)&stream->mutex);
709 return bytes;
710}

References platform_event_stream::mutex, platform_event_stream::queued, and event_write::stream.

◆ platform_event_stream_request_close()

void platform_event_stream_request_close ( platform_event_stream_t * stream,
asciichat_error_t reason )

Reject new writes, drain accepted output, then close; write deadlines still apply.

Definition at line 625 of file event.c.

625 {
626 if (!stream)
627 return;
628 uv_mutex_lock(&stream->mutex);
629 if (!stream->closing && !stream->close_requested) {
630 stream->close_requested = true;
631 stream->requested_reason = reason;
632 uv_async_send(&stream->output);
633 }
634 uv_mutex_unlock(&stream->mutex);
635}
asciichat_error_t requested_reason
Definition event.c:66

References platform_event_stream::close_requested, platform_event_stream::closing, platform_event_stream::mutex, platform_event_stream::output, platform_event_stream::requested_reason, and event_write::stream.

◆ platform_event_stream_resume()

asciichat_error_t platform_event_stream_resume ( platform_event_stream_t * stream)

Definition at line 346 of file event.c.

346 {
347 if (!stream || stream->closing || !stream->read)
348 return SET_ERRNO(ERROR_INVALID_STATE, "Stream cannot resume");
349 int status = uv_read_start((uv_stream_t *)&stream->tcp, allocate_read, read_stream);
350 return status < 0 ? event_error(status, "Start stream read") : ASCIICHAT_OK;
351}
platform_event_read_fn read
Definition event.c:55

References ASCIICHAT_OK, platform_event_stream::closing, ERROR_INVALID_STATE, platform_event_stream::read, SET_ERRNO, event_write::stream, and platform_event_stream::tcp.

Referenced by platform_event_stream_start().

◆ platform_event_stream_set_zerocopy()

void platform_event_stream_set_zerocopy ( platform_event_stream_t * stream,
bool enabled )

Configure copy avoidance before starting producers. The loop always owns I/O.

Definition at line 617 of file event.c.

617 {
618 if (!stream)
619 return;
620 uv_mutex_lock(&stream->mutex);
621 stream->zerocopy = enabled;
622 uv_mutex_unlock(&stream->mutex);
623}
bool enabled
Is filtering active?
Definition grep.c:62

References enabled, platform_event_stream::mutex, event_write::stream, and platform_event_stream::zerocopy.

◆ platform_event_stream_start()

asciichat_error_t platform_event_stream_start ( platform_event_stream_t * stream,
platform_event_read_fn read,
platform_event_close_fn close,
void * arg )

Definition at line 326 of file event.c.

327 {
328 if (!stream || stream->closing || !read)
329 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid stream callbacks");
330 // Retain cleanup callbacks even when configuring or starting reads fails.
331 stream->read = read;
332 stream->close = close;
333 stream->arg = arg;
334 int send_buffer = SOCKET_STREAM_SEND_BUFFER;
335 int status = uv_send_buffer_size((uv_handle_t *)&stream->tcp, &send_buffer);
336 if (status < 0)
337 return event_error(status, "Bound stream send buffer");
338 return platform_event_stream_resume(stream);
339}
asciichat_error_t platform_event_stream_resume(platform_event_stream_t *stream)
Definition event.c:346
platform_event_close_fn close
Definition event.c:56

References platform_event_stream::arg, platform_event_stream::close, platform_event_stream::closing, ERROR_INVALID_PARAM, platform_event_stream_resume(), platform_event_stream::read, SET_ERRNO, event_write::stream, and platform_event_stream::tcp.

Referenced by acip_async_tcp_accepted_create(), and acip_async_tcp_client_create().

◆ platform_event_stream_work()

asciichat_error_t platform_event_stream_work ( platform_event_stream_t * stream,
platform_event_work_fn run,
platform_event_work_done_fn done,
void * arg )

Run blocking application work outside the loop. One job per stream at a time; reads pause until done runs on the loop. Stream lifetime includes this job. write(), request_close(), and queued_bytes() are thread-safe while the caller holds a live stream reference; other stream operations are loop-only.

Definition at line 801 of file event.c.

802 {
803 if (!stream || stream->closing || stream->working || !run || !done)
804 return SET_ERRNO(ERROR_INVALID_STATE, "Stream work already active or closing");
805 event_work_t *work = SAFE_CALLOC(1, sizeof(*work), event_work_t *);
806 work->stream = stream;
807 work->run = run;
808 work->done = done;
809 work->arg = arg;
810 work->work.data = work;
812 int status = uv_queue_work(stream->tcp.loop, &work->work, run_work, finish_work);
813 if (status < 0) {
814 SAFE_FREE(work);
815 return event_error(status, "Queue stream work");
816 }
817 stream->working = true;
818 ++stream->handles;
819 return ASCIICHAT_OK;
820}
void platform_event_stream_pause(platform_event_stream_t *stream)
Definition event.c:341
event command keeps the values that move through the subsystem: fn, arg. Some members are pointers in...
Definition event.c:729
platform_event_work_fn run
Definition event.c:732
platform_event_stream_t * stream
Definition event.c:731
void * arg
Definition event.c:734
uv_work_t work
Definition event.c:730
platform_event_work_done_fn done
Definition event.c:733
unsigned handles
Definition event.c:62

References event_work_t::arg, ASCIICHAT_OK, platform_event_stream::closing, event_work_t::done, ERROR_INVALID_STATE, platform_event_stream::handles, platform_event_stream_pause(), event_work_t::run, SAFE_CALLOC, SAFE_FREE, SET_ERRNO, event_work_t::stream, platform_event_stream::tcp, event_work_t::work, and platform_event_stream::working.

◆ platform_event_stream_write()

asciichat_error_t platform_event_stream_write ( platform_event_stream_t * stream,
const socket_buffer_t * buffers,
size_t count,
platform_event_write_fn done,
void * arg )

Copies input before returning. Completion means local write completion, not peer acknowledgement. Rejected writes never invoke completion. Accepted writes invoke completion exactly once, including during shutdown, before on_close.

Definition at line 637 of file event.c.

638 {
639 if (!stream || !buffers || !count || count > SOCKET_IOV_MAX)
640 return SET_ERRNO(ERROR_INVALID_PARAM, "Invalid asynchronous write");
641 size_t size = 0;
642 for (size_t i = 0; i < count; ++i) {
643 if ((!buffers[i].data && buffers[i].len) || buffers[i].len > EVENT_WRITE_LIMIT - size)
644 return SET_ERRNO(ERROR_NETWORK_SIZE, "Asynchronous write too large");
645 size += buffers[i].len;
646 }
647 uv_mutex_lock(&stream->mutex);
648 if (stream->closing || stream->close_requested || !size || stream->writes >= EVENT_WRITE_COUNT_LIMIT ||
649 size > EVENT_WRITE_LIMIT - stream->queued) {
650 uv_mutex_unlock(&stream->mutex);
651 return SET_ERRNO(ERROR_NETWORK_SIZE, "Asynchronous output queue full");
652 }
653 bool mapped = stream->zerocopy && size >= SOCKET_ZEROCOPY_THRESHOLD;
654 event_write_t **cached = &stream->recycled;
655 while (*cached && (mapped || (*cached)->storage.capacity < size))
656 cached = &(*cached)->next;
657 event_write_t *write = *cached;
658 socket_send_buffer_t storage = {0};
659 if (write) {
660 *cached = write->next;
661 --stream->recycled_count;
662 storage = write->storage;
663 } else {
664 write = SAFE_MALLOC(sizeof(*write), event_write_t *);
665 }
666 *write = (event_write_t){.stream = stream, .done = done, .arg = arg, .size = size, .storage = storage};
667 if (!write->storage.data && mapped) {
668 if (socket_send_buffer_alloc(size, &write->storage) != ASCIICHAT_OK) {
669 SAFE_FREE(write);
670 uv_mutex_unlock(&stream->mutex);
671 return SET_ERRNO(ERROR_MEMORY, "Async copy avoidance exceeds process buffer budget");
672 }
673 } else if (!write->storage.data) {
674 write->storage.data = buffer_alloc(NULL, size);
675 write->storage.capacity = size;
676 }
677 if (!write->storage.data) {
678 SAFE_FREE(write);
679 uv_mutex_unlock(&stream->mutex);
680 return SET_ERRNO(ERROR_MEMORY, "Async output exceeds process buffer budget");
681 }
682 write->request.data = write;
683 size_t offset = 0;
684 for (size_t i = 0; i < count; ++i) {
685 if (buffers[i].len)
686 memcpy((char *)write->storage.data + offset, buffers[i].data, buffers[i].len);
687 offset += buffers[i].len;
688 }
689 stream->queued += size;
690 if (stream->queue_changed)
691 stream->queue_changed(stream->queue_context, stream->queued);
692 ++stream->writes;
693 if (stream->last)
694 stream->last->next = write;
695 else
696 stream->first = write;
697 stream->last = write;
698 uv_async_send(&stream->output);
699 uv_mutex_unlock(&stream->mutex);
700 return ASCIICHAT_OK;
701}
void * buffer_alloc(buffer_domain_t *domain, size_t size)
Definition buffer.c:274
#define EVENT_WRITE_LIMIT
Definition event.c:8
#define EVENT_WRITE_COUNT_LIMIT
Definition event.c:9
#define SAFE_MALLOC(size, cast)
Definition common.h:265
@ ERROR_NETWORK_SIZE
Definition error_codes.h:77
size_t recycled_count
Definition event.c:53
struct event_write * recycled
Definition event.c:52

References platform_event_stream::arg, ASCIICHAT_OK, buffer_alloc(), platform_event_stream::close_requested, platform_event_stream::closing, event_write::done, ERROR_INVALID_PARAM, ERROR_MEMORY, ERROR_NETWORK_SIZE, EVENT_WRITE_COUNT_LIMIT, EVENT_WRITE_LIMIT, platform_event_stream::first, platform_event_stream::last, platform_event_stream::mutex, event_write::next, event_write::offset, platform_event_stream::output, platform_event_stream::queue_changed, platform_event_stream::queue_context, platform_event_stream::queued, platform_event_stream::recycled, platform_event_stream::recycled_count, event_write::request, SAFE_FREE, SAFE_MALLOC, SET_ERRNO, event_write::size, event_write::storage, event_write::stream, platform_event_stream::writes, and platform_event_stream::zerocopy.