in other parts of code, we do not abort when running out of fds, so do the same

This commit is contained in:
Kazuho Oku 2025-04-28 12:32:22 +09:00
parent 669dd263f3
commit afcdeb5bcc
4 changed files with 25 additions and 22 deletions

View File

@ -1832,9 +1832,9 @@ static void *h2o_context_get_logger_context(h2o_context_t *ctx, h2o_logger_t *lo
*/
static void **h2o_context_get_storage(h2o_context_t *ctx, size_t *key, void (*dispose_cb)(void *));
/**
* provides a new pipe that has O_NONBLOCK set, possibly reusing a cached one that is empty
* provides a new pipe that has O_NONBLOCK set, possibly reusing a cached one that is empty; returns a boolean indicating success
*/
void h2o_context_new_pipe(h2o_context_t *ctx, int fds[2]);
int h2o_context_new_pipe(h2o_context_t *ctx, int fds[2]);
/**
* returns a pipe to the spare pipe cache
*/

View File

@ -299,27 +299,24 @@ void h2o_conn_set_state(h2o_conn_t *conn, h2o_conn_state_t state)
}
}
void h2o_context_new_pipe(h2o_context_t *ctx, int fds[2])
int h2o_context_new_pipe(h2o_context_t *ctx, int fds[2])
{
if (ctx->spare_pipes.count > 0) {
int *src = ctx->spare_pipes.pipes[--ctx->spare_pipes.count];
fds[0] = src[0];
fds[1] = src[1];
} else {
#ifdef __linux__
if (pipe2(fds, O_NONBLOCK | O_CLOEXEC) != 0) {
char errbuf[256];
h2o_fatal("pipe2(2) failed:%s", h2o_strerror_r(errno, errbuf, sizeof(errbuf)));
}
#else
if (cloexec_pipe(fds) != 0) {
char errbuf[256];
h2o_fatal("pipe(2) failed:%s", h2o_strerror_r(errno, errbuf, sizeof(errbuf)));
}
fcntl(fds[0], F_SETFL, O_NONBLOCK);
fcntl(fds[1], F_SETFL, O_NONBLOCK);
#endif
return 1;
}
#ifdef __linux__
return pipe2(fds, O_NONBLOCK | O_CLOEXEC) == 0;
#else
if (cloexec_pipe(fds) != 0)
return 0;
fcntl(fds[0], F_SETFL, O_NONBLOCK);
fcntl(fds[1], F_SETFL, O_NONBLOCK);
return 1;
#endif
}
static int empty_pipe(int fd)

View File

@ -643,9 +643,13 @@ static h2o_httpclient_body_cb on_head(h2o_httpclient_t *client, const char *errs
/* switch to using pipe reader, if the opportunity is provided */
if (args->pipe_reader != NULL) {
h2o_context_new_pipe(req->conn->ctx, self->pipe_reader.fds);
args->pipe_reader->fd = self->pipe_reader.fds[1];
args->pipe_reader->on_body_piped = on_body_piped;
if (h2o_context_new_pipe(req->conn->ctx, self->pipe_reader.fds)) {
args->pipe_reader->fd = self->pipe_reader.fds[1];
args->pipe_reader->on_body_piped = on_body_piped;
} else {
assert(self->pipe_reader.fds[0] == -1); /* check the field remains marked as unused */
h2o_req_log_error(req, "lib/core/proxy.c", "failed to allocate zero-copy pipe; falling back to read/write");
}
}
/* if httpclient has no received body at this time, immediately send only headers using zero timeout */

View File

@ -392,11 +392,13 @@ Opened:
self->send_etag = (flags & H2O_FILE_FLAG_NO_ETAG) == 0;
self->gunzip = gunzip;
#if H2O_USE_IO_URING
if ((flags & H2O_FILE_FLAG_IO_URING) != 0 && self->bytesleft != 0) {
int try_async_splice = (flags & H2O_FILE_FLAG_IO_URING) != 0 && self->bytesleft != 0;
if (try_async_splice && h2o_context_new_pipe(req->conn->ctx, self->splice_fds)) {
self->super.stop = do_stop_async_splice;
self->src_req = req;
h2o_context_new_pipe(req->conn->ctx, self->splice_fds);
} else {
if (try_async_splice)
h2o_req_log_error(req, "lib/handler/file.c", "failed to allocate a pipe for async I/O; falling back to blocking I/O");
self->splice_fds[0] = -1;
self->splice_fds[1] = -1;
}