void pc_channel_desire_write(pc_channel_t *channel) { int events; channel->desire_write = TRUE; events = EV_WRITE; if (channel->desire_read) events |= EV_READ; start_watcher(channel->ctx->cctx->loop, &channel->watcher, events); }
static void channel_is_usable(struct ev_loop *loop, ev_io *watcher, int revents) { pc_channel_t *channel = watcher->data; pc_bool_t dirty = FALSE; /* Note that we double-check the callbacks. We want to ignore spurious signals to read or write, and then we want to try to disable those events (again). */ if ((revents & EV_READ) != 0) { if (channel->desire_read) dirty = perform_read(channel); else dirty = TRUE; } if ((revents & EV_WRITE) != 0) { if (channel->desire_write) dirty |= perform_write(channel); else dirty = TRUE; } /* Do we need to adjust what events we're looking for? */ if (dirty) { int events = 0; if (channel->desire_read) events |= EV_READ; if (channel->desire_write) events |= EV_WRITE; start_watcher(loop, watcher, events); } }
static void gevent_loop() { // ensure SIGPIPE is ignored signal(SIGPIPE, SIG_IGN); if (!uwsgi.has_threads && uwsgi.mywid == 1) { uwsgi_log("!!! Running gevent without threads IS NOT recommended, enable them with --enable-threads !!!\n"); } if (uwsgi.socket_timeout < 30) { uwsgi_log("!!! Running gevent with a socket-timeout lower than 30 seconds is not recommended, tune it with --socket-timeout !!!\n"); } // get the GIL UWSGI_GET_GIL up.gil_get = gil_gevent_get; up.gil_release = gil_gevent_release; uwsgi.wait_write_hook = uwsgi_gevent_wait_write_hook; uwsgi.wait_read_hook = uwsgi_gevent_wait_read_hook; uwsgi.wait_milliseconds_hook = uwsgi_gevent_wait_milliseconds_hook; struct uwsgi_socket *uwsgi_sock = uwsgi.sockets; if (uwsgi.async < 1) { uwsgi_log("the gevent loop engine requires async mode (--async <n>)\n"); exit(1); } uwsgi.current_wsgi_req = uwsgi_gevent_current_wsgi_req; PyObject *gevent_dict = get_uwsgi_pydict("gevent"); if (!gevent_dict) uwsgi_pyexit; PyObject *gevent_version = PyDict_GetItemString(gevent_dict, "version_info"); if (!gevent_version) uwsgi_pyexit; if (PyInt_AsLong(PyTuple_GetItem(gevent_version, 0)) < 1) { uwsgi_log("uWSGI requires at least gevent 1.x version\n"); exit(1); } // call gevent.monkey.patch_all() if requested if (ugevent.monkey) { monkey_patch(); } ugevent.spawn = PyDict_GetItemString(gevent_dict, "spawn"); if (!ugevent.spawn) uwsgi_pyexit; ugevent.signal = PyDict_GetItemString(gevent_dict, "signal"); if (!ugevent.signal) uwsgi_pyexit; ugevent.greenlet_switch = PyDict_GetItemString(gevent_dict, "sleep"); if (!ugevent.greenlet_switch) uwsgi_pyexit; ugevent.greenlet_switch_args = PyTuple_New(0); Py_INCREF(ugevent.greenlet_switch_args); PyObject *gevent_get_hub = PyDict_GetItemString(gevent_dict, "get_hub"); ugevent.hub = python_call(gevent_get_hub, PyTuple_New(0), 0, NULL); if (!ugevent.hub) uwsgi_pyexit; ugevent.get_current = PyDict_GetItemString(gevent_dict, "getcurrent"); if (!ugevent.get_current) uwsgi_pyexit; ugevent.get_current_args = PyTuple_New(0); Py_INCREF(ugevent.get_current_args); ugevent.hub_loop = PyObject_GetAttrString(ugevent.hub, "loop"); if (!ugevent.hub_loop) uwsgi_pyexit; // main greenlet waiting for connection (one greenlet per-socket) uwsgi_gevent_main = PyCFunction_New(uwsgi_gevent_main_def, NULL); Py_INCREF(uwsgi_gevent_main); // greenlet to run at each request PyObject *uwsgi_request_greenlet = PyCFunction_New(uwsgi_gevent_request_def, NULL); Py_INCREF(uwsgi_request_greenlet); // pre-fill the greenlet args ugevent.greenlet_args = PyTuple_New(2); PyTuple_SetItem(ugevent.greenlet_args, 0, uwsgi_request_greenlet); if (uwsgi.signal_socket > -1) { // and these are the watcher for signal sockets ugevent.signal_watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi.signal_socket, 1); if (!ugevent.signal_watcher) uwsgi_pyexit; ugevent.my_signal_watcher = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi.my_signal_socket, 1); if (!ugevent.my_signal_watcher) uwsgi_pyexit; PyObject *uwsgi_greenlet_signal = PyCFunction_New(uwsgi_gevent_signal_def, NULL); Py_INCREF(uwsgi_greenlet_signal); PyObject *uwsgi_greenlet_my_signal = PyCFunction_New(uwsgi_gevent_my_signal_def, NULL); Py_INCREF(uwsgi_greenlet_my_signal); PyObject *uwsgi_greenlet_signal_handler = PyCFunction_New(uwsgi_gevent_signal_handler_def, NULL); Py_INCREF(uwsgi_greenlet_signal_handler); ugevent.signal_args = PyTuple_New(2); PyTuple_SetItem(ugevent.signal_args, 0, uwsgi_greenlet_signal_handler); // start the two signal watchers if (!PyObject_CallMethod(ugevent.signal_watcher, "start", "O", uwsgi_greenlet_signal)) uwsgi_pyexit; if (!PyObject_CallMethod(ugevent.my_signal_watcher, "start", "O", uwsgi_greenlet_my_signal)) uwsgi_pyexit; } // start a greenlet for each socket ugevent.watchers = uwsgi_malloc(sizeof(PyObject *) * uwsgi_count_sockets(uwsgi.sockets)); int i = 0; while(uwsgi_sock) { // this is the watcher for server socket ugevent.watchers[i] = PyObject_CallMethod(ugevent.hub_loop, "io", "ii", uwsgi_sock->fd, 1); if (!ugevent.watchers[i]) uwsgi_pyexit; // start the main greenlet start_watcher(i, uwsgi_sock); uwsgi_sock = uwsgi_sock->next; i++; } // patch goodbye_cruel_world uwsgi.gbcw_hook = uwsgi_gevent_gbcw; // map SIGHUP with gevent.signal PyObject *ge_signal_tuple = PyTuple_New(2); PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGHUP)); PyObject *uwsgi_gevent_unix_signal_handler = PyCFunction_New(uwsgi_gevent_unix_signal_handler_def, NULL); Py_INCREF(uwsgi_gevent_unix_signal_handler); PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_handler); python_call(ugevent.signal, ge_signal_tuple, 0, NULL); // map SIGINT/SIGTERM with gevent.signal ge_signal_tuple = PyTuple_New(2); PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGINT)); PyObject *uwsgi_gevent_unix_signal_int_handler = PyCFunction_New(uwsgi_gevent_unix_signal_int_handler_def, NULL); Py_INCREF(uwsgi_gevent_unix_signal_int_handler); PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_int_handler); python_call(ugevent.signal, ge_signal_tuple, 0, NULL); ge_signal_tuple = PyTuple_New(2); PyTuple_SetItem(ge_signal_tuple, 0, PyInt_FromLong(SIGTERM)); PyTuple_SetItem(ge_signal_tuple, 1, uwsgi_gevent_unix_signal_int_handler); python_call(ugevent.signal, ge_signal_tuple, 0, NULL); PyObject *wait_for_me = ugevent.hub; if (!ugevent.wait_for_hub) { // spawn the control greenlet PyObject *uwsgi_greenlet_ctrl_gl_handler = PyCFunction_New(uwsgi_gevent_ctrl_gl_def, NULL); Py_INCREF(uwsgi_greenlet_ctrl_gl_handler); PyObject *ctrl_gl_args = PyTuple_New(1); PyTuple_SetItem(ctrl_gl_args, 0, uwsgi_greenlet_ctrl_gl_handler); ugevent.ctrl_gl = python_call(ugevent.spawn, ctrl_gl_args, 0, NULL); Py_INCREF(ugevent.ctrl_gl); wait_for_me = ugevent.ctrl_gl; } for(;;) { if (!PyObject_CallMethod(wait_for_me, "join", NULL)) { PyErr_Print(); } else { break; } } // 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); } } if (uwsgi.workers[uwsgi.mywid].manage_next_request == 0) { uwsgi_log("goodbye to the gevent Hub on worker %d (pid: %d)\n", uwsgi.mywid, uwsgi.mypid); if (ugevent.destroy) { exit(0); } exit(UWSGI_RELOAD_CODE); } uwsgi_log("the gevent Hub is no more :(\n"); }
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; }
int main(int argc, char **argv) { int i; int fanotify_fd, ret; struct backend *be = NULL; struct stat stbuf; logfd = stdout; memset(frontend_prefix, 0x0, FILENAME_MAX); while ((i = getopt(argc, argv, "b:c:d:m:n:o:p:su:")) != -1) { switch (i) { case 'b': be = new_backend(optarg); if (!be) { err("Invalid backend '%s'\n", optarg); return EINVAL; } break; case 'd': if (stat(optarg, &stbuf) < 0 || !S_ISDIR(stbuf.st_mode)) { err("Frontend prefix %s is not a directory", optarg); return EINVAL; } strncpy(frontend_prefix, optarg, FILENAME_MAX); break; case 'c': return cli_command(CLI_CHECK, optarg); break; case 'm': ret = cli_command(CLI_CHECK, optarg); if (ret) return ret; ret = cli_command(CLI_MIGRATE, optarg); if (ret) return ret; /* Fallthrough */ case 'n': return cli_command(CLI_MONITOR, optarg); break; case 'o': if (!be) { err("No backend selected"); return EINVAL; } if (parse_backend_options(be, optarg) < 0) { err("Invalid backend option '%s'", optarg); return EINVAL; } break; case 'p': log_priority = strtoul(optarg, NULL, 10); if (log_priority > LOG_DEBUG) { err("Invalid logging priority %d (max %d)", log_priority, LOG_DEBUG); exit(1); } break; case 's': return cli_command(CLI_SHUTDOWN, NULL); break; case 'u': ret = cli_command(CLI_CHECK, optarg); if (ret && ret != ENOENT) return ret; ret = cli_command(CLI_SETUP, optarg); if (ret) return ret; return cli_command(CLI_MONITOR, optarg); break; default: fprintf(stderr, "usage: %s [-d <dir>]\n", argv[0]); return EINVAL; } } if (optind < argc) { fprintf(stderr, "usage: %s [-b file] [-p <dir>]\n", argv[0]); return EINVAL; } signal_set(SIGINT, sigend); signal_set(SIGTERM, sigend); fanotify_fd = fanotify_init(FAN_CLASS_PRE_CONTENT, O_RDWR); if (fanotify_fd < 0) { fprintf(stderr, "cannot start fanotify, error %d\n", errno); return errno; } daemon_thr = pthread_self(); watcher_thr = start_watcher(be, fanotify_fd); if (!watcher_thr) return errno; cli_thr = start_cli(be, fanotify_fd); if (!cli_thr) { stop_watcher(watcher_thr); return ENOMEM; } pthread_cond_wait(&exit_cond, &exit_mutex); stop_cli(cli_thr); stop_watcher(watcher_thr); return 0; }