From bdab4dcf84758559fb495fcd7a945c9565fbd91a Mon Sep 17 00:00:00 2001 From: "roberto@sirius" Date: Wed, 31 Mar 2010 09:57:16 +0200 Subject: [PATCH] uGreen fd async waiting support --- async.c | 22 +++++++++---- tests/iobound_green.py | 41 ++++++++++++++++++++++++ ugreen.c | 71 +++++++++++++++++++++++++++++++++++++++--- uwsgiconfig.py | 33 ++++++++++++++++++++ 4 files changed, 156 insertions(+), 11 deletions(-) create mode 100644 tests/iobound_green.py diff --git a/async.c b/async.c index a363b50e..510fee8e 100644 --- a/async.c +++ b/async.c @@ -279,12 +279,22 @@ struct wsgi_request *find_wsgi_req_by_fd(struct uwsgi_server *uwsgi, int fd, int struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ; int i ; - for(i=0;iasync;i++) { - if (wsgi_req->async_waiting_fd == fd && wsgi_req->async_waiting_fd_type == etype) { - return wsgi_req ; - } - wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ; - } + if (etype != -1) { + for(i=0;iasync;i++) { + if (wsgi_req->async_waiting_fd == fd && wsgi_req->async_waiting_fd_type == etype) { + return wsgi_req ; + } + wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ; + } + } + else { + for(i=0;iasync;i++) { + if (wsgi_req->async_waiting_fd == fd) { + return wsgi_req ; + } + wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ; + } + } return NULL ; diff --git a/tests/iobound_green.py b/tests/iobound_green.py new file mode 100644 index 00000000..0973c0c6 --- /dev/null +++ b/tests/iobound_green.py @@ -0,0 +1,41 @@ +import uwsgi +import socket +import errno + +def send_request(env, client): + + client.setblocking(1) + + client.send(b"GET /intl/it_it/images/logo.gif HTTP/1.0\r\n") + client.send(b"Host: www.google.it\r\n\r\n") + + uwsgi.green_schedule() + + while 1: + uwsgi.green_wait_fdread(client.fileno(), 10) + buf = client.recv(4096) + if len(buf) == 0: + break + else: + yield buf + + +def application(env, start_response): + + s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + s.setblocking(0) + + c = s.connect_ex(('74.125.77.104', 80)) + if c == errno.EINPROGRESS: + uwsgi.green_wait_fdwrite(s.fileno(), 10) + for r in send_request(env, s): + yield r + elif c == errno.EISCONN: + for r in send_request(env, s): + yield r + else: + uwsgi.green_schedule() + start_response( '500 Internal Server Error', [ ('Content-Type', 'text/html')]) + yield "Internal Server Error" + + s.close() diff --git a/ugreen.c b/ugreen.c index f90fab0b..81c2dbf9 100644 --- a/ugreen.c +++ b/ugreen.c @@ -6,23 +6,22 @@ TODO -io and sleep management +io, timeout and sleep management */ #include "uwsgi.h" -#define UGREEN_DEFAULT_STACKSIZE 128*1024 +#define UGREEN_DEFAULT_STACKSIZE 256*1024 extern struct uwsgi_server uwsgi; - static int u_green_blocking(struct uwsgi_server *uwsgi) { struct wsgi_request* wsgi_req = uwsgi->wsgi_requests ; int i ; for(i=0;iasync;i++) { - if (wsgi_req->async_status != UWSGI_ACCEPTING) { + if (wsgi_req->async_status != UWSGI_ACCEPTING && wsgi_req->async_waiting_fd == -1) { return 0 ; } wsgi_req = next_wsgi_req(uwsgi, wsgi_req) ; @@ -65,6 +64,25 @@ inline static void u_green_schedule_to_req(struct uwsgi_server *uwsgi, struct ws tstate->frame = py_current_frame ; } +static void u_green_wait_for_fd(struct uwsgi_server *uwsgi, struct wsgi_request *wsgi_req, int fd, int etype, int timeout) { + + if (fd < 0) return; + + if (async_add(uwsgi->async_queue, fd, etype)) return ; + + wsgi_req->async_waiting_fd = fd ; + wsgi_req->async_waiting_fd_type = etype; + wsgi_req->async_timeout = timeout ; + + u_green_schedule_to_main(uwsgi, wsgi_req->async_id); + + async_del(uwsgi->async_queue, wsgi_req->async_waiting_fd, wsgi_req->async_waiting_fd_type); + + wsgi_req->async_waiting_fd = -1; + wsgi_req->async_timeout = 0 ; +} + + PyObject *py_uwsgi_green_schedule(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = current_wsgi_req(&uwsgi); @@ -76,8 +94,42 @@ PyObject *py_uwsgi_green_schedule(PyObject * self, PyObject * args) { } +PyObject *py_uwsgi_green_wait_fdread(PyObject * self, PyObject * args) { + + struct wsgi_request *wsgi_req = current_wsgi_req(&uwsgi); + int fd,timeout; + + if (!PyArg_ParseTuple(args, "i|i", &fd, &timeout)) { + return NULL; + } + + u_green_wait_for_fd(&uwsgi, wsgi_req, fd, ASYNC_IN, timeout); + + Py_INCREF(Py_True); + return Py_True; +} + +PyObject *py_uwsgi_green_wait_fdwrite(PyObject * self, PyObject * args) { + + struct wsgi_request *wsgi_req = current_wsgi_req(&uwsgi); + int fd,timeout; + + if (!PyArg_ParseTuple(args, "i|i", &fd, &timeout)) { + return NULL; + } + + u_green_wait_for_fd(&uwsgi, wsgi_req, fd, ASYNC_OUT, timeout); + + Py_INCREF(Py_True); + return Py_True; +} + + + PyMethodDef uwsgi_green_methods[] = { {"green_schedule", py_uwsgi_green_schedule, METH_VARARGS, ""}, + {"green_wait_fdread", py_uwsgi_green_wait_fdread, METH_VARARGS, ""}, + {"green_wait_fdwrite", py_uwsgi_green_wait_fdwrite, METH_VARARGS, ""}, { NULL, NULL } }; @@ -218,12 +270,21 @@ void u_green_loop(struct uwsgi_server *uwsgi) { if (uwsgi->async_events[i].ASYNC_FD == uwsgi->serverfd) { u_green_schedule_to_req(uwsgi, wsgi_req); } + else { + wsgi_req = find_wsgi_req_by_fd(uwsgi, uwsgi->async_events[i].ASYNC_FD, -1); + if (wsgi_req) { + u_green_schedule_to_req(uwsgi, wsgi_req); + } + else { + async_del(uwsgi->async_queue, uwsgi->async_events[i].ASYNC_FD, uwsgi->async_events[i].ASYNC_EV); + } + } } cycle: wsgi_req = find_wsgi_req_by_id(uwsgi, current) ; - if (wsgi_req->async_status != UWSGI_ACCEPTING) { + if (wsgi_req->async_status != UWSGI_ACCEPTING && wsgi_req->async_waiting_fd == -1) { u_green_schedule_to_req(uwsgi, wsgi_req); } current++; diff --git a/uwsgiconfig.py b/uwsgiconfig.py index c952d86a..715a6036 100644 --- a/uwsgiconfig.py +++ b/uwsgiconfig.py @@ -18,6 +18,7 @@ ASYNC=True UGREEN=True STACKLESS=False PLUGINS = [] +UNBIT=False UWSGI_BIN_NAME = 'uwsgi' GCC='gcc' @@ -101,6 +102,31 @@ def build_uwsgi(bin_name): bin_name = './' + bin_name print("*** uWSGI is ready, launch it with %s ***" % bin_name) +def unbit_setup(): + global XML, SNMP, SCTP, ERLANG, SPOOLER + global EMBEDDED, UDP, MULTICAST, THREADING + global SENDFILE, PROFILER, NAGIOS, PROXY + + global UWSGI_BIN_NAME + + XML=False + SNMP=False + SCTP=False + ERLANG=False + UDP=False + MULTICAST=False + NAGIOS=False + PROXY=False + + EMBEDDED=True + SPOOLER=True + THREADING=True + SENDFILE=True + PROFILER=True + + UNBIT=True + UWSGI_BIN_NAME='/usr/share/unbit/uwsgi26' + def parse_vars(): @@ -211,6 +237,9 @@ def parse_vars(): cflags.append("-DUWSGI_SPOOLER") gcc_list.append('spooler') + if UNBIT: + cflags.append("-DUWSGI_UNBIT") + def build_plugin(path): path = path.rstrip('/') @@ -255,6 +284,10 @@ if __name__ == "__main__": elif cmd == '--build': parse_vars() build_uwsgi(UWSGI_BIN_NAME) + elif cmd == '--unbit': + unbit_setup() + parse_vars() + build_uwsgi(UWSGI_BIN_NAME) elif cmd == '--plugin': parse_vars() build_plugin(sys.argv[2])