diff --git a/async.c b/async.c index ddf86e76..d8423be6 100644 --- a/async.c +++ b/async.c @@ -2,198 +2,374 @@ extern struct uwsgi_server uwsgi; -int async_get_timeout() { - - struct wsgi_request* wsgi_req ; - int i ; - time_t curtime, tdelta = 0 ; - int ret = 0 ; - - // do not wait if there are cores running - if (!uwsgi.async_running) return 0; - - for(i=0;iasync_status == UWSGI_AGAIN) { - if (wsgi_req->async_timeout_expired) { - // do not wait if there are timeout expired - return 0; - } - if (wsgi_req->async_timeout > 0) { - if (tdelta <= 0 || tdelta > wsgi_req->async_timeout) { - tdelta = wsgi_req->async_timeout ; - } - } - } - } - - curtime = time(NULL); - - ret = tdelta - curtime ; - if (ret > 0) { - return ret; - } - - return -1; +struct wsgi_request *find_wsgi_req_by_fd(int fd) { + return uwsgi.async_waiting_fd_table[fd]; } -void async_expire_timeouts() { +void runqueue_remove(struct uwsgi_async_request *u_request) { - struct wsgi_request* wsgi_req ; - int i ; - time_t deadline = time(NULL); - - - for(i=0;iasync_status == UWSGI_AGAIN && wsgi_req->async_timeout > 0) { - if (wsgi_req->async_timeout <= deadline) { - wsgi_req->async_timeout = 0 ; - wsgi_req->async_timeout_expired = 1 ; - if (wsgi_req->async_waiting_fd != -1) { - event_queue_del_fd(uwsgi.async_queue, wsgi_req->async_waiting_fd); - uwsgi.async_waiting_fd_table[wsgi_req->async_waiting_fd] = -1; - wsgi_req->async_waiting_fd = -1; - wsgi_req->async_waiting_fd_monitored = 0; - } - } - } + struct uwsgi_async_request *parent = u_request->prev; + struct uwsgi_async_request *child = u_request->next; + + if (parent) { + parent->next = child; } + if (child) { + child->prev = parent; + } + + if (parent == NULL) { + uwsgi.async_runqueue = child; + } + + if (u_request == uwsgi.async_runqueue_last) { + uwsgi.async_runqueue_last = parent; + } + + free(u_request); + + uwsgi.async_runqueue_cnt--; +} + +void runqueue_push(struct wsgi_request *wsgi_req) { + + struct uwsgi_async_request *uar; + + if (uwsgi.async_runqueue == NULL) { + // empty runqueue, create a new one + uwsgi.async_runqueue = uwsgi_malloc(sizeof(struct uwsgi_async_request)); + uwsgi.async_runqueue->next = NULL; + uwsgi.async_runqueue->prev = NULL; + uwsgi.async_runqueue->wsgi_req = wsgi_req; + uwsgi.async_runqueue_last = uwsgi.async_runqueue; + } + else { + uar = uwsgi_malloc(sizeof(struct uwsgi_async_request)); + uar->prev = uwsgi.async_runqueue_last; + uar->next = NULL; + uar->wsgi_req = wsgi_req; + uwsgi.async_runqueue_last->next = uar; + uwsgi.async_runqueue_last = uar; + } + + uwsgi.async_runqueue_cnt++; + } struct wsgi_request *find_first_available_wsgi_req() { - struct wsgi_request* wsgi_req; - int i ; + struct wsgi_request *wsgi_req; - // optimization - if (uwsgi.async_current_max > 1) { - if (uwsgi.wsgi_requests[uwsgi.async_current_max-1]->async_status == UWSGI_OK) { - //uwsgi_log("decreasing current max cores\n"); - uwsgi.async_current_max--; - } + if (uwsgi.async_queue_unused_ptr < 0) { + return NULL; } - for(i=0;iasync_status == UWSGI_OK) { - // optimization - if (i > uwsgi.async_current_max-1) uwsgi.async_current_max = i+1; - wsgi_req->async_id = i; - return wsgi_req ; + wsgi_req = uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr]; + uwsgi.async_queue_unused_ptr--; + return wsgi_req; +} + +void async_expire_timeouts() { + + struct wsgi_request *wsgi_req; + time_t current_time = time(NULL); + struct uwsgi_async_fd *uaf = NULL, *current_uaf; + + struct uwsgi_rb_timer *urbt; + + for(;;) { + + urbt = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts); + + if (urbt == NULL) return; + + if (urbt->key <= current_time) { + wsgi_req = (struct wsgi_request *) urbt->data; + // timeout expired + wsgi_req->async_timed_out = 1; + rb_erase(&wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts); + free(wsgi_req->async_timeout); + wsgi_req->async_timeout = NULL; + uaf = wsgi_req->waiting_fds; + // remove fds from monitoring (no problem modifying the queue here, as the function is executed only when there are no fd ready) + while(uaf) { + event_queue_del_fd(uwsgi.async_queue, uaf->fd, uaf->event); + uwsgi.async_waiting_fd_table[uaf->fd] = NULL; + current_uaf = uaf; + uaf = current_uaf->next; + free(current_uaf); + } + wsgi_req->waiting_fds = NULL; + // put th request in the runqueue + runqueue_push(wsgi_req); + continue; } + + break; } - return NULL ; } -struct wsgi_request *find_wsgi_req_by_fd(int fd) { +void async_add_fd_read(struct wsgi_request *wsgi_req, int fd, int timeout) { - struct wsgi_request* wsgi_req = NULL ; - int core_id = uwsgi.async_waiting_fd_table[fd]; + struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds; - if (core_id == -1) return NULL; + if (fd < 0) return ; - wsgi_req = uwsgi.wsgi_requests[core_id]; - //if (wsgi_req->async_waiting_fd_type == etype) return wsgi_req ; - return wsgi_req; + // find first slot + while(uad) { + last_uad = uad; + uad = uad->next; + } - return NULL ; + uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd)); + uad->fd = fd; + uad->event = event_queue_read(); + uad->prev = last_uad; + uad->next = NULL; -} + if (last_uad) { + last_uad->next = uad; + } + else { + wsgi_req->waiting_fds = uad; + } -void async_set_timeout(struct wsgi_request *wsgi_req, time_t timeout) { - - wsgi_req->async_timeout = time(NULL); - wsgi_req->async_timeout += timeout; - wsgi_req->async_timeout_expired = 0 ; + if (timeout > 0) { + async_add_timeout(wsgi_req, timeout); + } + uwsgi.async_waiting_fd_table[fd] = wsgi_req; + event_queue_add_fd_read(uwsgi.async_queue, fd); } -void async_write_all(char *data, size_t len) { - - struct wsgi_request *wsgi_req; - int i; - ssize_t rlen ; +void async_add_timeout(struct wsgi_request *wsgi_req, int timeout) { - for(i=0;iasync_status == UWSGI_PAUSED) { - rlen = write(wsgi_req->poll.fd, data, len); - if (rlen < 0) { - uwsgi_error("write()"); + if (timeout > 0 && wsgi_req->async_timeout == NULL) { + wsgi_req->async_timeout = uwsgi_add_rb_timer(uwsgi.rb_async_timeouts, time(NULL)+timeout, wsgi_req); + } + +} + +void async_add_fd_write(struct wsgi_request *wsgi_req, int fd, int timeout) { + + struct uwsgi_async_fd *last_uad = NULL, *uad = wsgi_req->waiting_fds; + + if (fd < 0) return ; + + // find first slot + while(uad) { + last_uad = uad; + uad = uad->next; + } + + uad = uwsgi_malloc(sizeof(struct uwsgi_async_fd)); + uad->fd = fd; + uad->event = event_queue_write(); + uad->prev = last_uad; + uad->next = NULL; + + if (last_uad) { + last_uad->next = uad; + } + else { + wsgi_req->waiting_fds = uad; + } + + if (timeout > 0) { + async_add_timeout(wsgi_req, timeout); + } + + uwsgi.async_waiting_fd_table[fd] = wsgi_req; + event_queue_add_fd_write(uwsgi.async_queue, fd); + +} + + +void *async_loop(void *arg1) { + + struct uwsgi_async_fd *tmp_uaf; + int interesting_fd, i; + struct uwsgi_rb_timer *min_timeout; + int timeout; + + struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL; + + void *events = event_queue_alloc(64); + + uwsgi.async_runqueue = NULL; + uwsgi.async_runqueue_cnt = 0; + + while (uwsgi.workers[uwsgi.mywid].manage_next_request) { + + if (uwsgi.async_runqueue_cnt) { + timeout = 0; + } + else { + min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts); + if (uwsgi.async_runqueue_cnt) { + timeout = 0; + } + if (min_timeout) { + timeout = min_timeout->key - time(NULL); + if (timeout <= 0) { + async_expire_timeouts(); + timeout = 0; + } } else { - wsgi_req->response_size += rlen ; + timeout = -1; + } + } + + uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64); + + // timeout ??? + if (uwsgi.async_nevents == 0) { + async_expire_timeouts(); + } + + for(i=0;iasync_id ); + if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) { + continue; + } + + +// on linux we do not need to reset the socket to blocking state +#ifndef __linux__ + if (uwsgi.numproc > 1) { + /* re-set blocking socket */ + if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi.sockets[0].arg) < 0) { + uwsgi_error("fcntl()"); + continue; + } + } +#endif + + + if (wsgi_req_recv(uwsgi.wsgi_req)) { + continue; + } + + if (uwsgi.wsgi_req->async_status == UWSGI_OK) { + // fast request, close it + // remove all the monitored fds and timeout + while(uwsgi.wsgi_req->waiting_fds) { + event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event); + tmp_uaf = uwsgi.wsgi_req->waiting_fds; + uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL; + uwsgi.wsgi_req->waiting_fds = tmp_uaf->next; + free(tmp_uaf); + } + uwsgi.wsgi_req->waiting_fds = NULL; + if (uwsgi.wsgi_req->async_timeout) { + rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts); + free(uwsgi.wsgi_req->async_timeout); + uwsgi.wsgi_req->async_timeout = NULL; + } + uwsgi_close_request(uwsgi.wsgi_req); + // push the wsgi_request in the unused stack + uwsgi.async_queue_unused_ptr++; + uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; + } + else if (!uwsgi.wsgi_req->waiting_fds && !uwsgi.wsgi_req->async_timeout) { + // suspended request put it in the runqueue + runqueue_push(uwsgi.wsgi_req); + } + } + else { + // app event + uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd); + // unknown fd, remove it (for safety) + if (uwsgi.wsgi_req == NULL) { + close(interesting_fd); + continue; + } + + // remove all the fd monitors and timeout + while(uwsgi.wsgi_req->waiting_fds) { + event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event); + tmp_uaf = uwsgi.wsgi_req->waiting_fds; + uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL; + uwsgi.wsgi_req->waiting_fds = tmp_uaf->next; + free(tmp_uaf); + } + uwsgi.wsgi_req->waiting_fds = NULL; + if (uwsgi.wsgi_req->async_timeout) { + rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts); + free(uwsgi.wsgi_req->async_timeout); + uwsgi.wsgi_req->async_timeout = NULL; + } + + uwsgi.wsgi_req->async_ready_fd = 1; + uwsgi.wsgi_req->async_last_ready_fd = interesting_fd; + + // put the request in the runqueue again + runqueue_push(uwsgi.wsgi_req); } } - } -} -void async_unpause_all() { - - struct wsgi_request *wsgi_req ; - int i; + // event queue managed, give cpu to runqueue + + if (!current_request) + current_request = uwsgi.async_runqueue; + + if (uwsgi.async_runqueue_cnt) { + + + uwsgi.wsgi_req = current_request->wsgi_req; + uwsgi.wsgi_req->async_status = uwsgi.p[uwsgi.wsgi_req->uh.modifier1]->request(uwsgi.wsgi_req); + + next_async_request = current_request->next; + // request ended ? + if (uwsgi.wsgi_req->async_status == UWSGI_OK) { + // remove all the monitored fds and timeout + while(uwsgi.wsgi_req->waiting_fds) { + event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event); + tmp_uaf = uwsgi.wsgi_req->waiting_fds; + uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL; + uwsgi.wsgi_req->waiting_fds = tmp_uaf->next; + free(tmp_uaf); + } + uwsgi.wsgi_req->waiting_fds = NULL; + if (uwsgi.wsgi_req->async_timeout) { + rb_erase(&uwsgi.wsgi_req->async_timeout->rbt, uwsgi.rb_async_timeouts); + free(uwsgi.wsgi_req->async_timeout); + uwsgi.wsgi_req->async_timeout = NULL; + } + + // remove from the list + runqueue_remove(current_request); + + uwsgi_close_request(uwsgi.wsgi_req); + + // push wsgi_request in the unused stack + uwsgi.async_queue_unused_ptr++; + uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; + + } + else if (uwsgi.wsgi_req->waiting_fds || uwsgi.wsgi_req->async_timeout) { + // remove this request from suspended list + runqueue_remove(current_request); + } + + current_request = next_async_request; - for(i=0;iasync_status == UWSGI_PAUSED) { - wsgi_req->async_status = UWSGI_AGAIN; } - } -} -struct wsgi_request * async_loop() { - struct wsgi_request *wsgi_req ; - int i ; - int ret; - - uwsgi.async_running = -1 ; - - for(i=0;iasync_status == UWSGI_AGAIN) { - if (wsgi_req->sigwait) { - uwsgi_log("waiting for signal\n"); - continue; - } - else if (wsgi_req->async_waiting_fd != -1 && !wsgi_req->async_waiting_fd_monitored) { - // add fd to monitoring - ret = -1; - if (wsgi_req->async_waiting_fd_type == ASYNC_IN) { - ret = event_queue_add_fd_read(uwsgi.async_queue, wsgi_req->async_waiting_fd); - } - else if (wsgi_req->async_waiting_fd_type == ASYNC_OUT) { - ret = event_queue_add_fd_write(uwsgi.async_queue, wsgi_req->async_waiting_fd); - } - - if (ret < 0) { - // error adding fd to the async queue, better to close it... - close(wsgi_req->async_waiting_fd); - wsgi_req->async_status = UWSGI_OK ; - return wsgi_req; - } - uwsgi.async_waiting_fd_table[wsgi_req->async_waiting_fd] = wsgi_req->async_id; - wsgi_req->async_waiting_fd_monitored = 1; - wsgi_req->async_status = UWSGI_AGAIN; - } - else if (wsgi_req->async_waiting_fd == -1 && wsgi_req->async_timeout <= 0) { - uwsgi.async_running = 0 ; - // st global wsgi_req - uwsgi.wsgi_req = wsgi_req ; - - uwsgi_log("!!! getting new part\n"); - wsgi_req->async_status = uwsgi.p[wsgi_req->uh.modifier1]->request(wsgi_req);; - - wsgi_req->switches++; - - if (wsgi_req->async_status < UWSGI_AGAIN) { - return wsgi_req; - } - } - } } return NULL; diff --git a/event.c b/event.c index 62036ae6..47339593 100644 --- a/event.c +++ b/event.c @@ -6,6 +6,9 @@ extern struct uwsgi_server uwsgi; #include +#define UWSGI_EVENT_IN POLLIN +#define UWSGI_EVENT_OUT POLLOUT + int event_queue_init() { int port = port_create(); @@ -18,7 +21,7 @@ int event_queue_init() { return port; } -int event_queue_del_fd(int eq, int fd) { +int event_queue_del_fd(int eq, int fd, int event) { if (port_dissociate(eq, PORT_SOURCE_FD, fd)) { uwsgi_error("port_disassociate"); @@ -160,6 +163,9 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) { #include +#define UWSGI_EVENT_IN EPOLLIN +#define UWSGI_EVENT_OUT EPOLLOUT + int event_queue_init() { int epfd; @@ -207,12 +213,13 @@ int event_queue_fd_write_to_read(int eq, int fd) { return fd; } -int event_queue_del_fd(int eq, int fd) { +int event_queue_del_fd(int eq, int fd, int event) { struct epoll_event ee; memset(&ee, 0, sizeof(struct epoll_event)); ee.data.fd = fd; + ee.events = event; if (epoll_ctl(eq, EPOLL_CTL_DEL, fd, &ee)) { uwsgi_error("epoll_ctl()"); @@ -298,6 +305,10 @@ int event_queue_wait(int eq, int timeout, int *interesting_fd) { #endif #ifdef UWSGI_EVENT_USE_KQUEUE + +#define UWSGI_EVENT_IN EVFILT_READ +#define UWSGI_EVENT_OUT EVFILT_WRITE + int event_queue_init() { int kfd = kqueue(); @@ -329,11 +340,11 @@ int event_queue_fd_write_to_read(int eq, int fd) { return fd; } -int event_queue_del_fd(int eq, int fd) { +int event_queue_del_fd(int eq, int fd, int event) { struct kevent kev; - EV_SET(&kev, fd, EVFILT_READ, EV_DELETE, 0, 0, 0); + EV_SET(&kev, fd, event, EV_DELETE, 0, 0, 0); if (kevent(eq, &kev, 1, NULL, 0, NULL) < 0) { uwsgi_error("kevent()"); return -1; @@ -831,3 +842,11 @@ struct uwsgi_timer *event_queue_ack_timer(int id) { } #endif + +inline int event_queue_read() { + return UWSGI_EVENT_IN; +} + +inline int event_queue_write() { + return UWSGI_EVENT_OUT; +} diff --git a/loop.c b/loop.c index acff8021..77a7b38b 100644 --- a/loop.c +++ b/loop.c @@ -87,106 +87,3 @@ void *simple_loop(void *arg1) { //never here return NULL; } - -#ifdef UWSGI_ASYNC -void complex_loop() { - int current_async_timeout = 0; - int i, j; - int interesting_fd; - - struct wsgi_request *wsgi_req; - - while (uwsgi.workers[uwsgi.mywid].manage_next_request) { - - current_async_timeout = async_get_timeout(); - - uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, current_async_timeout, uwsgi.async_events, 64); - async_expire_timeouts(); - - if (uwsgi.async_nevents < 0) { - continue; - } - - - - for(i=0; iasync_id ); - - if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) { - continue; - } - -// on linux we do not need to reset the socket to blocking state -#ifndef __linux__ - if (uwsgi.numproc > 1) { - /* re-set blocking socket */ - if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, uwsgi.sockets[0].arg) < 0) { - uwsgi_error("fcntl()"); - continue; - } - } -#endif - - if (wsgi_req_recv(uwsgi.wsgi_req)) { - continue; - } - - if (uwsgi.wsgi_req->async_status == UWSGI_OK) { - goto reqclear; - } - - } - else if ( interesting_fd == uwsgi.sockets_poll[uwsgi.sockets_cnt].fd) { - // wake up cores waiting for signal - char byte; - if (read(uwsgi.sockets_poll[uwsgi.sockets_cnt].fd, &byte, 1) == 1) { - } - else { - uwsgi_error("read()"); - } - for(j=0;jsigwait) { - wsgi_req->signal_received = byte; - wsgi_req->sigwait = 0; - } - } - } - else { - uwsgi.wsgi_req = find_wsgi_req_by_fd(interesting_fd); - if (uwsgi.wsgi_req) { - uwsgi.wsgi_req->async_status = UWSGI_AGAIN; - uwsgi.wsgi_req->async_waiting_fd = -1; - uwsgi.wsgi_req->async_waiting_fd_monitored = 0; - uwsgi.wsgi_req->async_timeout = 0; - } - - event_queue_del_fd(uwsgi.async_queue, interesting_fd); - } - } - -cycle: - - uwsgi.wsgi_req = async_loop(); - - if (uwsgi.wsgi_req == NULL) - continue; - uwsgi.wsgi_req->async_status = UWSGI_OK; - -reqclear: - uwsgi_close_request(uwsgi.wsgi_req); - - } -} -#endif diff --git a/plugins/fastrouter/fastrouter.c b/plugins/fastrouter/fastrouter.c index 934179f1..c463398f 100644 --- a/plugins/fastrouter/fastrouter.c +++ b/plugins/fastrouter/fastrouter.c @@ -345,8 +345,7 @@ void fastrouter_loop() { break; } - event_queue_del_fd(fr_queue, fr_session->instance_fd); - event_queue_add_fd_read(fr_queue, fr_session->instance_fd); + event_queue_fd_write_to_read(fr_queue, fr_session->instance_fd); fr_session->status = FASTROUTER_STATUS_RESPONSE; } diff --git a/plugins/python/uwsgi_pymodule.c b/plugins/python/uwsgi_pymodule.c index 2e1e8398..3e4ef13f 100644 --- a/plugins/python/uwsgi_pymodule.c +++ b/plugins/python/uwsgi_pymodule.c @@ -813,16 +813,16 @@ PyObject *py_uwsgi_advanced_sendfile(PyObject * self, PyObject * args) { PyObject *py_uwsgi_async_sleep(PyObject * self, PyObject * args) { float timeout; - time_t sec_timeout; + int sec_timeout; if (!PyArg_ParseTuple(args, "f:async_sleep", &timeout)) { return NULL; } - sec_timeout = (time_t) timeout; + sec_timeout = (int) timeout; if (sec_timeout > 0) { - async_set_timeout(uwsgi.wsgi_req, sec_timeout); + async_add_timeout(uwsgi.wsgi_req, sec_timeout); } return PyString_FromString(""); diff --git a/plugins/python/wsgi_handlers.c b/plugins/python/wsgi_handlers.c index 4b64be58..0f70eafa 100644 --- a/plugins/python/wsgi_handlers.c +++ b/plugins/python/wsgi_handlers.c @@ -196,12 +196,7 @@ PyObject *py_eventfd_read(PyObject * self, PyObject * args) { } if (fd >= 0) { - wsgi_req->async_waiting_fd = fd; - wsgi_req->async_waiting_fd_type = ASYNC_IN; - wsgi_req->async_waiting_fd_monitored = 0; - if (timeout > 0) { - wsgi_req->async_timeout = time(NULL) + timeout; - } + async_add_fd_read(wsgi_req, fd, timeout); } return PyString_FromString(""); @@ -218,12 +213,7 @@ PyObject *py_eventfd_write(PyObject * self, PyObject * args) { } if (fd >= 0) { - wsgi_req->async_waiting_fd = fd; - wsgi_req->async_waiting_fd_type = ASYNC_OUT; - wsgi_req->async_waiting_fd_monitored = 0; - if (timeout > 0) { - wsgi_req->async_timeout = time(NULL) + timeout; - } + async_add_fd_write(wsgi_req, fd, timeout); } return PyString_FromString(""); @@ -249,13 +239,21 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) { #ifdef UWSGI_ASYNC if (wsgi_req->async_status == UWSGI_AGAIN) { // get rid of timeout - if (wsgi_req->async_timeout_expired) { + if (wsgi_req->async_timed_out) { PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_True); - wsgi_req->async_timeout_expired = 0; + wsgi_req->async_timed_out = 0; } else { PyDict_SetItemString(wsgi_req->async_environ, "x-wsgiorg.fdevent.timeout", Py_None); } + + if (wsgi_req->async_ready_fd) { + PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.ready_fd", PyInt_FromLong(wsgi_req->async_last_ready_fd)); + wsgi_req->async_ready_fd = 0; + } + else { + PyDict_SetItemString(wsgi_req->async_environ, "uwsgi.ready_fd", Py_None); + } return manage_python_response(wsgi_req); } #endif diff --git a/plugins/python/wsgi_subhandler.c b/plugins/python/wsgi_subhandler.c index f006b335..818ed6c7 100644 --- a/plugins/python/wsgi_subhandler.c +++ b/plugins/python/wsgi_subhandler.c @@ -225,18 +225,6 @@ clear2: Py_DECREF((PyObject *)wsgi_req->async_result); PyErr_Clear(); -#ifdef UWSGI_DEBUG - if (wsgi_req->async_placeholder) { - uwsgi_debug("wsgi_req->async_placeholder: %d\n", ((PyObject *)wsgi_req->async_placeholder)->ob_refcnt); - } - if (wsgi_req->async_result) { - uwsgi_debug("wsgi_req->async_result: %d\n", ((PyObject *)wsgi_req->async_result)->ob_refcnt); - } - if (wsgi_req->async_app) { - uwsgi_debug("wsgi_req->async_app: %d\n", ((PyObject *)wsgi_req->async_app)->ob_refcnt); - } -#endif - UWSGI_RELEASE_GIL return UWSGI_OK; } diff --git a/tests/iobound_async.py b/tests/iobound_async.py index e41690f5..4cdfff23 100644 --- a/tests/iobound_async.py +++ b/tests/iobound_async.py @@ -1,16 +1,30 @@ import socket import select import errno +import uwsgi def send_request(env, client): client.setblocking(1) + + yield env['x-wsgiorg.fdevent.writable'](client.fileno(), 2) + if env['x-wsgiorg.fdevent.timeout']: + return + client.send(b"GET /intl/it_it/images/logo.gif HTTP/1.0\r\n") + + yield env['x-wsgiorg.fdevent.writable'](client.fileno(), 2) + if env['x-wsgiorg.fdevent.timeout']: + return client.send(b"Host: www.google.it\r\n\r\n") + while 1: - yield env['x-wsgiorg.fdevent.readable'](client.fileno(), 10) + yield env['x-wsgiorg.fdevent.readable'](client.fileno(), 2) + if env['x-wsgiorg.fdevent.timeout']: + return + buf = client.recv(4096) if len(buf) == 0: break @@ -28,13 +42,10 @@ def application(env, start_response): #yield "" - print "opening socket" - - c = s.connect_ex(('www.google.it', 80)) + #c = s.connect_ex(('www.google.it', 80)) + c = s.connect_ex(('74.125.232.115', 80)) if c == errno.EINPROGRESS: - print "yielding" - yield env['x-wsgiorg.fdevent.writable'](s.fileno(), 10) - print "waiting for fd write" + yield env['x-wsgiorg.fdevent.writable'](s.fileno(), 2) for r in send_request(env, s): yield r elif c == errno.EISCONN: diff --git a/utils.c b/utils.c index 23d20700..4c71d5f4 100644 --- a/utils.c +++ b/utils.c @@ -376,6 +376,7 @@ void uwsgi_as_root() { void uwsgi_close_request(struct wsgi_request *wsgi_req) { int waitpid_status; + int tmp_id; gettimeofday(&wsgi_req->end_of_request, NULL); uwsgi.workers[uwsgi.mywid].running_time += (double) (((double) (wsgi_req->end_of_request.tv_sec * 1000000 + wsgi_req->end_of_request.tv_usec) - (double) (wsgi_req->start_of_request.tv_sec * 1000000 + wsgi_req->start_of_request.tv_usec)) / (double) 1000.0); @@ -408,7 +409,9 @@ void uwsgi_close_request(struct wsgi_request *wsgi_req) { } // reset request + tmp_id = wsgi_req->async_id; memset(wsgi_req, 0, sizeof(struct wsgi_request)); + wsgi_req->async_id = tmp_id; if (uwsgi.shared->options[UWSGI_OPTION_MAX_REQUESTS] > 0 && uwsgi.workers[uwsgi.mywid].requests >= uwsgi.shared->options[UWSGI_OPTION_MAX_REQUESTS]) { goodbye_cruel_world(); @@ -426,9 +429,6 @@ void wsgi_req_setup(struct wsgi_request *wsgi_req, int async_id) { wsgi_req->sendfile_fd = -1; #endif -#ifdef UWSGI_ASYNC - wsgi_req->async_waiting_fd = -1; -#endif wsgi_req->hvec = uwsgi.async_hvec[wsgi_req->async_id]; wsgi_req->buffer = uwsgi.async_buf[wsgi_req->async_id]; diff --git a/uwsgi.c b/uwsgi.c index 37f9c625..3a3063be 100644 --- a/uwsgi.c +++ b/uwsgi.c @@ -188,7 +188,7 @@ void warn_pipe() { struct wsgi_request *wsgi_req = current_wsgi_req(); - if (uwsgi.async < 2 && wsgi_req->uri_len > 0) { + if (uwsgi.threads < 2 && wsgi_req->uri_len > 0) { uwsgi_log("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) on request %.*s (ip %.*s) !!!\n", wsgi_req->uri_len, wsgi_req->uri, wsgi_req->remote_addr_len, wsgi_req->remote_addr); } else { uwsgi_log("SIGPIPE: writing to a closed pipe/socket/fd (probably the client disconnected) !!!\n"); @@ -1170,9 +1170,10 @@ int uwsgi_start(void *v_argv) { uwsgi_register_loop("simple", simple_loop); - uwsgi_register_loop("async", complex_loop); + uwsgi_register_loop("async", async_loop); + // TODO rewrite to use uwsgi.max_fd if (uwsgi.async > 1) { if (!getrlimit(RLIMIT_NOFILE, &uwsgi.rl)) { if ((unsigned long) uwsgi.rl.rlim_cur < (unsigned long) uwsgi.async) { @@ -1209,8 +1210,8 @@ int uwsgi_start(void *v_argv) { uwsgi.async_buf = uwsgi_malloc(sizeof(char *) * uwsgi.cores); if (uwsgi.async > 1) { - uwsgi_log("%d\n", uwsgi.max_fd); - uwsgi.async_waiting_fd_table = malloc( sizeof(int) * uwsgi.max_fd); + uwsgi_log("async fd table size: %d\n", uwsgi.max_fd); + uwsgi.async_waiting_fd_table = malloc( sizeof(struct wsgi_request *) * uwsgi.max_fd); if (!uwsgi.async_waiting_fd_table) { uwsgi_error("malloc()"); exit(1); @@ -1674,20 +1675,6 @@ int uwsgi_start(void *v_argv) { } #endif -#ifdef UWSGI_ASYNC - if (uwsgi.async > 1) { -#ifdef __linux__ - uwsgi.async_events = uwsgi_malloc(sizeof(struct epoll_event) * uwsgi.async); -#elif defined(__sun__) - uwsgi.async_events = uwsgi_malloc(sizeof(struct pollfd) * uwsgi.async); -#else - uwsgi.async_events = uwsgi_malloc(sizeof(struct kevent) * uwsgi.async); -#endif - } -#endif - - - #ifndef UNBIT uwsgi_log("your server socket listen backlog is limited to %d connections\n", uwsgi.listen_queue); @@ -1969,6 +1956,16 @@ uwsgi.shared->hooks[UWSGI_MODIFIER_PING] = uwsgi_request_ping; //100 event_queue_add_fd_read(uwsgi.async_queue, uwsgi.sockets[i].fd); } } + + uwsgi.rb_async_timeouts = uwsgi_init_rb_timer(); + + uwsgi.async_queue_unused = uwsgi_malloc(sizeof(struct wsgi_request*) * uwsgi.async); + + for(i=0;ihooks[UWSGI_MODIFIER_PING] = uwsgi_request_ping; //100 //re - initialize wsgi_req(can be full of init_uwsgi_app data) for (i = 0; i < uwsgi.cores; i++) { memset(uwsgi.wsgi_requests[i], 0, sizeof(struct wsgi_request)); + uwsgi.wsgi_requests[i]->async_id = i; } @@ -2037,6 +2035,7 @@ uwsgi.shared->hooks[UWSGI_MODIFIER_PING] = uwsgi_request_ping; //100 uwsgi.sockets_poll[uwsgi.sockets_cnt].fd = uwsgi.shared->worker_signal_pipe[1]; uwsgi.sockets_poll[uwsgi.sockets_cnt].events = POLLIN; #ifdef UWSGI_ASYNC + // add uwsgi signal fd to async queue if (uwsgi.async > 1) { event_queue_add_fd_read(uwsgi.async_queue, uwsgi.sockets_poll[uwsgi.sockets_cnt].fd); } @@ -2081,7 +2080,7 @@ uwsgi.shared->hooks[UWSGI_MODIFIER_PING] = uwsgi_request_ping; //100 long y = 0; simple_loop((void *) y); } else { - complex_loop(); + async_loop(NULL); } } @@ -2518,104 +2517,11 @@ end: uwsgi.single_interpreter = 1; return 1; case 'h': + uwsgi_help(); +/* fprintf(stdout, "Usage: %s [options...]\n\ -\t-s|--socket \t\tpath (or name) of UNIX/TCP socket to bind to\n\ -\t-l|--listen \t\tset socket listen queue to (default 64, maximum is system dependent)\n\ -\t-z|--socket-timeout \tset socket timeout to seconds (default 4 seconds)\n\ -\t-b|--buffer-size \t\tset buffer size to bytes\n\ -\t-L|--disable-logging\t\tdisable request logging (only errors or server messages will be logged)\n\ -\t-x|--xmlconfig \t\tpath of xml config file\n\ -\t-w|--module \t\tname of python config module\n\ -\t-t|--harakiri \t\tset harakiri timeout to seconds\n\ -\t-p|--processes \t\tspawn uwsgi worker processes\n\ -\t-O|--optimize \t\tset python optimization level to \n\ -\t-v|--max-vars \t\tset maximum number of vars/headers to \n\ -\t-A|--sharedarea \t\tcreate a shared memory area of pages\n\ -\t-c|--cgi-mode\t\t\tset cgi mode\n\ -\t-C|--chmod-socket[=NNN]\t\tchmod socket to 666 or NNN\n\ -\t-m|--memory-report\t\tenable memory usage report\n\ -\t-i|--single-interpreter\t\tsingle interpreter mode\n\ -\t-a|--abstract-socket\t\tset socket in the abstract namespace (Linux only)\n\ -\t-T|--enable-threads\t\tenable threads support\n\ -\t-M|--master\t\t\tenable master process manager\n\ -\t-H|--home \t\tset python home/virtualenv\n\ -\t-h|--help\t\t\tthis help\n\ -\t-r|--reaper\t\t\tprocess reaper (call waitpid(-1,...) after each request)\n\ -\t-R|--max-requests\t\tmaximum number of requests for each worker\n\ -\t-j|--test\t\t\ttest if uWSGI can import a module\n\ -\t-Q|--spooler \t\trun the spooler on directory \n\ -\t--callable \t\tset the callable (default 'application')\n\ -\t--pidfile \t\twrite the masterpid to \n\ -\t--chroot \t\t\tchroot to directory (only root)\n\ -\t--gid \t\tsetgid to (only root)\n\ -\t--uid \t\tsetuid to (only root)\n\ -\t--chdir \t\t\tchdir to before app loading\n\ -\t--chdir2 \t\t\tchdir to after module loading\n\ -\t--no-server\t\t\tinitialize the uWSGI server then exit. Useful for testing and using uwsgi embedded module\n\ -\t--no-defer-accept\t\tdisable the no-standard way to defer the accept() call (TCP_DEFER_ACCEPT, SO_ACCEPTFILTER...)\n\ -\t--paste \t\tload applications using paste.deploy.loadapp()\n\ -\t--check-interval \t\tset the check interval (in seconds) of the master process\n\ -\t--pythonpath \t\tadd to PYTHONPATH\n\ -\t--python-path \t\tadd to PYTHONPATH\n\ -\t--pp \t\t\tadd to PYTHONPATH\n\ -\t--pyargv \t\t\tassign args to python sys.argv\n\ -\t--limit-as \t\t\tlimit the address space of processes to MB megabytes\n\ -\t--limit-post \t\tlimit HTTP content_length size to \n\ -\t--post-buffering \tbuffer HTTP POST request higher than to disk\n\ -\t--post-buffering-bufsize \tset the buffer size to bytes for post-buffering\n\ -\t--prio \t\t\tset process priority/nice to N\n\ -\t--no-orphans\t\t\tautomatically kill workers on master's dead\n\ -\t--udp \t\t\tbind master process to udp socket on ip:port\n\ -\t--multicast \t\tset multicast group\n\ -\t--snmp\t\t\t\tenable SNMP support in the UDP server\n\ -\t--snmp-community \tset SNMP community code to \n\ -\t--erlang \t\tenable the Erlang server with node name \n\ -\t--erlang-cookie \tset the erlang cookie to \n\ -\t--nagios\t\t\tdo a nagios check\n\ -\t--binary-path \tset the path for the next reload of uWSGI (needed for chroot environments)\n\ -\t--proxy \t\trun the uwsgi proxy on socket \n\ -\t--proxy-node \t\tadd the node to the proxy\n\ -\t--proxy-max-connections \tset the max number of concurrent connections mnaged by the proxy\n\ -\t--wsgi-file \t\tload the wsgi file\n\ -\t--file \t\t\tuse python file instead of python module for configuration\n\ -\t--eval \t\t\tevaluate code for app configuration\n\ -\t--async \t\t\tenable async mode with n core\n\ -\t--logto \t\tlog to file/udp\n\ -\t--logdate\t\t\tadd timestamp to loglines\n\ -\t--log-zero\t\t\tlog requests with 0 response size\n\ -\t--log-slow \t\t\tlog requests slower than milliseconds\n\ -\t--log-4xx\t\t\tlog requests with status code 4xx\n\ -\t--log-5xx\t\t\tlog requests with status code 5xx\n\ -\t--log-big \t\t\tlog requests bigger than bytes\n\ -\t--log-sendfile\t\t\tlog sendfile() requests\n\ -\t--ignore-script-name\t\tdisable uWSGI management of SCRIPT_NAME\n\ -\t--no-default-app\t\tdo not fallback unknown SCRIPT_NAME requests\n\ -\t--ini \t\t\tpath of ini config file\n\ -\t--ini-paste \t\tpath of ini config file that contains paste configuration\n\ -\t--ldap \t\t\turl of LDAP uWSGIConfig resource\n\ -\t--ldap-schema\t\t\tdump uWSGIConfig LDAP schema\n\ -\t--ldap-schema-ldif\t\tdump uWSGIConfig LDAP schema in LDIF format\n\ -\t--grunt\t\t\t\tenable grunt workers\n\ -\t--ugreen\t\t\tenable uGreen support\n\ -\t--ugreen-stacksize \t\tset uGreen stacksize to \n\ -\t--stackless\t\t\tenable usage of tasklet (only on Stackless Python)\n\ -\t--no-site\t\t\tdo not import site.py on startup\n\ -\t--vhost\t\t\t\tenable virtual hosting\n\ -\t--mount MOUNTPOINT=app\t\tadda new app under MOUNTPOINT\n\ -\t--routing\t\t\tenable uWSGI advanced routing\n\ -\t--http \t\t\tstart embedded HTTP server on \n\ -\t--http-only\t\t\tstart only the embedded HTTP server\n\ -\t--http-var KEY[=VALUE]\t\tadd var KEY to uwsgi requests made by the embedded HTTP server\n\ -\t--catch-exceptions\t\tprint exceptions in the browser\n\ -\t--mode\t\t\t\tset configuration mode\n\ -\t--env KEY=VALUE\t\t\tset environment variable\n\ -\t--vacuum\t\t\tclear the environment on exit (remove UNIX sockets and pidfiles)\n\ -\t--ping \t\t\tping a uWSGI server (returns 1 on failure 0 on success)\n\ -\t--ping-timeout \t\tset ping timeout to \n\ -\t--cgroup \t\trun the server in cgroup (Linux only)\n\ -\t--cgroup-opt KEY=VAL\t\tset cgroup option (Linux only)\n\ -\t--version\t\t\tprint server version\n\ \t-d|--daemonize \tdaemonize and log into or udp \n", uwsgi.binary_path); +*/ return 0; } @@ -3068,3 +2974,111 @@ char *uwsgi_cluster_best_node() { uwsgi.shared->nodes[best_node].last_choosen = time(NULL); return uwsgi.shared->nodes[best_node].name; } + + +struct uwsgi_help_item main_help[] = { + +{"socket ", "path (or name) of UNIX/TCP socket to bind to"}, +{"listen ", "set socket listen queue to (default 100, maximum is system dependent)"}, +{"socket-timeout ", "set socket timeout to seconds (default 4 seconds)"}, +{"buffer-size ", "set buffer size to bytes"}, +{"disable-logging", "disable request logging (only errors or server messages will be logged)"}, +{"xmlconfig ", "path of xml config file"}, +{"module " ,"name of python config module"}, +{"harakiri ", "set harakiri timeout to seconds"}, +{"processes ", "spawn uwsgi worker processes"}, +{"optimize ", "set python optimization level to "}, +{"max-vars ", "set maximum number of vars/headers to "}, +{"sharedarea ", "create a shared memory area of pages"}, +{"cgi-mode", "set cgi mode"}, +{"chmod-socket[=NNN]", "chmod socket to 666 or NNN"}, +{"memory-report", "enable memory usage report"}, +{"single-interpreter", "single interpreter mode"}, +{"abstract-socket", "set socket in the abstract namespace (Linux only)"}, +{"enable-threads", "enable threads support"}, +{"master", "enable master process manager"}, +{"home ", "set python home/virtualenv"}, +{"help", "this help"}, +{"reaper", "process reaper (call waitpid(-1,...) after each request)"}, +{"max-requests", "maximum number of requests for each worker"}, +{"test", "test if uWSGI can import a module"}, +{"spooler ", "run the spooler on directory "}, +{"callable ", "set the callable (default 'application')"}, +{"pidfile ", "write the masterpid to "}, +{"chroot ", "chroot to directory (only root)"}, +{"gid ", "setgid to (only root)"}, +{"uid ", "setuid to (only root)"}, +{"chdir ", "chdir to before app loading"}, +{"chdir2 ", "chdir to after module loading"}, +{"no-server", "initialize the uWSGI server then exit. Useful for testing and using uwsgi embedded module"}, +{"no-defer-accept", "disable the no-standard way to defer the accept() call (TCP_DEFER_ACCEPT, SO_ACCEPTFILTER...)"}, +{"paste ", "load applications using paste.deploy.loadapp()"}, +{"check-interval ", "set the check interval (in seconds) of the master process"}, +{"pythonpath ", "add to PYTHONPATH"}, +{"python-path ", "add to PYTHONPATH"}, +{"pp ", "add to PYTHONPATH"}, +{"pyargv ", "assign args to python sys.argv"}, +{"limit-as ", "limit the address space of processes to MB megabytes"}, +{"limit-post ", "limit HTTP content_length size to "}, +{"post-buffering ", "buffer HTTP POST request higher than to disk"}, +{"post-buffering-bufsize ", "set the buffer size to bytes for post-buffering"}, +{"prio ", "set process priority/nice to N"}, +{"no-orphans", "automatically kill workers on master's dead"}, +{"udp ", "bind master process to udp socket on ip:port"}, +{"multicast ", "set multicast group"}, +{"snmp", "enable SNMP support in the UDP server"}, +{"snmp-community ", "set SNMP community code to "}, +{"erlang ", "enable the Erlang server with node name "}, +{"erlang-cookie ", "set the erlang cookie to "}, +{"nagios", "do a nagios check"}, +{"binary-path ", "set the path for the next reload of uWSGI (needed for chroot environments)"}, +{"proxy ", "run the uwsgi proxy on socket "}, +{"proxy-node ", "add the node to the proxy"}, +{"proxy-max-connections ", "set the max number of concurrent connections mnaged by the proxy"}, +{"wsgi-file ", "load the wsgi file"}, +{"file ", "use python file instead of python module for configuration"}, +{"eval ", "evaluate code for app configuration"}, +{"async ", "enable async mode with n core"}, +{"logto ", "log to file/udp"}, +{"logdate", "add timestamp to loglines"}, +{"log-zero", "log requests with 0 response size"}, +{"log-slow ", "log requests slower than milliseconds"}, +{"log-4xx", "log requests with status code 4xx"}, +{"log-5xx", "log requests with status code 5xx"}, +{"log-big ", "log requests bigger than bytes"}, +{"log-sendfile", "log sendfile() requests"}, +{"ignore-script-name", "disable uWSGI management of SCRIPT_NAME"}, +{"no-default-app", "do not fallback unknown SCRIPT_NAME requests"}, +{"ini ", "path of ini config file"}, +{"ini-paste ", "path of ini config file that contains paste configuration"}, +{"ldap ", "url of LDAP uWSGIConfig resource"}, +{"ldap-schema", "dump uWSGIConfig LDAP schema"}, +{"ldap-schema-ldif", "dump uWSGIConfig LDAP schema in LDIF format"}, +{"grunt", "enable grunt workers"}, +{"ugreen", "enable uGreen support"}, +{"ugreen-stacksize ", "set uGreen stacksize to "}, +{"no-site", "do not import site.py on startup"}, +{"vhost", "enable virtual hosting"}, +{"mount MOUNTPOINT=app", "adda new app under MOUNTPOINT"}, +{"routing", "enable uWSGI advanced routing"}, +{"http ", "start embedded HTTP server on "}, +{"http-only", "start only the embedded HTTP server"}, +{"http-var KEY[=VALUE]", "add var KEY to uwsgi requests made by the embedded HTTP server"}, +{"catch-exceptions", "print exceptions in the browser"}, +{"mode", "set configuration mode"}, +{"env KEY=VALUE", "set environment variable"}, +{"vacuum", "clear the environment on exit (remove UNIX sockets and pidfiles)"}, +{"ping ", "ping a uWSGI server (returns 1 on failure 0 on success)"}, +{"ping-timeout ", "set ping timeout to "}, +{"cgroup ", "run the server in cgroup (Linux only)"}, +{"cgroup-opt KEY=VAL", "set cgroup option (Linux only)"}, +{"version", "print server version"}, +{"daemonize ", "daemonize and log into or udp "}, + +{ 0, 0 }, + +}; + + +void uwsgi_help(void) { +} diff --git a/uwsgi.h b/uwsgi.h index 835e2dfe..7c540939 100644 --- a/uwsgi.h +++ b/uwsgi.h @@ -560,6 +560,13 @@ struct __attribute__ ((packed)) uwsgi_header { uint8_t modifier2; }; +struct uwsgi_async_fd { + int fd; + int event; + struct uwsgi_async_fd* prev; + struct uwsgi_async_fd* next; +}; + struct wsgi_request { struct uwsgi_header uh; @@ -639,14 +646,14 @@ struct wsgi_request { int async_id; int async_status; - int async_waiting_fd; - int async_waiting_fd_type; - int async_waiting_fd_monitored; int switches; - time_t async_timeout; - int async_timeout_expired; + int async_timed_out; + int async_ready_fd; + int async_last_ready_fd; + struct uwsgi_rb_timer *async_timeout; + struct uwsgi_async_fd *waiting_fds; void *async_app; void *async_result; @@ -772,8 +779,16 @@ struct uwsgi_server { char **async_buf; char **async_post_buf; - int *async_waiting_fd_table; - int async_current_max; + struct wsgi_request **async_waiting_fd_table; + struct uwsgi_async_request *async_runqueue; + struct uwsgi_async_request *async_runqueue_last; + int async_runqueue_cnt; + + struct rb_root *rb_async_timeouts; + + int async_queue_unused_ptr; + struct wsgi_request **async_queue_unused; + #ifdef UWSGI_ROUTING int **async_ovector; @@ -835,14 +850,6 @@ struct uwsgi_server { int async_queue; int async_nevents; -#ifdef __linux__ - struct epoll_event *async_events; -#elif defined(__sun__) - struct pollfd *async_events; -#else - struct kevent *async_events; -#endif - int max_vars; int vec_size; @@ -1268,14 +1275,15 @@ struct http_status_codes { #ifdef UWSGI_ASYNC -#define ASYNC_IN 1 -#define ASYNC_OUT 2 -struct wsgi_request *async_loop(void); +void *async_loop(void *); struct wsgi_request *find_first_available_wsgi_req(void); struct wsgi_request *find_first_accepting_wsgi_req(void); struct wsgi_request *find_wsgi_req_by_fd(int); struct wsgi_request *find_wsgi_req_by_id(int); +void async_add_fd_write(struct wsgi_request *, int, int); +void async_add_fd_read(struct wsgi_request *, int, int); + #ifdef __clang__ struct wsgi_request *next_wsgi_req(struct wsgi_request *); #else @@ -1283,11 +1291,8 @@ inline struct wsgi_request *next_wsgi_req(struct wsgi_request *); #endif -int async_get_timeout(void); -void async_set_timeout(struct wsgi_request*, time_t); +void async_add_timeout(struct wsgi_request*, int); void async_expire_timeouts(void); -void async_write_all(char *, size_t); -void async_unpause_all(void); #endif @@ -1375,7 +1380,6 @@ int find_worker_id(pid_t); void *simple_loop(void *); -void complex_loop(void); int count_options(struct option *); @@ -1445,7 +1449,7 @@ int event_queue_init(void); void *event_queue_alloc(int); int event_queue_add_fd_read(int, int); int event_queue_add_fd_write(int, int); -int event_queue_del_fd(int, int); +int event_queue_del_fd(int, int, int); int event_queue_wait(int, int, int *); int event_queue_wait_multi(int, int, void *, int); int event_queue_interesting_fd(void *, int); @@ -1627,3 +1631,21 @@ int uwsgi_list_has_num(char *, int); int uwsgi_list_has_str(char *, char *); void uwsgi_cache_fix(void); + +struct uwsgi_async_request { + + struct wsgi_request *wsgi_req; + struct uwsgi_async_request *prev; + struct uwsgi_async_request *next; +}; + +inline int event_queue_read(void); +inline int event_queue_write(void); + +struct uwsgi_help_item { + + char *key; + char *value; +}; + +void uwsgi_help(void);