diff --git a/core/protocol.c b/core/protocol.c index 26c38241..590c0eff 100644 --- a/core/protocol.c +++ b/core/protocol.c @@ -1910,7 +1910,7 @@ int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, si wsgi_req->header_cnt += 2; // Ok, the file must be transferred from uWSGI - if (!wsgi_req->socket->can_offload) { + if (wsgi_req->socket->can_offload) { if (!uwsgi_offload_request_do(wsgi_req, real_filename, st->st_size)) goto done; } diff --git a/core/sendfile.c b/core/sendfile.c index 1c950581..e81bc8ca 100644 --- a/core/sendfile.c +++ b/core/sendfile.c @@ -13,6 +13,10 @@ int uwsgi_offload_request_do(struct wsgi_request *wsgi_req, char *filename, size // avoid closing the connection wsgi_req->fd_closed = 1; +#ifdef TCP_CORK + // enable CORK mode (if available) +#endif + // fill offload request struct uwsgi_offload_request uor; uor.fd = open(filename, O_RDONLY | O_NONBLOCK); @@ -24,6 +28,8 @@ int uwsgi_offload_request_do(struct wsgi_request *wsgi_req, char *filename, size uor.pos = 0; uor.len = len; uor.written = 0; + uor.prev = NULL; + uor.next = NULL; if (write(uwsgi.offload_thread->pipe[0], &uor, sizeof(struct uwsgi_offload_request)) != sizeof(struct uwsgi_offload_request)) { goto error2; @@ -38,6 +44,59 @@ error: return -1; } +static void uwsgi_offload_close(struct uwsgi_offload_request *uor) { + // close the socket and the file descriptor + close(uor->s); + close(uor->fd); + // remove the structure from the linked list; + struct uwsgi_offload_request *prev = uor->prev; + struct uwsgi_offload_request *next = uor->next; + + if (uor == uwsgi.offload_requests_head) { + uwsgi.offload_requests_head = next; + } + + if (uor == uwsgi.offload_requests_tail) { + uwsgi.offload_requests_tail = prev; + } + + if (prev) { + prev->next = next; + } + + if (next) { + next->prev = prev; + } + + free(uor); +} + +static void uwsgi_offload_append(struct uwsgi_offload_request *uor) { + + if (!uwsgi.offload_requests_head) { + uwsgi.offload_requests_head = uor; + } + + if (uwsgi.offload_requests_tail) { + uwsgi.offload_requests_tail->next = uor; + uor->prev = uwsgi.offload_requests_tail; + } + + uwsgi.offload_requests_tail = uor; +} + +static struct uwsgi_offload_request *uwsgi_offload_get_by_socket(int s) { + struct uwsgi_offload_request *uor = uwsgi.offload_requests_head; + while(uor) { + if (uor->s == s) { + return uor; + } + uor = uor->next; + } + + return NULL; +} + static void uwsgi_offload_loop(struct uwsgi_thread *ut) { int i; @@ -46,7 +105,42 @@ static void uwsgi_offload_loop(struct uwsgi_thread *ut) { for(;;) { int nevents = event_queue_wait_multi(ut->queue, -1, events, uwsgi.static_offload_to_thread); for (i=0;ipipe[1]) { + struct uwsgi_offload_request *uor = uwsgi_malloc(sizeof(struct uwsgi_offload_request)); + ssize_t len = read(uwsgi.offload_thread->pipe[1], uor, sizeof(struct uwsgi_offload_request)); + if (len != sizeof(struct uwsgi_offload_request)) { + uwsgi_error("read()"); + free(uor); + continue; + } + // start monitoring socket for write + if (event_queue_add_fd_write(ut->queue, uor->s) < 0) { + free(uor); + continue; + } + uwsgi_offload_append(uor); + continue; + } + // ok check for socket writability + struct uwsgi_offload_request *uor = uwsgi_offload_get_by_socket(interesting_fd); + if (!uor) continue; + // sendfile() in chunks (128k is a good size...) +#if defined(__linux__) + ssize_t len = sendfile(uor->s, uor->fd, &uor->pos, 128*1024); + if (len > 0) { + uor->written += len; + if (uor->written >= uor->len) { + uwsgi_offload_close(uor); + } + continue; + } + else if (len < 0) { + if (errno == EAGAIN) continue; + uwsgi_error("sendfile()"); + } + uwsgi_offload_close(uor); +#endif } } } diff --git a/core/socket.c b/core/socket.c index 81515cd9..d388d8a1 100644 --- a/core/socket.c +++ b/core/socket.c @@ -1751,7 +1751,8 @@ setup_proto: uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header; uwsgi_sock->proto_sendfile = NULL; uwsgi_sock->proto_close = uwsgi_proto_base_close; - uwsgi_sock->can_offload = 1; + if (uwsgi.static_offload_to_thread) + uwsgi_sock->can_offload = 1; } else if (requested_protocol && (!strcmp("fastcgi", requested_protocol) || !strcmp("fcgi", requested_protocol))) { if (!strcmp(uwsgi.protocol, "fastcgi") || !strcmp(uwsgi.protocol, "fcgi")) { @@ -1780,7 +1781,8 @@ setup_proto: uwsgi_sock->proto_writev_header = uwsgi_proto_uwsgi_writev_header; uwsgi_sock->proto_sendfile = NULL; uwsgi_sock->proto_close = uwsgi_proto_base_close; - uwsgi_sock->can_offload = 1; + if (uwsgi.static_offload_to_thread) + uwsgi_sock->can_offload = 1; } nextsock: uwsgi_sock = uwsgi_sock->next; diff --git a/core/uwsgi.c b/core/uwsgi.c index c99a6989..39a9c03f 100644 --- a/core/uwsgi.c +++ b/core/uwsgi.c @@ -2599,6 +2599,14 @@ next2: // set default wsgi_req (for loading apps); uwsgi.wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[0].req; + if (uwsgi.static_offload_to_thread) { + uwsgi.offload_thread = uwsgi_offload_thread_start(); + if (!uwsgi.offload_thread) { + uwsgi_log("unable to offload static file serving !!!\n"); + uwsgi.static_offload_to_thread = 0; + } + } + // must be run before running apps for (i = 0; i < 256; i++) { if (uwsgi.p[i]->post_fork) { diff --git a/uwsgi.h b/uwsgi.h index 602a8da8..5a4fd1ca 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -1491,6 +1491,9 @@ struct uwsgi_server { int check_static_docroot; int static_offload_to_thread; struct uwsgi_thread *offload_thread; + // linked list for offloaded requests + struct uwsgi_offload_request *offload_requests_head; + struct uwsgi_offload_request *offload_requests_tail; char *daemonize; char *daemonize2; @@ -3325,6 +3328,8 @@ struct uwsgi_offload_request { off_t pos; size_t len; size_t written; + struct uwsgi_offload_request *prev; + struct uwsgi_offload_request *next; }; struct uwsgi_thread *uwsgi_offload_thread_start(void);