Skip to content

Commit d5fe089

Browse files
committed
Unify I/O wrappers (should work with request FDs and other FDs!)
1 parent bba7388 commit d5fe089

File tree

6 files changed

+199
-229
lines changed

6 files changed

+199
-229
lines changed

src/lib/lwan-io-wrappers.c

+81-74
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
static const int MAX_FAILED_TRIES = 5;
3333

3434
ssize_t
35-
lwan_writev(struct lwan_request *request, struct iovec *iov, int iov_count)
35+
lwan_writev_fd(struct lwan_request *request, int fd, struct iovec *iov, int iov_count)
3636
{
3737
ssize_t total_written = 0;
3838
int curr_iov = 0;
@@ -44,14 +44,14 @@ lwan_writev(struct lwan_request *request, struct iovec *iov, int iov_count)
4444

4545
if (remaining_len == 1) {
4646
const struct iovec *vec = &iov[curr_iov];
47-
return lwan_send(request, vec->iov_base, vec->iov_len, flags);
47+
return lwan_send_fd(request, fd, vec->iov_base, vec->iov_len, flags);
4848
}
4949

5050
struct msghdr hdr = {
5151
.msg_iov = iov + curr_iov,
5252
.msg_iovlen = (size_t)remaining_len,
5353
};
54-
written = sendmsg(request->fd, &hdr, flags);
54+
written = sendmsg(fd, &hdr, flags);
5555

5656
if (UNLIKELY(written < 0)) {
5757
/* FIXME: Consider short writes as another try as well? */
@@ -62,7 +62,7 @@ lwan_writev(struct lwan_request *request, struct iovec *iov, int iov_count)
6262
case EINTR:
6363
goto try_again;
6464
default:
65-
goto out;
65+
return -errno;
6666
}
6767
}
6868

@@ -81,23 +81,20 @@ lwan_writev(struct lwan_request *request, struct iovec *iov, int iov_count)
8181
iov[curr_iov].iov_len -= (size_t)written;
8282

8383
try_again:
84-
coro_yield(request->conn->coro, CONN_CORO_WANT_WRITE);
84+
lwan_request_await_read(request, fd);
8585
}
8686

87-
out:
88-
coro_yield(request->conn->coro, CONN_CORO_ABORT);
89-
__builtin_unreachable();
87+
return -ETIMEDOUT;
9088
}
9189

9290
ssize_t
93-
lwan_readv(struct lwan_request *request, struct iovec *iov, int iov_count)
91+
lwan_readv_fd(struct lwan_request *request, int fd, struct iovec *iov, int iov_count)
9492
{
9593
ssize_t total_bytes_read = 0;
9694
int curr_iov = 0;
9795

9896
for (int tries = MAX_FAILED_TRIES; tries;) {
99-
ssize_t bytes_read =
100-
readv(request->fd, iov + curr_iov, iov_count - curr_iov);
97+
ssize_t bytes_read = readv(fd, iov + curr_iov, iov_count - curr_iov);
10198
if (UNLIKELY(bytes_read < 0)) {
10299
/* FIXME: Consider short reads as another try as well? */
103100
tries--;
@@ -107,7 +104,7 @@ lwan_readv(struct lwan_request *request, struct iovec *iov, int iov_count)
107104
case EINTR:
108105
goto try_again;
109106
default:
110-
goto out;
107+
return -errno;
111108
}
112109
}
113110

@@ -126,26 +123,25 @@ lwan_readv(struct lwan_request *request, struct iovec *iov, int iov_count)
126123
iov[curr_iov].iov_len -= (size_t)bytes_read;
127124

128125
try_again:
129-
coro_yield(request->conn->coro, CONN_CORO_WANT_READ);
126+
lwan_request_await_read(request, fd);
130127
}
131128

132-
out:
133-
coro_yield(request->conn->coro, CONN_CORO_ABORT);
134-
__builtin_unreachable();
129+
return -ETIMEDOUT;
135130
}
136131

137-
ssize_t lwan_send(struct lwan_request *request,
138-
const void *buf,
139-
size_t count,
140-
int flags)
132+
ssize_t lwan_send_fd(struct lwan_request *request,
133+
int fd,
134+
const void *buf,
135+
size_t count,
136+
int flags)
141137
{
142138
ssize_t total_sent = 0;
143139

144140
if (request->conn->flags & CONN_CORK)
145141
flags |= MSG_MORE;
146142

147143
for (int tries = MAX_FAILED_TRIES; tries;) {
148-
ssize_t written = send(request->fd, buf, count, flags);
144+
ssize_t written = send(fd, buf, count, flags);
149145
if (UNLIKELY(written < 0)) {
150146
tries--;
151147

@@ -154,7 +150,7 @@ ssize_t lwan_send(struct lwan_request *request,
154150
case EINTR:
155151
goto try_again;
156152
default:
157-
goto out;
153+
return -errno;
158154
}
159155
}
160156

@@ -165,21 +161,19 @@ ssize_t lwan_send(struct lwan_request *request,
165161
buf = (char *)buf + written;
166162

167163
try_again:
168-
coro_yield(request->conn->coro, CONN_CORO_WANT_WRITE);
164+
lwan_request_await_write(request, fd);
169165
}
170166

171-
out:
172-
coro_yield(request->conn->coro, CONN_CORO_ABORT);
173-
__builtin_unreachable();
167+
return -ETIMEDOUT;
174168
}
175169

176170
ssize_t
177-
lwan_recv(struct lwan_request *request, void *buf, size_t count, int flags)
171+
lwan_recv_fd(struct lwan_request *request, int fd, void *buf, size_t count, int flags)
178172
{
179173
ssize_t total_recv = 0;
180174

181175
for (int tries = MAX_FAILED_TRIES; tries;) {
182-
ssize_t recvd = recv(request->fd, buf, count, flags);
176+
ssize_t recvd = recv(fd, buf, count, flags);
183177
if (UNLIKELY(recvd < 0)) {
184178
tries--;
185179

@@ -191,7 +185,7 @@ lwan_recv(struct lwan_request *request, void *buf, size_t count, int flags)
191185
case EINTR:
192186
goto try_again;
193187
default:
194-
goto out;
188+
return -errno;
195189
}
196190
}
197191

@@ -202,21 +196,20 @@ lwan_recv(struct lwan_request *request, void *buf, size_t count, int flags)
202196
buf = (char *)buf + recvd;
203197

204198
try_again:
205-
coro_yield(request->conn->coro, CONN_CORO_WANT_READ);
199+
lwan_request_await_read(request, fd);
206200
}
207201

208-
out:
209-
coro_yield(request->conn->coro, CONN_CORO_ABORT);
210-
__builtin_unreachable();
202+
return -ETIMEDOUT;
211203
}
212204

213205
#if defined(__linux__)
214-
void lwan_sendfile(struct lwan_request *request,
215-
int in_fd,
216-
off_t offset,
217-
size_t count,
218-
const char *header,
219-
size_t header_len)
206+
int lwan_sendfile_fd(struct lwan_request *request,
207+
int out_fd,
208+
int in_fd,
209+
off_t offset,
210+
size_t count,
211+
const char *header,
212+
size_t header_len)
220213
{
221214
/* Clamp each chunk to 2^21 bytes[1] to balance throughput and
222215
* scalability. This used to be capped to 2^14 bytes, as that's the
@@ -227,47 +220,51 @@ void lwan_sendfile(struct lwan_request *request,
227220
* sent using MSG_MORE. Subsequent chunks are sized 2^21 bytes. (Do
228221
* this regardless of this connection being TLS or not for simplicity.)
229222
*
230-
* [1] https://www.kernel.org/doc/html/v5.12/networking/tls.html#sending-tls-application-data
223+
* [1]
224+
* https://www.kernel.org/doc/html/v5.12/networking/tls.html#sending-tls-application-data
231225
* [2] https://github.com/lpereira/lwan/issues/334
232226
*/
233227
size_t chunk_size = LWAN_MIN(count, (1ul << 21) - header_len);
234228
size_t to_be_written = count;
229+
ssize_t r;
235230

236231
assert(header_len < (1ul << 21));
237232

238-
lwan_send(request, header, header_len, MSG_MORE);
233+
r = lwan_send_fd(request, out_fd, header, header_len, MSG_MORE);
234+
if (r < 0)
235+
return (int)r;
239236

240237
while (true) {
241-
ssize_t written = sendfile(request->fd, in_fd, &offset, chunk_size);
238+
ssize_t written = sendfile(out_fd, in_fd, &offset, chunk_size);
242239
if (written < 0) {
243240
switch (errno) {
244241
case EAGAIN:
245242
case EINTR:
246243
goto try_again;
247244
default:
248-
coro_yield(request->conn->coro, CONN_CORO_ABORT);
249-
__builtin_unreachable();
245+
return -errno;
250246
}
251247
}
252248

253249
to_be_written -= (size_t)written;
254250
if (!to_be_written)
255-
break;
251+
return 0;
256252

257253
chunk_size = LWAN_MIN(to_be_written, 1ul << 21);
258254
lwan_readahead_queue(in_fd, offset, chunk_size);
259255

260256
try_again:
261-
coro_yield(request->conn->coro, CONN_CORO_WANT_WRITE);
257+
lwan_request_await_write(request, out_fd);
262258
}
263259
}
264260
#elif defined(__FreeBSD__) || defined(__APPLE__)
265-
void lwan_sendfile(struct lwan_request *request,
266-
int in_fd,
267-
off_t offset,
268-
size_t count,
269-
const char *header,
270-
size_t header_len)
261+
int lwan_sendfile(struct lwan_request *request,
262+
int out_fd,
263+
int in_fd,
264+
off_t offset,
265+
size_t count,
266+
const char *header,
267+
size_t header_len)
271268
{
272269
struct sf_hdtr headers = {.headers =
273270
(struct iovec[]){{.iov_base = (void *)header,
@@ -277,41 +274,40 @@ void lwan_sendfile(struct lwan_request *request,
277274

278275
if (!count) {
279276
/* FreeBSD's sendfile() won't send the headers when count is 0. Why? */
280-
return (void)lwan_writev(request, headers.headers, headers.hdr_cnt);
277+
return lwan_writev_fd(request, out_fd, headers.headers,
278+
headers.hdr_cnt);
281279
}
282280

283281
while (true) {
284282
int r;
285283

286284
#ifdef __APPLE__
287-
r = sendfile(in_fd, request->fd, offset, &sbytes, &headers, 0);
285+
r = sendfile(in_fd, out_fd, offset, &sbytes, &headers, 0);
288286
#else
289-
r = sendfile(in_fd, request->fd, offset, count, &headers, &sbytes,
287+
r = sendfile(in_fd, out_fd, offset, count, &headers, &sbytes,
290288
SF_MNOWAIT);
291289
#endif
292-
293290
if (UNLIKELY(r < 0)) {
294291
switch (errno) {
295292
case EAGAIN:
296293
case EBUSY:
297294
case EINTR:
298295
goto try_again;
299296
default:
300-
coro_yield(request->conn->coro, CONN_CORO_ABORT);
301-
__builtin_unreachable();
297+
return -errno;
302298
}
303299
}
304300

305301
count -= (size_t)sbytes;
306302
if (!count)
307-
break;
303+
return 0;
308304

309305
try_again:
310-
coro_yield(request->conn->coro, CONN_CORO_WANT_WRITE);
306+
lwan_request_await_write(request, out_fd);
311307
}
312308
}
313309
#else
314-
static size_t try_pread_file(struct lwan_request *request,
310+
static ssize_t try_pread_file(struct lwan_request *request,
315311
int fd,
316312
void *buffer,
317313
size_t len,
@@ -332,7 +328,7 @@ static size_t try_pread_file(struct lwan_request *request,
332328
coro_yield(request->conn->coro, CONN_CORO_YIELD);
333329
continue;
334330
default:
335-
break;
331+
return -errno;
336332
}
337333
}
338334

@@ -344,25 +340,36 @@ static size_t try_pread_file(struct lwan_request *request,
344340
offset += r;
345341
}
346342

347-
coro_yield(request->conn->coro, CONN_CORO_ABORT);
348-
__builtin_unreachable();
343+
return -ETIMEDOUT;
349344
}
350345

351-
void lwan_sendfile(struct lwan_request *request,
352-
int in_fd,
353-
off_t offset,
354-
size_t count,
355-
const char *header,
356-
size_t header_len)
346+
int lwan_sendfile_fd(struct lwan_request *request,
347+
int out_fd,
348+
int in_fd,
349+
off_t offset,
350+
size_t count,
351+
const char *header,
352+
size_t header_len)
357353
{
358354
unsigned char buffer[512];
355+
ssize_t r;
359356

360-
lwan_send(request, header, header_len, MSG_MORE);
357+
r = lwan_send_fd(request, out_fd, header, header_len, MSG_MORE);
358+
if (UNLIKELY(r < 0)) {
359+
return (int)r;
360+
}
361361

362362
while (count) {
363-
size_t bytes_read = try_pread_file(
364-
request, in_fd, buffer, LWAN_MIN(count, sizeof(buffer)), offset);
365-
lwan_send(request, buffer, bytes_read, 0);
363+
r = try_pread_file(request, in_fd, buffer,
364+
LWAN_MIN(count, sizeof(buffer)), offset);
365+
if (UNLIKELY(r < 0))
366+
return (int)r;
367+
368+
size_t bytes_read = (size_t)r;
369+
r = lwan_send_fd(request, out_fd, buffer, bytes_read, 0);
370+
if (UNLIKELY(r < 0))
371+
return (int)r;
372+
366373
count -= bytes_read;
367374
offset += bytes_read;
368375
}

0 commit comments

Comments
 (0)