non blocking wsgi.input in gevent

This commit is contained in:
Roberto De Ioris
2012-10-22 15:58:36 +02:00
parent 49140c3387
commit 7017712c6d
4 changed files with 193 additions and 52 deletions
+2
View File
@@ -239,6 +239,8 @@ pep405:
up.wsgi_writeout = PyCFunction_New(uwsgi_write_method, NULL);
up.hook_write_string = python_simple_hook_write_string;
up.hook_wsgi_input_read = uwsgi_python_hook_simple_input_read;
up.hook_wsgi_input_readline = uwsgi_python_hook_simple_input_readline;
up.main_thread = PyThreadState_Get();
+5
View File
@@ -187,6 +187,8 @@ struct uwsgi_python {
int start_response_nodelay;
void (*hook_write_string)(struct wsgi_request *, PyObject *);
ssize_t (*hook_wsgi_input_read)(struct wsgi_request *, char *, size_t);
ssize_t (*hook_wsgi_input_readline)(struct wsgi_request *, char *, size_t);
char *programname;
};
@@ -279,6 +281,9 @@ int uwsgi_python_do_send_headers(struct wsgi_request *);
void *uwsgi_python_tracebacker_thread(void *);
PyObject *uwsgi_python_setup_thread(char *);
ssize_t uwsgi_python_hook_simple_input_read(struct wsgi_request *, char *, size_t);
ssize_t uwsgi_python_hook_simple_input_readline(struct wsgi_request *, char *, size_t);
#ifdef UWSGI_PYPY
#undef UWSGI_MINTERPRETERS
#endif
+59 -36
View File
@@ -9,6 +9,24 @@ PyObject *uwsgi_Input_iter(PyObject *self) {
return self;
}
ssize_t uwsgi_python_hook_simple_input_readline(struct wsgi_request *wsgi_req, char *readline, size_t max_size) {
ssize_t rlen = 0;
UWSGI_RELEASE_GIL;
if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
UWSGI_GET_GIL
return 0;
}
if (max_size > 0 && max_size < UWSGI_PY_READLINE_BUFSIZE) {
rlen = read(wsgi_req->poll.fd, readline, max_size);
}
else {
rlen = read(wsgi_req->poll.fd, readline, UWSGI_PY_READLINE_BUFSIZE);
}
UWSGI_GET_GIL;
return rlen;
}
PyObject *uwsgi_Input_getline(uwsgi_Input *self) {
size_t i;
ssize_t rlen;
@@ -40,29 +58,18 @@ PyObject *uwsgi_Input_getline(uwsgi_Input *self) {
}
UWSGI_RELEASE_GIL;
if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
UWSGI_GET_GIL
rlen = up.hook_wsgi_input_readline(wsgi_req, self->readline, self->readline_max_size);
if (rlen < 0) {
return PyErr_Format(PyExc_IOError, "error reading for wsgi.input data (readline/getline)");
}
else if (rlen == 0) {
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data (readline/getline)");
}
if (self->readline_max_size > 0 && self->readline_max_size < UWSGI_PY_READLINE_BUFSIZE) {
rlen = read(wsgi_req->poll.fd, self->readline, self->readline_max_size);
}
else {
rlen = read(wsgi_req->poll.fd, self->readline, UWSGI_PY_READLINE_BUFSIZE);
}
if (rlen <= 0) {
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data (readline/getline)");
}
self->readline_size = rlen;
self->readline_pos = 0;
self->pos += rlen;
UWSGI_GET_GIL;
for(i=0;i<(size_t)rlen;i++) {
if (self->readline[i] == '\n') {
res = PyString_FromStringAndSize(self->readline, i+1);
@@ -91,11 +98,37 @@ static void uwsgi_Input_free(uwsgi_Input *self) {
PyObject_Del(self);
}
ssize_t uwsgi_python_hook_simple_input_read(struct wsgi_request *wsgi_req, char *tmp_buf, size_t remains) {
size_t tmp_pos = 0;
UWSGI_RELEASE_GIL
while(remains) {
if (uwsgi_waitfd(wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
UWSGI_GET_GIL
return 0;
}
ssize_t rlen = read(wsgi_req->poll.fd, tmp_buf+tmp_pos, remains);
if (rlen <= 0) {
UWSGI_GET_GIL
return -1;
}
tmp_pos += rlen;
remains -= rlen;
}
UWSGI_GET_GIL
return tmp_pos;
}
static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
long len = 0;
size_t remains, tmp_pos = 0;
ssize_t rlen;
size_t remains;
ssize_t tmp_pos = 0;
char *tmp_buf;
PyObject *res;
@@ -144,28 +177,18 @@ static PyObject *uwsgi_Input_read(uwsgi_Input *self, PyObject *args) {
return res;
}
UWSGI_RELEASE_GIL
tmp_buf = uwsgi_malloc(remains);
while(remains) {
if (uwsgi_waitfd(self->wsgi_req->poll.fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]) <= 0) {
free(tmp_buf);
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data: Content-Length %llu requested %llu received %llu", (unsigned long long) self->wsgi_req->post_cl, (unsigned long long) remains + tmp_pos, (unsigned long long) tmp_pos);
}
rlen = read(self->wsgi_req->poll.fd, tmp_buf+tmp_pos, remains);
if (rlen <= 0) {
free(tmp_buf);
UWSGI_GET_GIL
return PyErr_Format(PyExc_IOError, "error reading wsgi.input data: Content-Length %llu requested %llu received %llu", (unsigned long long) self->wsgi_req->post_cl, (unsigned long long) remains + tmp_pos, (unsigned long long) tmp_pos);
}
tmp_pos += rlen;
remains -= rlen;
tmp_pos = up.hook_wsgi_input_read(self->wsgi_req, tmp_buf, remains);
if (tmp_pos < 0) {
free(tmp_buf);
return PyErr_Format(PyExc_IOError, "error reading for wsgi.input data: Content-Length %llu requested %llu received %llu", (unsigned long long) self->wsgi_req->post_cl, (unsigned long long) (remains + (tmp_pos+1)), (unsigned long long) (tmp_pos+1));
}
else if (tmp_pos == 0) {
free(tmp_buf);
return PyErr_Format(PyExc_IOError, "error waiting for wsgi.input data: Content-Length %llu requested %llu received %llu", (unsigned long long) self->wsgi_req->post_cl, (unsigned long long) (remains + tmp_pos), (unsigned long long) tmp_pos);
}
UWSGI_GET_GIL
self->pos += tmp_pos;
res = PyString_FromStringAndSize(tmp_buf, tmp_pos);
free(tmp_buf);