PyObject *py_uwsgi_stackless_worker(PyObject * self, PyObject * args) { PyThreadState *ts = PyThreadState_GET(); struct wsgi_request *wsgi_req = find_request_by_tasklet(ts->st.current); PyObject *zero; int async_id = wsgi_req->async_id; //fprintf(stderr,"i am the tasklet worker\n"); for(;;) { // wait for request zero = PyChannel_Receive(uwsgi.workers_channel); wsgi_req_setup(wsgi_req, async_id); if (wsgi_req_accept(uwsgi.serverfd, wsgi_req)) { continue; } if (wsgi_req_recv(wsgi_req)) { continue; } uwsgi_close_request(&uwsgi, wsgi_req); } }
void async_schedule_to_req_green(void) { struct wsgi_request *wsgi_req = uwsgi.wsgi_req; #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) { break; } wsgi_req->switches++; if (uwsgi.schedule_fix) { uwsgi.schedule_fix(wsgi_req); } // switch after each yield uwsgi.schedule_to_main(wsgi_req); } #ifdef UWSGI_ROUTING end: #endif // re-set the global state uwsgi.wsgi_req = wsgi_req; async_reset_request(wsgi_req); uwsgi_close_request(wsgi_req); // re-set the global state (routing could have changed it) uwsgi.wsgi_req = wsgi_req; wsgi_req->async_status = UWSGI_OK; uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = wsgi_req; }
PyObject *py_uwsgi_tornado_request(PyObject *self, PyObject *args) { int fd = -1; PyObject *events = NULL; if (!PyArg_ParseTuple(args, "iO:uwsgi_tornado_request", &fd, &events)) { uwsgi_log_verbose("[BUG] invalid arguments for tornado callback !!!\n"); exit(1); } struct wsgi_request *wsgi_req = find_wsgi_req_proto_by_fd(fd); uwsgi.wsgi_req = wsgi_req; int status = wsgi_req->socket->proto(wsgi_req); if (status > 0) goto again; if (PyObject_CallMethod(utornado.ioloop, "remove_handler", "i", fd) == NULL) { PyErr_Print(); goto end; } if (status == 0) { // we call this two time... overengineering :( uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL; uwsgi.schedule_to_req(); goto again; } end: uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL; uwsgi_close_request(uwsgi.wsgi_req); free_req_queue; again: Py_INCREF(Py_None); return Py_None; }
static PyObject *py_uwsgi_asyncio_request(PyObject *self, PyObject *args) { long wsgi_req_ptr = 0; int timed_out = 0; if (!PyArg_ParseTuple(args, "l|i:uwsgi_asyncio_request", &wsgi_req_ptr, &timed_out)) { uwsgi_log_verbose("[BUG] invalid arguments for asyncio callback !!!\n"); exit(1); } struct wsgi_request *wsgi_req = (struct wsgi_request *) wsgi_req_ptr; uwsgi.wsgi_req = wsgi_req; PyObject *ob_timeout = (PyObject *) wsgi_req->async_timeout; if (PyObject_CallMethod(ob_timeout, "cancel", NULL) == NULL) PyErr_Print(); Py_DECREF(ob_timeout); // avoid mess when closing the request wsgi_req->async_timeout = NULL; if (timed_out > 0) { if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print(); goto end; } int status = wsgi_req->socket->proto(wsgi_req); if (status > 0) { ob_timeout = PyObject_CallMethod(uasyncio.loop, "call_later", "iOli", uwsgi.socket_timeout, uasyncio.request, wsgi_req_ptr, 1); if (!ob_timeout) { if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) PyErr_Print(); goto end; } // trick for reference counting wsgi_req->async_timeout = (struct uwsgi_rb_timer *) ob_timeout; goto again; } if (PyObject_CallMethod(uasyncio.loop, "remove_reader", "i", wsgi_req->fd) == NULL) { PyErr_Print(); goto end; } if (status == 0) { // we call this two time... overengineering :( uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL; uwsgi.schedule_to_req(); goto again; } end: uwsgi.async_proto_fd_table[wsgi_req->fd] = NULL; uwsgi_close_request(uwsgi.wsgi_req); free_req_queue; again: Py_INCREF(Py_None); return Py_None; }
void *simple_loop_run(void *arg1) { long core_id = (long) arg1; struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req; if (uwsgi.threads > 1) { uwsgi_setup_thread_req(core_id, wsgi_req); } // initialize the main event queue to monitor sockets int main_queue = event_queue_init(); uwsgi_add_sockets_to_queue(main_queue, core_id); if (uwsgi.signal_socket > -1) { event_queue_add_fd_read(main_queue, uwsgi.signal_socket); event_queue_add_fd_read(main_queue, uwsgi.my_signal_socket); } // ok we are ready, let's start managing requests and signals while (uwsgi.workers[uwsgi.mywid].manage_next_request) { wsgi_req_setup(wsgi_req, core_id, NULL); if (wsgi_req_accept(main_queue, wsgi_req)) { continue; } if (wsgi_req_recv(main_queue, wsgi_req)) { uwsgi_destroy_request(wsgi_req); continue; } uwsgi_close_request(wsgi_req); } // end of the loop if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) { #ifdef __APPLE__ kill(uwsgi.workers[0].pid, SIGTERM); #else if (uwsgi.propagate_touch) { kill(uwsgi.workers[0].pid, SIGHUP); } else { gracefully_kill(0); } #endif } return NULL; }
PyObject *py_uwsgi_gevent_main(PyObject * self, PyObject * args) { struct wsgi_request *wsgi_req = find_first_available_wsgi_req(); if (wsgi_req == NULL) { uwsgi_log("async queue is full !!!\n"); goto clear; } uwsgi.wsgi_req = wsgi_req; // fill wsgi_request structure wsgi_req_setup(wsgi_req, wsgi_req->async_id, uwsgi.sockets ); // mark core as used uwsgi.core[wsgi_req->async_id]->in_request = 1; gettimeofday(&wsgi_req->start_of_request, NULL); // enter harakiri mode if (uwsgi.shared->options[UWSGI_OPTION_HARAKIRI] > 0) { set_harakiri(uwsgi.shared->options[UWSGI_OPTION_HARAKIRI]); } // accept the connection if (wsgi_req_simple_accept(wsgi_req, uwsgi.sockets->fd)) { uwsgi_close_request(wsgi_req); free_req_queue; goto clear; } // hack to easily pass wsgi_req pointer to the greenlet PyTuple_SetItem(ugevent.greenlet_args, 1, PyLong_FromLong((long)wsgi_req)); // spawn the request greenlet PyObject *new_gl = python_call(ugevent.spawn, ugevent.greenlet_args, 0, NULL); Py_DECREF(new_gl); clear: Py_INCREF(Py_None); return Py_None; }
void async_schedule_to_req_green(void) { #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) { break; } uwsgi.wsgi_req->switches++; // switch after each yield uwsgi.schedule_to_main(uwsgi.wsgi_req); } #ifdef UWSGI_ROUTING end: #endif async_reset_request(uwsgi.wsgi_req); uwsgi_close_request(uwsgi.wsgi_req); uwsgi.wsgi_req->async_status = UWSGI_OK; }
void async_schedule_to_req(void) { #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(uwsgi.wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } // a trick to avoid calling routes again uwsgi.wsgi_req->is_routing = 1; #endif if (uwsgi.p[uwsgi.wsgi_req->uh->modifier1]->request(uwsgi.wsgi_req) <= UWSGI_OK) { goto end; } if (uwsgi.schedule_to_main) { uwsgi.schedule_to_main(uwsgi.wsgi_req); } return; end: async_reset_request(uwsgi.wsgi_req); uwsgi_close_request(uwsgi.wsgi_req); uwsgi.wsgi_req->async_status = UWSGI_OK; }
static VALUE uwsgi_rb_thread_core(void *arg) { long core_id = (long) arg; struct wsgi_request *wsgi_req = &uwsgi.workers[uwsgi.mywid].cores[core_id].req; uwsgi_setup_thread_req(core_id, wsgi_req); struct uwsgi_rbthread *urbt = uwsgi_malloc(sizeof(struct uwsgi_rbthread)); // initialize the main event queue to monitor sockets urbt->queue = event_queue_init(); urbt->wsgi_req = wsgi_req; uwsgi_add_sockets_to_queue(urbt->queue, (int)core_id); if (uwsgi.signal_socket > -1) { event_queue_add_fd_read(urbt->queue, uwsgi.signal_socket); event_queue_add_fd_read(urbt->queue, uwsgi.my_signal_socket); } // ok we are ready, let's start managing requests and signals while (uwsgi.workers[uwsgi.mywid].manage_next_request) { wsgi_req_setup(wsgi_req, (int)core_id, NULL); rb_thread_call_without_gvl(uwsgi_rb_thread_accept, urbt, NULL, NULL); // accept failed ? if (urbt->ret) continue; if (wsgi_req_recv(urbt->queue, wsgi_req)) { uwsgi_destroy_request(wsgi_req); continue; } uwsgi_close_request(wsgi_req); } return Qnil; }
void *async_loop(void *arg1) { struct uwsgi_async_fd *tmp_uaf; int interesting_fd, i; struct uwsgi_rb_timer *min_timeout; int timeout; int is_a_new_connection; int proto_parser_status; time_t now, last_now = 0; static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL; void *events = event_queue_alloc(64); struct uwsgi_socket *uwsgi_sock; uwsgi.async_runqueue = NULL; uwsgi.async_runqueue_cnt = 0; if (uwsgi.signal_socket > -1) { event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket); event_queue_add_fd_read(uwsgi.async_queue, uwsgi.my_signal_socket); } // set a default request manager if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req; 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 { 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;i<uwsgi.async_nevents;i++) { // manage events interesting_fd = event_queue_interesting_fd(events, i); if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) { uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid); continue; } is_a_new_connection = 0; // new request coming in ? uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (interesting_fd == uwsgi_sock->fd) { is_a_new_connection = 1; uwsgi.wsgi_req = find_first_available_wsgi_req(); if (uwsgi.wsgi_req == NULL) { now = time(NULL); if (now > last_now) { uwsgi_log("async queue is full !!!\n"); last_now = now; } break; } wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock ); if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) { #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(uwsgi.async_queue, interesting_fd); #endif uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; break; } #ifdef UWSGI_EVENT_USE_PORT event_queue_add_fd_read(uwsgi.async_queue, interesting_fd); #endif // on linux we do not need to reset the socket to blocking state #ifndef __linux__ /* re-set blocking socket */ int arg = uwsgi_sock->arg; arg &= (~O_NONBLOCK); if (fcntl(uwsgi.wsgi_req->poll.fd, F_SETFL, arg) < 0) { uwsgi_error("fcntl()"); uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; break; } #endif if (wsgi_req_async_recv(uwsgi.wsgi_req)) { uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; break; } if (uwsgi.wsgi_req->do_not_add_to_async_queue) { runqueue_push(uwsgi.wsgi_req); } break; } uwsgi_sock = uwsgi_sock->next; } if (!is_a_new_connection) { // proto event uwsgi.wsgi_req = find_wsgi_req_proto_by_fd(interesting_fd); if (uwsgi.wsgi_req) { proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req); // reset 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; // parsing complete if (!proto_parser_status) { // remove fd from event poll and fd proto table #ifndef UWSGI_EVENT_USE_PORT event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read()); #endif uwsgi.async_proto_fd_table[interesting_fd] = NULL; // put request in the runqueue runqueue_push(uwsgi.wsgi_req); continue; } else if (proto_parser_status < 0) { if (proto_parser_status == -1) uwsgi_log("error parsing request\n"); uwsgi.async_proto_fd_table[interesting_fd] = NULL; close(interesting_fd); continue; } // re-add timer async_add_timeout(uwsgi.wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); continue; } // 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) { #ifndef UWSGI_EVENT_USE_PORT event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event); #endif 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); } } // 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.schedule_to_req(); uwsgi.wsgi_req->switches++; 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) { #ifndef UWSGI_EVENT_USE_PORT event_queue_del_fd(uwsgi.async_queue, uwsgi.wsgi_req->waiting_fds->fd, uwsgi.wsgi_req->waiting_fds->event); #endif 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; } } return NULL; }
PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) { PyObject *py_wsgi_req = PyTuple_GetItem(args, 0); struct wsgi_request *wsgi_req = (struct wsgi_request *) PyLong_AsLong(py_wsgi_req); PyObject *greenlet_switch = NULL; PyObject *current_greenlet = GET_CURRENT_GREENLET; // another hack to retrieve the current wsgi_req; PyObject_SetAttrString(current_greenlet, "uwsgi_wsgi_req", py_wsgi_req); // if in edge-triggered mode read from socket now !!! if (wsgi_req->socket->edge_trigger) { int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end2; } goto request; } greenlet_switch = PyObject_GetAttrString(current_greenlet, "switch"); for(;;) { int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); wsgi_req->switches++; if (ret <= 0) { goto end; } int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end; } else if (status == 0) { break; } } request: #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { wsgi_req->async_status = uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req); if (wsgi_req->async_status <= UWSGI_OK) { goto end; } wsgi_req->switches++; // switch after each yield GEVENT_SWITCH; } end: Py_DECREF(greenlet_switch); end2: Py_DECREF(current_greenlet); uwsgi_close_request(wsgi_req); free_req_queue; Py_INCREF(Py_None); return Py_None; }
PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) { PyObject *py_wsgi_req = PyTuple_GetItem(args, 0); struct wsgi_request *wsgi_req = (struct wsgi_request *) PyLong_AsLong(py_wsgi_req); PyObject *greenlet_switch = NULL; PyObject *current_greenlet = GET_CURRENT_GREENLET; // another hack to retrieve the current wsgi_req; PyObject_SetAttrString(current_greenlet, "uwsgi_wsgi_req", py_wsgi_req); // if in edge-triggered mode read from socket now !!! if (wsgi_req->socket->edge_trigger) { int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end; } goto request; } greenlet_switch = PyObject_GetAttrString(current_greenlet, "switch"); for(;;) { int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.socket_timeout); wsgi_req->switches++; if (ret <= 0) { goto end; } int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end; } else if (status == 0) { break; } } request: #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) { goto end; } wsgi_req->switches++; // switch after each yield GEVENT_SWITCH; } end: if (greenlet_switch) { Py_DECREF(greenlet_switch); } Py_DECREF(current_greenlet); uwsgi_close_request(wsgi_req); free_req_queue; if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) { int running_cores = 0; int i; for(i=0;i<uwsgi.async;i++) { if (uwsgi.workers[uwsgi.mywid].cores[i].in_request) { running_cores++; } } if (running_cores == 0) { // no need to worry about freeing memory PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi"); if (uwsgi_dict) { PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit"); if (ae) { python_call(ae, PyTuple_New(0), 0, NULL); } } } } else { // If we stopped any watcher due to being out of async workers, restart it. int i = 0; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; for (; uwsgi_sock; uwsgi_sock = uwsgi_sock->next, ++i) { PyObject *py_watcher_active = PyObject_GetAttrString(ugevent.watchers[i], "active"); if (py_watcher_active && PyBool_Check(py_watcher_active) && !PyInt_AsLong(py_watcher_active)) { start_watcher(i, uwsgi_sock); } Py_XDECREF(py_watcher_active); } } Py_INCREF(Py_None); return Py_None; }
PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) { PyObject *ret; PyObject *py_wsgi_req = PyTuple_GetItem(args, 0); struct wsgi_request *wsgi_req = (struct wsgi_request *) PyLong_AsLong(py_wsgi_req); int status ; PyObject *current_greenlet = GET_CURRENT_GREENLET; PyObject *greenlet_switch = PyObject_GetAttrString(current_greenlet, "switch"); uwsgi.wsgi_req = wsgi_req; // create a watcher for request socket PyObject *watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", wsgi_req->poll.fd, 1); if (!watcher) goto clear1; // a timer to implement timeoit (thanks Denis) PyObject *timer = PyObject_CallMethod(ugevent.hub_loop, "timer", "i", uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); if (!timer) goto clear0; for(;;) { // wait for data in the socket PyObject *ret = uwsgi_gevent_wait(watcher, timer, greenlet_switch); if (!ret) goto clear_and_stop; // do not forget to overwrite this pointer each time !!! uwsgi.wsgi_req = wsgi_req; // we can safely decref here as watcher and timer has got a +1 for start() method Py_DECREF(ret); if (ret == timer) { uwsgi_log( "timeout. skip request.\n"); goto clear_and_stop; } else if (ret == watcher) { status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto clear_and_stop; } else if (status == 0) { stop_the_watchers; break; } } else { uwsgi_log("unrecognized gevent event !!!\n"); goto clear_and_stop; } stop_the_watchers; } for(;;) { uwsgi.wsgi_req = wsgi_req; wsgi_req->async_status = uwsgi.p[wsgi_req->uh.modifier1]->request(wsgi_req); if (wsgi_req->async_status <= UWSGI_OK) { goto clear; } // switch after each yield GEVENT_SWITCH; } goto clear; clear_and_stop: stop_the_watchers; clear: Py_DECREF(timer); clear0: Py_DECREF(watcher); clear1: Py_DECREF(greenlet_switch); Py_DECREF(current_greenlet); uwsgi_close_request(wsgi_req); uwsgi.wsgi_req = wsgi_req; free_req_queue; Py_INCREF(Py_None); return Py_None; }
void *zeromq_loop(void *arg1) { sigset_t smask; int i; long core_id = (long) arg1; struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id]; uwsgi.zeromq_recv_flag = 0; zmq_pollitem_t zmq_poll_items[3]; char uwsgi_signal; if (uwsgi.threads > 1) { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i); pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req); if (core_id > 0) { // block all signals on new threads sigfillset(&smask); pthread_sigmask(SIG_BLOCK, &smask, NULL); for (i = 0; i < 0xFF; i++) { if (uwsgi.p[i]->init_thread) { uwsgi.p[i]->init_thread(core_id); } } void *tmp_zmq_pull = zmq_socket(uwsgi.zmq_context, ZMQ_PULL); if (tmp_zmq_pull == NULL) { uwsgi_error("zmq_socket()"); exit(1); } if (zmq_connect(tmp_zmq_pull, uwsgi.zmq_receiver) < 0) { uwsgi_error("zmq_connect()"); exit(1); } pthread_setspecific(uwsgi.zmq_pull, tmp_zmq_pull); } } if (uwsgi.signal_socket > -1) { zmq_poll_items[0].socket = pthread_getspecific(uwsgi.zmq_pull); zmq_poll_items[0].fd = -1; zmq_poll_items[0].events = ZMQ_POLLIN; zmq_poll_items[1].socket = NULL; zmq_poll_items[1].fd = uwsgi.signal_socket; zmq_poll_items[1].events = ZMQ_POLLIN; zmq_poll_items[2].socket = NULL; zmq_poll_items[2].fd = uwsgi.my_signal_socket; zmq_poll_items[2].events = ZMQ_POLLIN; } while (uwsgi.workers[uwsgi.mywid].manage_next_request) { wsgi_req_setup(wsgi_req, core_id, NULL); uwsgi.edge_triggered = 1; wsgi_req->socket = uwsgi.zmq_socket; if (uwsgi.signal_socket > -1) { if (zmq_poll(zmq_poll_items, 3, -1) < 0) { uwsgi_error("zmq_poll()"); continue; } if (zmq_poll_items[1].revents & ZMQ_POLLIN) { if (read(uwsgi.signal_socket, &uwsgi_signal, 1) <= 0) { if (uwsgi.no_orphans) { uwsgi_log_verbose("uWSGI worker %d screams: UAAAAAAH my master died, i will follow him...\n", uwsgi.mywid); end_me(0); } } else { #ifdef UWSGI_DEBUG uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid); #endif if (uwsgi_signal_handler(uwsgi_signal)) { uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid); } } continue; } if (zmq_poll_items[2].revents & ZMQ_POLLIN) { if (read(uwsgi.my_signal_socket, &uwsgi_signal, 1) <= 0) { if (uwsgi.no_orphans) { uwsgi_log_verbose("uWSGI worker %d screams: UAAAAAAH my master died, i will follow him...\n", uwsgi.mywid); end_me(0); } } else { #ifdef UWSGI_DEBUG uwsgi_log_verbose("master sent signal %d to worker %d\n", uwsgi_signal, uwsgi.mywid); #endif if (uwsgi_signal_handler(uwsgi_signal)) { uwsgi_log_verbose("error managing signal %d on worker %d\n", uwsgi_signal, uwsgi.mywid); } } continue; } if (zmq_poll_items[0].revents & ZMQ_POLLIN) { wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd); } } else { wsgi_req->poll.fd = wsgi_req->socket->proto_accept(wsgi_req, uwsgi.zmq_socket->fd); } if (wsgi_req->poll.fd >= 0) { wsgi_req_recv(wsgi_req); } uwsgi_close_request(wsgi_req); } // end of the loop return NULL; }
PyObject *py_uwsgi_gevent_request(PyObject * self, PyObject * args) { PyObject *py_wsgi_req = PyTuple_GetItem(args, 0); struct wsgi_request *wsgi_req = (struct wsgi_request *) PyLong_AsLong(py_wsgi_req); PyObject *greenlet_switch = NULL; PyObject *current_greenlet = GET_CURRENT_GREENLET; // another hack to retrieve the current wsgi_req; PyObject_SetAttrString(current_greenlet, "uwsgi_wsgi_req", py_wsgi_req); // if in edge-triggered mode read from socket now !!! if (wsgi_req->socket->edge_trigger) { int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end2; } goto request; } greenlet_switch = PyObject_GetAttrString(current_greenlet, "switch"); for(;;) { int ret = uwsgi.wait_read_hook(wsgi_req->fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); wsgi_req->switches++; if (ret <= 0) { goto end; } int status = wsgi_req->socket->proto(wsgi_req); if (status < 0) { goto end; } else if (status == 0) { break; } } request: #ifdef UWSGI_ROUTING if (uwsgi_apply_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { goto end; } #endif for(;;) { if (uwsgi.p[wsgi_req->uh->modifier1]->request(wsgi_req) <= UWSGI_OK) { goto end; } wsgi_req->switches++; // switch after each yield GEVENT_SWITCH; } end: Py_DECREF(greenlet_switch); end2: Py_DECREF(current_greenlet); uwsgi_close_request(wsgi_req); free_req_queue; if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) { int running_cores = 0; int i; for(i=0;i<uwsgi.async;i++) { if (uwsgi.workers[uwsgi.mywid].cores[i].in_request) { running_cores++; } } if (running_cores == 0) { // no need to worry about freeing memory PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi"); if (uwsgi_dict) { PyObject *ae = PyDict_GetItemString(uwsgi_dict, "atexit"); if (ae) { python_call(ae, PyTuple_New(0), 0, NULL); } } } } Py_INCREF(Py_None); return Py_None; }
void *simple_loop(void *arg1) { long core_id = (long) arg1; struct wsgi_request *wsgi_req = uwsgi.wsgi_requests[core_id]; #ifdef UWSGI_THREADING int i; sigset_t smask; if (uwsgi.threads > 1) { pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &i); pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &i); pthread_setspecific(uwsgi.tur_key, (void *) wsgi_req); if (core_id > 0) { // block all signals on new threads sigfillset(&smask); #ifdef UWSGI_DEBUG sigdelset(&smask, SIGSEGV); #endif pthread_sigmask(SIG_BLOCK, &smask, NULL); // run per-thread socket hook struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; while(uwsgi_sock) { if (uwsgi_sock->proto_thread_fixup) { uwsgi_sock->proto_thread_fixup(uwsgi_sock, core_id); } uwsgi_sock = uwsgi_sock->next; } for (i = 0; i < 256; i++) { if (uwsgi.p[i]->init_thread) { uwsgi.p[i]->init_thread(core_id); } } } } #endif // initialize the main event queue to monitor sockets int main_queue = event_queue_init(); uwsgi_add_sockets_to_queue(main_queue, core_id); if (uwsgi.signal_socket > -1) { event_queue_add_fd_read(main_queue, uwsgi.signal_socket); event_queue_add_fd_read(main_queue, uwsgi.my_signal_socket); } // ok we are ready, let's start managing requests and signals while (uwsgi.workers[uwsgi.mywid].manage_next_request) { wsgi_req_setup(wsgi_req, core_id, NULL); if (wsgi_req_accept(main_queue, wsgi_req)) { continue; } if (wsgi_req_recv(wsgi_req)) { uwsgi_destroy_request(wsgi_req); continue; } uwsgi_close_request(wsgi_req); } // end of the loop if (uwsgi.workers[uwsgi.mywid].destroy && uwsgi.workers[0].pid > 0) { #ifdef __APPLE__ kill(uwsgi.workers[0].pid, SIGTERM); #else if (uwsgi.propagate_touch) { kill(uwsgi.workers[0].pid, SIGHUP); } else { gracefully_kill(0); } #endif } return NULL; }
void async_loop() { if (uwsgi.async < 2) { uwsgi_log("the async loop engine requires async mode (--async <n>)\n"); exit(1); } struct uwsgi_async_fd *tmp_uaf; int interesting_fd, i; struct uwsgi_rb_timer *min_timeout; int timeout; int is_a_new_connection; int proto_parser_status; uint64_t now; static struct uwsgi_async_request *current_request = NULL, *next_async_request = NULL; void *events = event_queue_alloc(64); struct uwsgi_socket *uwsgi_sock; uwsgi.async_runqueue = NULL; uwsgi.async_runqueue_cnt = 0; uwsgi.wait_write_hook = async_wait_fd_write; uwsgi.wait_read_hook = async_wait_fd_read; if (uwsgi.signal_socket > -1) { event_queue_add_fd_read(uwsgi.async_queue, uwsgi.signal_socket); event_queue_add_fd_read(uwsgi.async_queue, uwsgi.my_signal_socket); } // set a default request manager if (!uwsgi.schedule_to_req) uwsgi.schedule_to_req = async_schedule_to_req; if (!uwsgi.schedule_to_main) { uwsgi_log("*** WARNING *** async mode without coroutine/greenthread engine loaded !!!\n"); } while (uwsgi.workers[uwsgi.mywid].manage_next_request) { now = (uint64_t) uwsgi_now(); if (uwsgi.async_runqueue_cnt) { timeout = 0; } else { min_timeout = uwsgi_min_rb_timer(uwsgi.rb_async_timeouts, NULL); if (min_timeout) { timeout = min_timeout->value - now; if (timeout <= 0) { async_expire_timeouts(now); timeout = 0; } } else { timeout = -1; } } uwsgi.async_nevents = event_queue_wait_multi(uwsgi.async_queue, timeout, events, 64); now = (uint64_t) uwsgi_now(); // timeout ??? if (uwsgi.async_nevents == 0) { async_expire_timeouts(now); } for (i = 0; i < uwsgi.async_nevents; i++) { // manage events interesting_fd = event_queue_interesting_fd(events, i); if (uwsgi.signal_socket > -1 && (interesting_fd == uwsgi.signal_socket || interesting_fd == uwsgi.my_signal_socket)) { uwsgi_receive_signal(interesting_fd, "worker", uwsgi.mywid); continue; } is_a_new_connection = 0; // new request coming in ? uwsgi_sock = uwsgi.sockets; while (uwsgi_sock) { if (interesting_fd == uwsgi_sock->fd) { is_a_new_connection = 1; uwsgi.wsgi_req = find_first_available_wsgi_req(); if (uwsgi.wsgi_req == NULL) { uwsgi_async_queue_is_full((time_t)now); break; } wsgi_req_setup(uwsgi.wsgi_req, uwsgi.wsgi_req->async_id, uwsgi_sock); if (wsgi_req_simple_accept(uwsgi.wsgi_req, interesting_fd)) { uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; break; } if (wsgi_req_async_recv(uwsgi.wsgi_req)) { uwsgi.async_queue_unused_ptr++; uwsgi.async_queue_unused[uwsgi.async_queue_unused_ptr] = uwsgi.wsgi_req; break; } if (uwsgi.wsgi_req->do_not_add_to_async_queue) { runqueue_push(uwsgi.wsgi_req); } break; } uwsgi_sock = uwsgi_sock->next; } if (!is_a_new_connection) { // proto event uwsgi.wsgi_req = find_wsgi_req_proto_by_fd(interesting_fd); if (uwsgi.wsgi_req) { proto_parser_status = uwsgi.wsgi_req->socket->proto(uwsgi.wsgi_req); // reset timeout uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout); free(uwsgi.wsgi_req->async_timeout); uwsgi.wsgi_req->async_timeout = NULL; // parsing complete if (!proto_parser_status) { // remove fd from event poll and fd proto table uwsgi.async_proto_fd_table[interesting_fd] = NULL; event_queue_del_fd(uwsgi.async_queue, interesting_fd, event_queue_read()); // put request in the runqueue runqueue_push(uwsgi.wsgi_req); continue; } else if (proto_parser_status < 0) { if (proto_parser_status == -1) uwsgi_log("error parsing request\n"); uwsgi.async_proto_fd_table[interesting_fd] = NULL; close(interesting_fd); continue; } // re-add timer async_add_timeout(uwsgi.wsgi_req, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); continue; } // 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) { tmp_uaf = uwsgi.wsgi_req->waiting_fds; uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL; event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event); uwsgi.wsgi_req->waiting_fds = tmp_uaf->next; free(tmp_uaf); } uwsgi.wsgi_req->waiting_fds = NULL; if (uwsgi.wsgi_req->async_timeout) { uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout); 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); // avoid managing other enqueued events... break; } } // 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.schedule_to_req(); uwsgi.wsgi_req->switches++; 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) { tmp_uaf = uwsgi.wsgi_req->waiting_fds; uwsgi.async_waiting_fd_table[tmp_uaf->fd] = NULL; event_queue_del_fd(uwsgi.async_queue, tmp_uaf->fd, tmp_uaf->event); uwsgi.wsgi_req->waiting_fds = tmp_uaf->next; free(tmp_uaf); } uwsgi.wsgi_req->waiting_fds = NULL; if (uwsgi.wsgi_req->async_timeout) { uwsgi_del_rb_timer(uwsgi.rb_async_timeouts, uwsgi.wsgi_req->async_timeout); 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; } } }