~ubuntu-branches/ubuntu/saucy/uwsgi/saucy

« back to all changes in this revision

Viewing changes to plugins/python/python_plugin.c

  • Committer: Package Import Robot
  • Author(s): Janos Guljas
  • Date: 2012-04-30 17:35:22 UTC
  • mfrom: (1.1.7)
  • Revision ID: package-import@ubuntu.com-20120430173522-qucwu1au3s9bflhb
Tags: 1.2+dfsg-1
New upstream release.

Show diffs side-by-side

added added

removed removed

Lines of Context:
119
119
        {"py", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0},
120
120
        {"pyrun", required_argument, 0, "run a python script in the uWSGI environment", uwsgi_opt_pyrun, NULL, 0},
121
121
 
 
122
#ifdef UWSGI_THREADING
 
123
        {"py-auto-reload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
 
124
        {"py-autoreload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
 
125
        {"python-auto-reload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
 
126
        {"python-autoreload", required_argument, 0, "monitor python modules mtime to trigger reload (use only in development)", uwsgi_opt_set_int, &up.auto_reload, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
 
127
        {"py-auto-reload-ignore", required_argument, 0, "ignore the specified module during auto-reload scan (can be specified multiple times)", uwsgi_opt_add_string_list, &up.auto_reload_ignore, UWSGI_OPT_THREADS|UWSGI_OPT_MASTER},
 
128
#endif
 
129
 
122
130
        {0, 0, 0, 0, 0, 0, 0},
123
131
};
124
132
 
142
150
 
143
151
#ifndef UWSGI_PYPY
144
152
        char *pyversion = strchr(Py_GetVersion(), '\n');
145
 
        uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
 
153
        if (!pyversion) {
 
154
                uwsgi_log_initial("Python version: %s\n", Py_GetVersion());
 
155
        }
 
156
        else {
 
157
                uwsgi_log_initial("Python version: %.*s %s\n", pyversion-Py_GetVersion(), Py_GetVersion(), Py_GetCompiler()+1);
 
158
        }
146
159
#else
147
160
        uwsgi_log_initial("PyPy version: %s\n", PYPY_VERSION);
148
161
#endif
149
162
 
150
 
#ifndef UWSGI_PYPY
151
163
        if (up.home != NULL) {
152
164
#ifdef PYTHREE
153
165
                wchar_t *wpyhome;
166
178
                uwsgi_log("Set PythonHome to %s\n", up.home);
167
179
        }
168
180
 
 
181
 
169
182
#ifdef PYTHREE
170
183
        wchar_t pname[6];
171
184
        mbstowcs(pname, "uWSGI", 6);
172
185
        Py_SetProgramName(pname);
173
186
#else
174
 
 
175
187
        Py_SetProgramName("uWSGI");
176
188
#endif
177
189
 
178
190
 
 
191
#ifndef UWSGI_PYPY
179
192
        Py_OptimizeFlag = up.optimize;
 
193
#endif
180
194
 
181
195
        Py_Initialize();
182
196
 
183
 
 
184
 
#endif
 
197
        if (!uwsgi.has_threads) {
 
198
                uwsgi_log("*** Python threads support is disabled. You can enable it with --enable-threads ***\n");
 
199
        }
185
200
 
186
201
        up.wsgi_spitout = PyCFunction_New(uwsgi_spit_method, NULL);
187
202
        up.wsgi_writeout = PyCFunction_New(uwsgi_write_method, NULL);
204
219
 
205
220
void uwsgi_python_reset_random_seed() {
206
221
 
207
 
#ifndef UWSGI_PYPY
208
222
        PyObject *random_module, *random_dict, *random_seed;
209
223
 
210
224
        // reinitialize the random seed (thanks Jonas Borgström)
215
229
                        random_seed = PyDict_GetItemString(random_dict, "seed");
216
230
                        if (random_seed) {
217
231
                                PyObject *random_args = PyTuple_New(1);
 
232
#ifdef UWSGI_PYPY
 
233
                                Py_INCREF(Py_None);
 
234
#endif
218
235
                                // pass no args
219
236
                                PyTuple_SetItem(random_args, 0, Py_None);
220
237
                                PyEval_CallObject(random_seed, random_args);
224
241
                        }
225
242
                }
226
243
        }
227
 
#endif
228
244
}
229
245
 
230
246
 
268
284
        PyObject *module = PyImport_ImportModule("atexit");
269
285
        Py_XDECREF(module);
270
286
 
271
 
        if (uwsgi.threads > 1) {
 
287
        if (uwsgi.has_threads) {
272
288
                if (!PyImport_AddModule("dummy_threading"))
273
289
                        PyErr_Clear();
274
290
        }
286
302
 
287
303
        uwsgi_python_reset_random_seed();
288
304
 
289
 
#ifndef UWSGI_PYPY
290
305
#ifdef UWSGI_EMBEDDED
291
306
        // call the post_fork_hook
292
307
        PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
298
313
        }
299
314
        PyErr_Clear();
300
315
#endif
 
316
 
 
317
        if (uwsgi.mywid > 0) {
 
318
#ifdef UWSGI_THREADING
 
319
                if (up.auto_reload) {
 
320
                        // spawn the reloader thread
 
321
                        pthread_t par_tid;
 
322
                        pthread_create(&par_tid, NULL, uwsgi_python_autoreloader_thread, NULL);
 
323
                }
301
324
#endif
 
325
        }
302
326
 
303
327
UWSGI_RELEASE_GIL
304
328
 
306
330
 
307
331
PyObject *uwsgi_pyimport_by_filename(char *name, char *filename) {
308
332
 
309
 
#ifndef UWSGI_PYPY
 
333
#ifdef UWSGI_PYPY
 
334
        uwsgi_log("import by filename is currently not supported on PyPy !!!\n");
 
335
        return NULL;
 
336
#else
310
337
        FILE *pyfile;
311
338
        struct _node *py_file_node = NULL;
312
339
        PyObject *py_compiled_node, *py_file_module;
374
401
                return NULL;
375
402
        }
376
403
 
 
404
        if (is_a_package) {
 
405
                py_file_module = PyImport_AddModule(name);
 
406
                if (py_file_module) {
 
407
                        PyModule_AddObject(py_file_module, "__path__", Py_BuildValue("[O]", PyString_FromString(filename)));
 
408
                }
 
409
                free(real_filename);
 
410
        }
 
411
 
377
412
        py_file_module = PyImport_ExecCodeModule(name, py_compiled_node);
378
413
        if (!py_file_module) {
379
414
                PyErr_Print();
382
417
 
383
418
        Py_DECREF(py_compiled_node);
384
419
 
385
 
        if (is_a_package) {
386
 
                PyObject *py_file_module_dict = PyModule_GetDict(py_file_module);
387
 
                if (py_file_module_dict) {
388
 
                        PyDict_SetItemString(py_file_module_dict, "__path__", Py_BuildValue("[O]", PyString_FromString(filename)));
389
 
                }
390
 
                free(real_filename);
391
 
        }
392
 
 
393
420
        return py_file_module;
394
 
#else
395
 
        return NULL;
396
421
#endif
397
422
 
398
423
}
448
473
                char *value = strchr(uppma->value, '=');
449
474
                if (!value) {
450
475
                        uwsgi_log("invalid pymodule-alias syntax\n");
451
 
                        continue;
 
476
                        goto next;
452
477
                }
453
478
                value[0] = 0;
454
479
                if (!strchr(value + 1, '/')) {
473
498
                // reset original value
474
499
                value[0] = '=';
475
500
 
 
501
next:
476
502
                uppma = uppma->next;
477
503
        }
478
504
 
536
562
        // just for safety
537
563
        Py_INCREF(up.embedded_dict);
538
564
 
 
565
 
539
566
        if (PyDict_SetItemString(up.embedded_dict, "version", PyString_FromString(UWSGI_VERSION))) {
540
567
                PyErr_Print();
541
568
                exit(1);
913
940
 
914
941
        init_pyargv();
915
942
 
916
 
#ifndef UWSGI_PYPY
917
943
#ifdef UWSGI_EMBEDDED
918
944
        init_uwsgi_embedded_module();
919
945
#endif
920
 
#endif
921
946
 
922
947
#ifdef __linux__
923
 
#ifndef UWSGI_PYPY
924
948
#ifdef UWSGI_EMBEDDED
925
949
        uwsgi_init_symbol_import();
926
950
#endif
927
951
#endif
928
 
#endif
929
952
 
930
953
        if (up.test_module != NULL) {
931
954
                if (PyImport_ImportModule(up.test_module)) {
956
979
 
957
980
        struct http_status_codes *http_sc;
958
981
 
 
982
#ifndef UWSGI_PYPY
959
983
        // prepare for stack suspend/resume
960
984
        if (uwsgi.async > 1) {
961
985
                up.current_recursion_depth = uwsgi_malloc(sizeof(int)*uwsgi.async);
962
 
#ifndef UWSGI_PYPY
963
986
                up.current_frame = uwsgi_malloc(sizeof(struct _frame)*uwsgi.async);
 
987
        }
964
988
#endif
965
 
        }
966
989
 
967
990
        // setup app loaders
968
991
#ifdef UWSGI_MINTERPRETERS
998
1021
                char *value = strchr(uppa->value, '=');
999
1022
                if (!value) {
1000
1023
                        uwsgi_log("invalid pymodule-alias syntax\n");
1001
 
                        continue;
 
1024
                        goto next;
1002
1025
                }
1003
1026
                value[0] = 0;
1004
1027
                if (!strchr(value + 1, '/')) {
1023
1046
                // reset original value
1024
1047
                value[0] = '=';
1025
1048
 
 
1049
next:
1026
1050
                uppa = uppa->next;
1027
1051
        }
1028
1052
 
1054
1078
                init_uwsgi_app(LOADER_UWSGI, up.wsgi_lite, uwsgi.wsgi_req, up.main_thread, PYTHON_APP_TYPE_WSGI_LITE);
1055
1079
        }
1056
1080
 
 
1081
#ifndef UWSGI_PYPY
1057
1082
        if (uwsgi.profiler) {
1058
 
#ifndef UWSGI_PYPY
1059
1083
                if (!strcmp(uwsgi.profiler, "pycall")) {
1060
1084
                        PyEval_SetProfile(uwsgi_python_profiler_call, NULL);
1061
1085
                }
 
1086
                else if (!strcmp(uwsgi.profiler, "pyline")) {
 
1087
                        PyEval_SetTrace(uwsgi_python_tracer, NULL);
 
1088
                }
 
1089
        }
1062
1090
#endif
1063
 
        }
1064
1091
 
1065
1092
        PyObject *uwsgi_dict = get_uwsgi_pydict("uwsgi");
1066
1093
        if (uwsgi_dict) {
1168
1195
 
1169
1196
}
1170
1197
 
 
1198
#ifdef UWSGI_THREADING
 
1199
int uwsgi_check_python_mtime(PyObject *times_dict, char *filename) {
 
1200
        struct stat st;
 
1201
 
 
1202
        PyObject *py_mtime = PyDict_GetItemString(times_dict, filename); 
 
1203
        if (!py_mtime) {
 
1204
                if (stat(filename, &st)) {
 
1205
                        return 0;
 
1206
                }
 
1207
                PyDict_SetItemString(times_dict, filename, PyLong_FromLong(st.st_mtime));
 
1208
        }
 
1209
        // the record is already tracked;
 
1210
        else {
 
1211
                long mtime = PyLong_AsLong(py_mtime);
 
1212
 
 
1213
                if (stat(filename, &st)) {
 
1214
                        return 0;
 
1215
                }
 
1216
 
 
1217
                if ((long) st.st_mtime != mtime) {
 
1218
                        uwsgi_log("[uwsgi-python-reloader] module/file %s has been modified\n", filename);
 
1219
                        kill(uwsgi.workers[0].pid, SIGHUP);
 
1220
                        return 1;
 
1221
                }
 
1222
        }
 
1223
        return 0;
 
1224
}
 
1225
void *uwsgi_python_autoreloader_thread(void *foobar) {
 
1226
 
 
1227
        PyObject *modules;
 
1228
 
 
1229
        // block signals on this thread
 
1230
        sigset_t smask;
 
1231
        sigfillset(&smask);
 
1232
#ifndef UWSGI_DEBUG
 
1233
        sigdelset(&smask, SIGSEGV);
 
1234
#endif
 
1235
        pthread_sigmask(SIG_BLOCK, &smask, NULL);
 
1236
 
 
1237
        PyThreadState *pts = PyThreadState_New(up.main_thread->interp);
 
1238
        pthread_setspecific(up.upt_save_key, (void *) pts);
 
1239
        pthread_setspecific(up.upt_gil_key, (void *) pts);
 
1240
        UWSGI_GET_GIL;
 
1241
        PyObject *threading_module = PyImport_ImportModule("threading");
 
1242
        if (threading_module) {
 
1243
                PyObject *threading_module_dict = PyModule_GetDict(threading_module);
 
1244
                if (threading_module_dict) {
 
1245
#ifdef PYTHREE
 
1246
                        PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "current_thread");
 
1247
#else
 
1248
                        PyObject *threading_current = PyDict_GetItemString(threading_module_dict, "currentThread");
 
1249
#endif
 
1250
                        if (threading_current) {
 
1251
                                PyObject *current_thread = PyEval_CallObject(threading_current, (PyObject *)NULL);
 
1252
                                if (!current_thread) {
 
1253
                                        // ignore the error
 
1254
                                        PyErr_Clear();
 
1255
                                }
 
1256
                                else {
 
1257
                                        PyObject_SetAttrString(current_thread, "name", PyString_FromString("uWSGIAutoReloader"));
 
1258
                                        Py_INCREF(current_thread);
 
1259
                                        modules = PyImport_GetModuleDict();
 
1260
                                        goto cycle;
 
1261
                                }
 
1262
                        }
 
1263
                }
 
1264
 
 
1265
        }
 
1266
        return NULL;
 
1267
cycle:
 
1268
        if (uwsgi.mywid == 1) {
 
1269
                uwsgi_log("Python auto-reloader enabled\n");
 
1270
        }
 
1271
        PyObject *times_dict = PyDict_New();
 
1272
        char *filename;
 
1273
        for(;;) {
 
1274
                UWSGI_RELEASE_GIL;
 
1275
                sleep(up.auto_reload);
 
1276
                UWSGI_GET_GIL;
 
1277
                // do not start monitoring til the first app is loaded (required for lazy mode)
 
1278
                if (uwsgi_apps_cnt == 0) continue;
 
1279
#ifdef UWSGI_PYTHON_OLD
 
1280
                int pos = 0;
 
1281
#else
 
1282
                Py_ssize_t pos = 0;
 
1283
#endif
 
1284
                PyObject *mod_name, *mod;
 
1285
                while (PyDict_Next(modules, &pos, &mod_name, &mod)) {
 
1286
                        int found = 0;
 
1287
                        struct uwsgi_string_list *usl = up.auto_reload_ignore;
 
1288
                        while(usl) {
 
1289
                                if (!strcmp(usl->value, PyString_AsString(mod_name))) {
 
1290
                                        found = 1;
 
1291
                                        break;
 
1292
                                }
 
1293
                                usl = usl->next;
 
1294
                        }
 
1295
                        if (found) continue;
 
1296
                        if (!PyObject_HasAttrString(mod, "__file__")) continue;
 
1297
                        PyObject *mod_file = PyObject_GetAttrString(mod, "__file__");
 
1298
                        if (!mod_file) continue;
 
1299
#ifdef PYTHREE
 
1300
                        PyObject *zero = PyUnicode_AsUTF8String(mod_file);
 
1301
                        char *mod_filename = PyString_AsString(zero);
 
1302
#else
 
1303
                        char *mod_filename = PyString_AsString(mod_file);
 
1304
#endif
 
1305
                        if (!mod_filename) {
 
1306
#ifdef PYTHREE
 
1307
                                Py_DECREF(zero);
 
1308
#endif
 
1309
                                continue;
 
1310
                        }
 
1311
                        char *ext = strrchr(mod_filename, '.');
 
1312
                        if (ext && (!strcmp(ext+1, "pyc") || !strcmp(ext+1, "pyd") || !strcmp(ext+1, "pyo"))) {
 
1313
                                filename = uwsgi_concat2n(mod_filename, strlen(mod_filename)-1, "", 0);
 
1314
                        }
 
1315
                        else {
 
1316
                                filename = uwsgi_concat2(mod_filename, "");
 
1317
                        }
 
1318
                        if (uwsgi_check_python_mtime(times_dict, filename)) {
 
1319
                                UWSGI_RELEASE_GIL;
 
1320
                                return NULL;
 
1321
                        }
 
1322
                        free(filename);
 
1323
#ifdef PYTHREE
 
1324
                        Py_DECREF(zero);
 
1325
#endif
 
1326
                }
 
1327
        }
 
1328
 
 
1329
        return NULL;
 
1330
}
 
1331
#endif
 
1332
 
1171
1333
#ifndef UWSGI_PYPY
1172
1334
void uwsgi_python_suspend(struct wsgi_request *wsgi_req) {
1173
1335
 
1407
1569
 
1408
1570
        // the pyshell will be execute only in the first worker
1409
1571
 
 
1572
#ifndef UWSGI_PYPY
1410
1573
        FILE *pyfile;
1411
1574
        if (up.pyrun) {
1412
1575
                uwsgi.workers[uwsgi.mywid].hijacked = 1;
1420
1583
                // could be never executed
1421
1584
                exit(0);
1422
1585
        }
 
1586
#endif
1423
1587
 
1424
 
#ifndef UWSGI_PYPY
1425
1588
        if (up.pyshell_oneshot && uwsgi.workers[uwsgi.mywid].hijacked_count > 0) {
1426
1589
                uwsgi.workers[uwsgi.mywid].hijacked = 0;
1427
1590
                return;
1440
1603
                }
1441
1604
                UWSGI_GET_GIL;
1442
1605
                PyImport_ImportModule("readline");
 
1606
 
 
1607
#ifndef UWSGI_PYPY
1443
1608
                int ret = PyRun_InteractiveLoop(stdin, "uwsgi");
1444
1609
 
1445
1610
                if (up.pyshell_oneshot) {
1449
1614
                if (ret == 0) {
1450
1615
                        exit(UWSGI_QUIET_CODE);
1451
1616
                }
 
1617
#endif
1452
1618
                exit(0);
1453
1619
        }
1454
 
#endif
1455
1620
}
1456
1621
 
1457
1622
int uwsgi_python_mule(char *opt) {
1496
1661
        return 1;
1497
1662
}
1498
1663
 
 
1664
 
 
1665
#ifndef UWSGI_PYPY
1499
1666
struct uwsgi_plugin python_plugin = {
1500
 
 
1501
1667
        .name = "python",
 
1668
#else
 
1669
struct uwsgi_plugin pypy_plugin = {
 
1670
        .name = "pypy",
 
1671
#endif
1502
1672
        .alias = "python",
1503
1673
        .modifier1 = 0,
1504
1674
        .init = uwsgi_python_init,