diff --git a/hello_world_rrdtool.py b/hello_world_rrdtool.py index 9fa8b702..4b0caa2a 100644 --- a/hello_world_rrdtool.py +++ b/hello_world_rrdtool.py @@ -6,20 +6,18 @@ import rrdtool s_freq = 10 -# this is a cron emulator done with the Spooler :) -def rrdtool_updater(env): - uwsgi.set_spooler_frequency(s_freq) - rrdtool.update('../test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests())) - uwsgi.send_to_spooler({}) +# this task will be executed every s_freq seconds +def rrdtool_updater(sig, sec): + rrdtool.update('test.rrd', str(int(time.time()))+':'+str(uwsgi.total_requests())) -uwsgi.spooler = rrdtool_updater +uwsgi.register_timer(0, s_freq, uwsgi.KIND_WORKER, rrdtool_updater) def hello_world(env, start_response): start_response('200 Ok', [('Content-type', 'text/plain')]) - yield 'Hello world !' + return 'Hello world !' def graph(env, start_response): @@ -27,12 +25,7 @@ def graph(env, start_response): now = int(time.time()) graph_range = (3600*24) rrdtool.graph('uwsgi_graph.png', '--start', str(now - graph_range), '--end', str(now), 'DEF:urequests=test.rrd:requests:AVERAGE', 'LINE2:urequests#00FF00') - fd = open('uwsgi_graph.png', 'r') - # send file to browser - return env['wsgi.file_wrapper'](fd, 4096) - -# start the simil-cron -uwsgi.send_to_spooler({}) - + # send file to client + uwsgi.sendfile('uwsgi_graph.png') uwsgi.applications = {'/': hello_world, '/graph':graph} diff --git a/plugins/python/pyloader.c b/plugins/python/pyloader.c index e105ff9c..c199f654 100644 --- a/plugins/python/pyloader.c +++ b/plugins/python/pyloader.c @@ -18,11 +18,13 @@ PyMethodDef uwsgi_eventfd_read_method[] = { {"uwsgi_eventfd_read", py_eventfd_re PyMethodDef uwsgi_eventfd_write_method[] = { {"uwsgi_eventfd_write", py_eventfd_write, METH_VARARGS, ""}}; #endif -int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int new_interpreter) { +int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, PyThreadState *interpreter) { PyObject *zero; + PyObject *app_list = NULL, *applications = NULL; int id = uwsgi.apps_cnt; + int multiapp = 0; #ifdef UWSGI_ASYNC int i; @@ -35,11 +37,11 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne if (wsgi_req->script_name_len == 0) { wsgi_req->script_name = ""; - if (!uwsgi.vhost) id = 0; } else if (wsgi_req->script_name_len == 1) { if (wsgi_req->script_name[0] == '/') { - if (!uwsgi.vhost) id = 0; + wsgi_req->script_name = ""; + wsgi_req->script_name_len = 0; } } @@ -77,7 +79,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne // Initialize a new environment for the new interpreter - if (new_interpreter && id) { + if (interpreter == NULL && id) { wi->interpreter = Py_NewInterpreter(); if (!wi->interpreter) { uwsgi_log( "unable to initialize the new python interpreter\n"); @@ -93,6 +95,9 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne init_uwsgi_vars(); } + else if (interpreter) { + wi->interpreter = interpreter; + } else { wi->interpreter = up.main_thread; } @@ -105,6 +110,32 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne goto doh; } + + + // the module contains multiple apps + if (PyDict_Check(wi->callable)) { + applications = wi->callable; + uwsgi_log("found a multiapp module...\n"); + app_list = PyDict_Keys(applications); + multiapp = PyList_Size(app_list); + if (multiapp < 1) { + uwsgi_log("you have to define at least one app in the apllications dictionary\n"); + goto doh; + } + + PyObject *app_mnt = PyList_GetItem(app_list, 0); + if (!PyString_Check(app_mnt)) { + uwsgi_log("the app mountpoint must be a string\n"); + goto doh; + } + wi->mountpoint = PyString_AsString(app_mnt); + wi->mountpoint_len = strlen(wi->mountpoint); + wsgi_req->script_name = wi->mountpoint; + wsgi_req->script_name_len = wi->mountpoint_len; + uwsgi_log("main mountpoint = %s\n", wi->mountpoint); + wi->callable = PyDict_GetItem(applications, app_mnt); + } + #ifdef UWSGI_ASYNC wi->environ = malloc(sizeof(PyObject*)*uwsgi.cores); if (!wi->environ) { @@ -216,7 +247,7 @@ int init_uwsgi_app(int loader, void *arg1, struct wsgi_request *wsgi_req, int ne #endif } - if (new_interpreter && id) { + if (interpreter == NULL && id) { // if we have multiple threads we need to initialize a PyThreadState for each one if (uwsgi.threads > 1) { for(i=0;imountpoint_len, wi->mountpoint, wi->interpreter); } - if (id == 0) { + if (!wsgi_req->script_name_len) { uwsgi_log(" (default app)"); - uwsgi.default_app = 0; - if (uwsgi.vhost) uwsgi.apps_cnt++; - } - else { - uwsgi.apps_cnt++; + uwsgi.default_app = id; } + uwsgi.apps_cnt++; + uwsgi_log("\n"); + if (multiapp > 1) { + for(i=1;iscript_name = PyString_AsString(app_mnt); + wsgi_req->script_name_len = strlen(wsgi_req->script_name); + init_uwsgi_app(LOADER_CALLABLE, PyDict_GetItem(applications, app_mnt), wsgi_req, wi->interpreter); + } + } + return id; doh: free(mountpoint); PyErr_Print(); - if (new_interpreter && id) { + if (interpreter == NULL && id) { Py_EndInterpreter(wi->interpreter); if (uwsgi.threads > 1) { PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key)); @@ -308,6 +351,8 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) { char *quick_callable; PyObject *tmp_callable; + PyObject *applications; + PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi"); char *module = (char *) arg1; @@ -330,6 +375,12 @@ PyObject *uwsgi_uwsgi_loader(void *arg1) { return NULL; } + applications = PyDict_GetItemString(uwsgi_dict, "applications"); + if (applications) return applications; + + applications = PyDict_GetItemString(wsgi_dict, "applications"); + if (applications) return applications; + // quick callable -> thanks gunicorn for the idea // we have extended the concept a bit... if (quick_callable[strlen(quick_callable) -2 ] == '(' && quick_callable[strlen(quick_callable) -1] ==')') { diff --git a/plugins/python/python_plugin.c b/plugins/python/python_plugin.c index db7ca886..fa24a3eb 100644 --- a/plugins/python/python_plugin.c +++ b/plugins/python/python_plugin.c @@ -91,6 +91,7 @@ int uwsgi_python_init() { up.main_thread = PyThreadState_Get(); + uwsgi_log("Python main interpreter initialized at %p\n", up.main_thread); #ifdef UWSGI_MINTERPRETERS init_uwsgi_embedded_module(); @@ -337,125 +338,6 @@ void init_uwsgi_vars() { } -void uwsgi_uwsgi_config(char *module) { - -#ifdef UWSGI_EMBEDDED - PyObject *uwsgi_module, *uwsgi_dict; -#endif - PyObject *applications; - PyObject *app_list; - Py_ssize_t i; - PyObject *app_mnt, *app_app = NULL; - char *quick_callable; - - quick_callable = get_uwsgi_pymodule(module); - if (quick_callable == NULL) { - if (up.callable) { - quick_callable = up.callable; - } - else { - quick_callable = "application"; - } - } - - up.loader_dict = get_uwsgi_pydict(module); - if (!up.loader_dict) { - exit(1); - } - - uwsgi_log( "...getting the applications list from the '%s' module...\n", module); - -#ifdef UWSGI_EMBEDDED - uwsgi_module = PyImport_ImportModule("uwsgi"); - if (!uwsgi_module) { - PyErr_Print(); - exit(1); - } - - uwsgi_dict = PyModule_GetDict(uwsgi_module); - if (!uwsgi_dict) { - PyErr_Print(); - exit(1); - } - - applications = PyDict_GetItemString(uwsgi_dict, "applications"); - if (!PyDict_Check(applications)) { - uwsgi_log( "uwsgi.applications dictionary is not defined, trying with the \"applications\" one...\n"); -#endif - applications = PyDict_GetItemString(up.loader_dict, "applications"); - if (!applications) { - uwsgi_log( "applications dictionary is not defined, trying with the \"application\" callable.\n"); - quick_callable = uwsgi_concat3(module, ":", quick_callable); - if (init_uwsgi_app(LOADER_UWSGI, (void *) quick_callable, uwsgi.wsgi_req, 0) < 0) { - uwsgi_log( "...goodbye cruel world...\n"); - exit(1); - } - free(quick_callable); - return; - } -#ifdef UWSGI_EMBEDDED - } -#endif - - if (!PyDict_Check(applications)) { - uwsgi_log( "The 'applications' object must be a dictionary.\n"); - exit(1); - } - - app_list = PyDict_Keys(applications); - if (!app_list) { - PyErr_Print(); - exit(1); - } - if (PyList_Size(app_list) < 1) { - uwsgi_log( "You must define an app.\n"); - exit(1); - } - - for (i = 0; i < PyList_Size(app_list); i++) { - app_mnt = PyList_GetItem(app_list, i); - - if (!PyString_Check(app_mnt)) { - uwsgi_log( "the app mountpoint must be a bytestring.\n"); - exit(1); - } - - - uwsgi.wsgi_req->script_name = PyString_AsString(app_mnt); - uwsgi.wsgi_req->script_name_len = strlen(uwsgi.wsgi_req->script_name); - - app_app = PyDict_GetItem(applications, app_mnt); - - if (!PyString_Check(app_app) && !PyFunction_Check(app_app) && !PyCallable_Check(app_app)) { - uwsgi_log( "the app callable must be a string, a function or a callable. (found %s)\n", app_app->ob_type->tp_name); - exit(1); - } - -#ifdef PYTHREE - if (PyUnicode_Check(app_app)) { -#else - if (PyString_Check(app_app)) { -#endif - if (init_uwsgi_app(LOADER_STRING_CALLABLE, (void *) PyString_AsString(app_app), uwsgi.wsgi_req, 0) < 0) { - uwsgi_log( "...goodbye cruel world...\n"); - exit(1); - } - - - } - else { - if (init_uwsgi_app(LOADER_CALLABLE, (void *) app_app, uwsgi.wsgi_req, 0) < 0) { - uwsgi_log( "...goodbye cruel world...\n"); - exit(1); - } - } - - Py_DECREF(app_mnt); - Py_DECREF(app_app); - } - - } - #ifdef PYTHREE static PyModuleDef uwsgi_module3 = { @@ -755,26 +637,29 @@ int uwsgi_python_mount_app(char *mountpoint, char *app) { uwsgi.wsgi_req->script_name = mountpoint; uwsgi.wsgi_req->script_name_len = strlen(mountpoint); - return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, uwsgi.single_interpreter-1); + if (uwsgi.single_interpreter) { + return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, up.main_thread); + } + return init_uwsgi_app(LOADER_MOUNT, app, uwsgi.wsgi_req, NULL); } void uwsgi_python_init_apps() { if (up.wsgi_config != NULL) { - init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, 0); + init_uwsgi_app(LOADER_UWSGI, up.wsgi_config, uwsgi.wsgi_req, up.main_thread); } if (up.file_config != NULL) { - init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, 0); + init_uwsgi_app(LOADER_FILE, up.file_config, uwsgi.wsgi_req, up.main_thread); } #ifdef UWSGI_PASTE if (up.paste != NULL) { - init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, 0); + init_uwsgi_app(LOADER_PASTE, up.paste, uwsgi.wsgi_req, up.main_thread); } #endif if (up.eval != NULL) { - init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, 0); + init_uwsgi_app(LOADER_EVAL, up.eval, uwsgi.wsgi_req, up.main_thread); } } @@ -806,17 +691,23 @@ int uwsgi_python_mount_app(char *mountpoint, char *app) { int uwsgi_python_xml(char *node, char *content) { + PyThreadState *interpreter = NULL; + + if (uwsgi.single_interpreter) { + interpreter = up.main_thread; + } + if (!strcmp("script", node)) { - return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1); + return init_uwsgi_app(LOADER_UWSGI, content, uwsgi.wsgi_req, interpreter); } else if (!strcmp("file", node)) { - return init_uwsgi_app(LOADER_FILE, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1); + return init_uwsgi_app(LOADER_FILE, content, uwsgi.wsgi_req, interpreter); } else if (!strcmp("eval", node)) { - return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1); + return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter); } else if (!strcmp("wsgi", node)) { - return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, uwsgi.single_interpreter-1); + return init_uwsgi_app(LOADER_EVAL, content, uwsgi.wsgi_req, interpreter); } else if (!strcmp("module", node)) { uwsgi.wsgi_req->module = content; @@ -827,7 +718,7 @@ int uwsgi_python_xml(char *node, char *content) { uwsgi.wsgi_req->callable++; uwsgi.wsgi_req->callable_len = strlen(uwsgi.wsgi_req->callable); uwsgi.wsgi_req->module_len = strlen(uwsgi.wsgi_req->module); - return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, uwsgi.single_interpreter-1); + return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter); } return 1; } @@ -839,7 +730,7 @@ int uwsgi_python_xml(char *node, char *content) { else if (!strcmp("callable", node)) { uwsgi.wsgi_req->callable = content; uwsgi.wsgi_req->callable_len = strlen(content); - return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, uwsgi.single_interpreter-1); + return init_uwsgi_app(LOADER_DYN, uwsgi.wsgi_req, uwsgi.wsgi_req, interpreter); } return 0; diff --git a/plugins/python/uwsgi_python.h b/plugins/python/uwsgi_python.h index 5ac8e47b..3d03799e 100644 --- a/plugins/python/uwsgi_python.h +++ b/plugins/python/uwsgi_python.h @@ -137,7 +137,7 @@ void uwsgi_paste_config(char *); void uwsgi_file_config(char *); void uwsgi_eval_config(char *); -int init_uwsgi_app(int, void *, struct wsgi_request *wsgi_req, int); +int init_uwsgi_app(int, void *, struct wsgi_request *wsgi_req, PyThreadState *); PyObject *py_eventfd_read(PyObject *, PyObject *); diff --git a/plugins/python/wsgi_handlers.c b/plugins/python/wsgi_handlers.c index b63971bc..a20570ba 100644 --- a/plugins/python/wsgi_handlers.c +++ b/plugins/python/wsgi_handlers.c @@ -153,7 +153,12 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) { pthread_mutex_lock(&up.lock_pyloaders); } UWSGI_GET_GIL - wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, uwsgi.single_interpreter-1); + if (uwsgi.single_interpreter) { + wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, up.main_thread); + } + else { + wsgi_req->app_id = init_uwsgi_app(LOADER_DYN, (void *) wsgi_req, wsgi_req, NULL); + } UWSGI_RELEASE_GIL if (uwsgi.threads > 1) { pthread_mutex_unlock(&up.lock_pyloaders); @@ -186,7 +191,7 @@ int uwsgi_request_wsgi(struct wsgi_request *wsgi_req) { wi = &uwsgi.apps[wsgi_req->app_id]; - if (uwsgi.single_interpreter == 0 && wsgi_req->app_id > 0) { + if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) { if (!wi->interpreter) { internal_server_error(wsgi_req->poll.fd, "wsgi application's %d interpreter not found"); goto clear2; @@ -339,7 +344,7 @@ clear: UWSGI_GET_GIL - if (uwsgi.single_interpreter == 0 && wsgi_req->app_id > 0) { + if (uwsgi.single_interpreter == 0 && wi->interpreter != up.main_thread) { // restoring main interpreter if (uwsgi.threads > 1) { PyThreadState_Swap((PyThreadState *) pthread_getspecific(up.upt_save_key)); diff --git a/protocol.c b/protocol.c index 6acf46f7..a90b74c9 100644 --- a/protocol.c +++ b/protocol.c @@ -525,7 +525,7 @@ int uwsgi_parse_vars(struct wsgi_request *wsgi_req) { wsgi_req->var_cnt++; script_name = wsgi_req->var_cnt; } - for(i=1;i= uwsgi.apps[i].mountpoint_len) { if (!uwsgi_startswith(orig_path_info, uwsgi.apps[i].mountpoint, uwsgi.apps[i].mountpoint_len) && uwsgi.apps[i].mountpoint_len > best_found) { diff --git a/utils.c b/utils.c index 99d93335..e18931f1 100644 --- a/utils.c +++ b/utils.c @@ -907,6 +907,7 @@ int uwsgi_get_app_id(char *script_name, int script_name_len, int modifier1) { int i; for(i=0;i