diff --git a/include/h2o.h b/include/h2o.h index 0801ae77c..d93a00b61 100644 --- a/include/h2o.h +++ b/include/h2o.h @@ -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 */ diff --git a/lib/core/context.c b/lib/core/context.c index aa3007478..1eda522a8 100644 --- a/lib/core/context.c +++ b/lib/core/context.c @@ -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) diff --git a/lib/core/proxy.c b/lib/core/proxy.c index 3554d27e4..43c12f2e4 100644 --- a/lib/core/proxy.c +++ b/lib/core/proxy.c @@ -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 */ diff --git a/lib/handler/file.c b/lib/handler/file.c index 7dcc4cf6e..b68f109b9 100644 --- a/lib/handler/file.c +++ b/lib/handler/file.c @@ -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; }