cwist
Modern C web framework with libttak runtime
Loading...
Searching...
No Matches
writer_fast.c
Go to the documentation of this file.
1#ifndef _GNU_SOURCE
2#define _GNU_SOURCE
3#endif
4#include <cwist/sys/wasi.h>
7#include <sys/socket.h>
8#include <errno.h>
9#include <stdatomic.h>
10#include <unistd.h>
11#include <time.h>
12#include <stdlib.h>
13#include <string.h>
14
31cwist_write_status_t cwist_http_send_speculative(int fd, const void *buf, size_t len,
32 size_t *sent_out) {
33 if (!buf || len == 0) {
34 if (sent_out) *sent_out = 0;
35 return CWIST_WRITE_DONE;
36 }
37
38 int flags = MSG_DONTWAIT;
39#if defined(MSG_NOSIGNAL)
40 flags |= MSG_NOSIGNAL;
41#endif
42
43 ssize_t n;
44 do {
45 n = send(fd, buf, len, flags);
46 } while (n < 0 && errno == EINTR);
47
48 if (n >= 0) {
49 if (sent_out) *sent_out = (size_t)n;
50 if ((size_t)n == len) {
51 return CWIST_WRITE_DONE;
52 }
54 }
55
56 if (errno == EAGAIN || errno == EWOULDBLOCK) {
57 if (sent_out) *sent_out = 0;
59 }
60
61 return CWIST_WRITE_ERR;
62}
63
84 int flags, size_t *total_sent) {
85 if (!iov || iovcnt <= 0) {
86 if (total_sent) *total_sent = 0;
87 return CWIST_WRITE_DONE;
88 }
89
90 int send_flags = flags | MSG_DONTWAIT;
91#if defined(MSG_NOSIGNAL)
93#endif
94
95#ifdef CWIST_WASI_SOCKETS
96 /* wasi:sockets (0.2) has no sendmsg(2): coalesce and send once.
97 * This is the speculative path - the blocking drain in
98 * cwist_http_sendmsg_all() re-drives whatever is left. */
99 size_t expected_wasi = 0;
100 for (int i = 0; i < iovcnt; ++i) expected_wasi += iov[i].iov_len;
102 if (!wasi_buf) {
103 if (total_sent) *total_sent = 0;
104 return CWIST_WRITE_ERR;
105 }
106 size_t wasi_off = 0;
107 for (int i = 0; i < iovcnt; ++i) {
109 wasi_off += iov[i].iov_len;
110 }
111 ssize_t n;
112 do {
113 n = send(fd, wasi_buf, expected_wasi, send_flags);
114 } while (n < 0 && errno == EINTR);
116#else
117 struct msghdr msg = {.msg_iov = iov, .msg_iovlen = (size_t)iovcnt};
118
119 ssize_t n;
120 do {
121 n = sendmsg(fd, &msg, send_flags);
122 } while (n < 0 && errno == EINTR);
123#endif
124
125 if (n >= 0) {
126 if (total_sent) *total_sent = (size_t)n;
127
128 /* Calculate total expected payload length across all iovec items */
129 size_t expected = 0;
130 for (int i = 0; i < iovcnt; ++i) {
131 expected += iov[i].iov_len;
132 }
133
134 if ((size_t)n >= expected) {
135 return CWIST_WRITE_DONE;
136 }
137 return CWIST_WRITE_PENDING;
138 }
139
140 if (errno == EAGAIN || errno == EWOULDBLOCK) {
141 if (total_sent) *total_sent = 0;
142 return CWIST_WRITE_PENDING;
143 }
144
145 return CWIST_WRITE_ERR;
146}
147
162 if (!worker_loads || num_workers <= 1) return 0;
163
164 static _Thread_local uint32_t seed = 0x9e3779b9;
165 if (__builtin_expect(seed == 0, 0)) {
166 seed = (uint32_t)(uintptr_t)&seed;
167 if (seed == 0) seed = 0x9e3779b9;
168 }
169
170 /* Fast xorshift32 PRNG */
171 seed ^= seed << 13;
172 seed ^= seed >> 17;
173 seed ^= seed << 5;
174 uint32_t w1 = seed % num_workers;
175
176 seed ^= seed << 13;
177 seed ^= seed >> 17;
178 seed ^= seed << 5;
179 uint32_t w2 = seed % num_workers;
180
181 if (w1 == w2) {
182 w2 = (w1 + 1) % num_workers;
183 }
184
187
188 return (load1 <= load2) ? w1 : w2;
189}
190
201 struct timespec ts;
202#if defined(CLOCK_MONOTONIC_COARSE)
204#else
206#endif
207 return (uint32_t)ts.tv_sec;
208}
Memory allocation wrappers backed by libttak.
void cwist_free(void *ptr)
Free memory obtained via cwist_alloc/cwist_strdup/etc.
Definition alloc.c:52
void * cwist_alloc(size_t size)
Allocate zeroed memory tracked by libttak.
Definition alloc.c:17
#define MSG_DONTWAIT
Definition http3.c:82
size_t cap
Definition otel.c:56
WASI target feature detection shared by all CWIST sources.
cwist_write_status_t cwist_http_send_speculative(int fd, const void *buf, size_t len, size_t *sent_out)
Attempt a single non-blocking speculative write of a buffer to a socket.
Definition writer_fast.c:31
cwist_write_status_t cwist_http_sendmsg_speculative(int fd, struct iovec *iov, int iovcnt, int flags, size_t *total_sent)
Attempt a single non-blocking speculative sendmsg over an iovec array.
Definition writer_fast.c:83
uint32_t cwist_sched_p2c_select_worker(const _Atomic uint32_t *worker_loads, uint32_t num_workers)
Select the less-loaded of two randomly sampled workers (power-of-two choices).
uint32_t cwist_fast_monotonic_sec(void)
Return a cheap monotonic timestamp in whole seconds.
Zero-latency speculative fast-path writer and P2C worker scheduler.
cwist_write_status_t
Definition writer_fast.h:24
@ CWIST_WRITE_DONE
Definition writer_fast.h:25
@ CWIST_WRITE_PENDING
Definition writer_fast.h:27
@ CWIST_WRITE_ERR
Definition writer_fast.h:29