11592Smax.romanov@nginx.com
21592Smax.romanov@nginx.com /*
31592Smax.romanov@nginx.com * Copyright (C) NGINX, Inc.
41592Smax.romanov@nginx.com */
51592Smax.romanov@nginx.com
61592Smax.romanov@nginx.com
71592Smax.romanov@nginx.com #include <Python.h>
81592Smax.romanov@nginx.com
91592Smax.romanov@nginx.com #include <nxt_main.h>
101592Smax.romanov@nginx.com #include <nxt_router.h>
111592Smax.romanov@nginx.com #include <nxt_unit.h>
121592Smax.romanov@nginx.com
131592Smax.romanov@nginx.com #include <python/nxt_python.h>
141592Smax.romanov@nginx.com
151592Smax.romanov@nginx.com #include NXT_PYTHON_MOUNTS_H
161592Smax.romanov@nginx.com
171592Smax.romanov@nginx.com
181681Smax.romanov@nginx.com typedef struct {
191681Smax.romanov@nginx.com pthread_t thread;
201681Smax.romanov@nginx.com nxt_unit_ctx_t *ctx;
211681Smax.romanov@nginx.com void *ctx_data;
221681Smax.romanov@nginx.com } nxt_py_thread_info_t;
231681Smax.romanov@nginx.com
241681Smax.romanov@nginx.com
252251Sa.clayton@nginx.com #if PY_MAJOR_VERSION == 3
262251Sa.clayton@nginx.com static nxt_int_t nxt_python3_init_config(nxt_int_t pep405);
272251Sa.clayton@nginx.com #endif
282251Sa.clayton@nginx.com
291592Smax.romanov@nginx.com static nxt_int_t nxt_python_start(nxt_task_t *task,
301592Smax.romanov@nginx.com nxt_process_data_t *data);
311872So.canty@f5.com static nxt_int_t nxt_python_set_target(nxt_task_t *task,
321872So.canty@f5.com nxt_python_target_t *target, nxt_conf_value_t *conf);
33*2273Sjeff.iadarola@gmail.com nxt_inline nxt_int_t nxt_python_set_prefix(nxt_task_t *task,
34*2273Sjeff.iadarola@gmail.com nxt_python_target_t *target, nxt_conf_value_t *value);
351759Svbart@nginx.com static nxt_int_t nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value);
361681Smax.romanov@nginx.com static int nxt_python_init_threads(nxt_python_app_conf_t *c);
371681Smax.romanov@nginx.com static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx);
381681Smax.romanov@nginx.com static void *nxt_python_thread_func(void *main_ctx);
391681Smax.romanov@nginx.com static void nxt_python_join_threads(nxt_unit_ctx_t *ctx,
401681Smax.romanov@nginx.com nxt_python_app_conf_t *c);
411592Smax.romanov@nginx.com static void nxt_python_atexit(void);
421592Smax.romanov@nginx.com
431592Smax.romanov@nginx.com static uint32_t compat[] = {
441592Smax.romanov@nginx.com NXT_VERNUM, NXT_DEBUG,
451592Smax.romanov@nginx.com };
461592Smax.romanov@nginx.com
471592Smax.romanov@nginx.com
481592Smax.romanov@nginx.com NXT_EXPORT nxt_app_module_t nxt_app_module = {
491592Smax.romanov@nginx.com sizeof(compat),
501592Smax.romanov@nginx.com compat,
511592Smax.romanov@nginx.com nxt_string("python"),
521592Smax.romanov@nginx.com PY_VERSION,
531592Smax.romanov@nginx.com nxt_python_mounts,
541592Smax.romanov@nginx.com nxt_nitems(nxt_python_mounts),
551592Smax.romanov@nginx.com NULL,
561592Smax.romanov@nginx.com nxt_python_start,
571592Smax.romanov@nginx.com };
581592Smax.romanov@nginx.com
591592Smax.romanov@nginx.com static PyObject *nxt_py_stderr_flush;
601872So.canty@f5.com nxt_python_targets_t *nxt_py_targets;
611592Smax.romanov@nginx.com
621592Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3
631592Smax.romanov@nginx.com static wchar_t *nxt_py_home;
641592Smax.romanov@nginx.com #else
651592Smax.romanov@nginx.com static char *nxt_py_home;
661592Smax.romanov@nginx.com #endif
671592Smax.romanov@nginx.com
681681Smax.romanov@nginx.com static pthread_attr_t *nxt_py_thread_attr;
691681Smax.romanov@nginx.com static nxt_py_thread_info_t *nxt_py_threads;
701681Smax.romanov@nginx.com static nxt_python_proto_t nxt_py_proto;
711681Smax.romanov@nginx.com
721592Smax.romanov@nginx.com
732251Sa.clayton@nginx.com #if PY_VERSION_HEX >= NXT_PYTHON_VER(3, 8)
742251Sa.clayton@nginx.com
752251Sa.clayton@nginx.com static nxt_int_t
nxt_python3_init_config(nxt_int_t pep405)762251Sa.clayton@nginx.com nxt_python3_init_config(nxt_int_t pep405)
772251Sa.clayton@nginx.com {
782337Sa.clayton@nginx.com PyConfig config;
792337Sa.clayton@nginx.com PyStatus status;
802337Sa.clayton@nginx.com nxt_int_t ret;
812338Sa.clayton@nginx.com PyPreConfig preconfig;
822337Sa.clayton@nginx.com
832337Sa.clayton@nginx.com ret = NXT_ERROR;
842251Sa.clayton@nginx.com
852338Sa.clayton@nginx.com PyPreConfig_InitIsolatedConfig(&preconfig);
862338Sa.clayton@nginx.com /*
872338Sa.clayton@nginx.com * Determine whether to use UTF-8 mode or not, UTF-8
882338Sa.clayton@nginx.com * will be enabled if LC_CTYPE is C, POSIX or some
892338Sa.clayton@nginx.com * specific UTF-8 locale.
902338Sa.clayton@nginx.com */
912338Sa.clayton@nginx.com preconfig.utf8_mode = -1;
922338Sa.clayton@nginx.com
932338Sa.clayton@nginx.com status = Py_PreInitialize(&preconfig);
942338Sa.clayton@nginx.com if (PyStatus_Exception(status)) {
952338Sa.clayton@nginx.com return ret;
962338Sa.clayton@nginx.com }
972338Sa.clayton@nginx.com
982251Sa.clayton@nginx.com PyConfig_InitIsolatedConfig(&config);
992251Sa.clayton@nginx.com
1002251Sa.clayton@nginx.com if (pep405) {
1012251Sa.clayton@nginx.com status = PyConfig_SetString(&config, &config.program_name,
1022251Sa.clayton@nginx.com nxt_py_home);
1032251Sa.clayton@nginx.com if (PyStatus_Exception(status)) {
1042337Sa.clayton@nginx.com goto out_config_clear;
1052251Sa.clayton@nginx.com }
1062251Sa.clayton@nginx.com
1072251Sa.clayton@nginx.com } else {
1082337Sa.clayton@nginx.com status = PyConfig_SetString(&config, &config.home, nxt_py_home);
1092251Sa.clayton@nginx.com if (PyStatus_Exception(status)) {
1102337Sa.clayton@nginx.com goto out_config_clear;
1112251Sa.clayton@nginx.com }
1122251Sa.clayton@nginx.com }
1132251Sa.clayton@nginx.com
1142251Sa.clayton@nginx.com status = Py_InitializeFromConfig(&config);
1152251Sa.clayton@nginx.com if (PyStatus_Exception(status)) {
1162337Sa.clayton@nginx.com goto out_config_clear;
1172251Sa.clayton@nginx.com }
1182251Sa.clayton@nginx.com
1192337Sa.clayton@nginx.com ret = NXT_OK;
1202251Sa.clayton@nginx.com
1212337Sa.clayton@nginx.com out_config_clear:
1222251Sa.clayton@nginx.com
1232251Sa.clayton@nginx.com PyConfig_Clear(&config);
1242251Sa.clayton@nginx.com
1252337Sa.clayton@nginx.com return ret;
1262251Sa.clayton@nginx.com }
1272251Sa.clayton@nginx.com
1282251Sa.clayton@nginx.com #elif PY_MAJOR_VERSION == 3
1292251Sa.clayton@nginx.com
1302251Sa.clayton@nginx.com static nxt_int_t
nxt_python3_init_config(nxt_int_t pep405)1312251Sa.clayton@nginx.com nxt_python3_init_config(nxt_int_t pep405)
1322251Sa.clayton@nginx.com {
1332251Sa.clayton@nginx.com if (pep405) {
1342251Sa.clayton@nginx.com Py_SetProgramName(nxt_py_home);
1352251Sa.clayton@nginx.com
1362251Sa.clayton@nginx.com } else {
1372251Sa.clayton@nginx.com Py_SetPythonHome(nxt_py_home);
1382251Sa.clayton@nginx.com }
1392251Sa.clayton@nginx.com
1402251Sa.clayton@nginx.com return NXT_OK;
1412251Sa.clayton@nginx.com }
1422251Sa.clayton@nginx.com
1432251Sa.clayton@nginx.com #endif
1442251Sa.clayton@nginx.com
1452251Sa.clayton@nginx.com
1461592Smax.romanov@nginx.com static nxt_int_t
nxt_python_start(nxt_task_t * task,nxt_process_data_t * data)1471592Smax.romanov@nginx.com nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
1481592Smax.romanov@nginx.com {
1491681Smax.romanov@nginx.com int rc;
1501872So.canty@f5.com size_t len, size;
1511872So.canty@f5.com uint32_t next;
1522240Sjeff.iadarola@gmail.com PyObject *obj;
1531872So.canty@f5.com nxt_str_t proto, probe_proto, name;
1541872So.canty@f5.com nxt_int_t ret, n, i;
1551592Smax.romanov@nginx.com nxt_unit_ctx_t *unit_ctx;
1561592Smax.romanov@nginx.com nxt_unit_init_t python_init;
1571872So.canty@f5.com nxt_conf_value_t *cv;
1581872So.canty@f5.com nxt_python_targets_t *targets;
1591592Smax.romanov@nginx.com nxt_common_app_conf_t *app_conf;
1601592Smax.romanov@nginx.com nxt_python_app_conf_t *c;
1611592Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3
1621592Smax.romanov@nginx.com char *path;
1631592Smax.romanov@nginx.com nxt_int_t pep405;
1641592Smax.romanov@nginx.com
1651592Smax.romanov@nginx.com static const char pyvenv[] = "/pyvenv.cfg";
1661592Smax.romanov@nginx.com static const char bin_python[] = "/bin/python";
1671592Smax.romanov@nginx.com #endif
1681592Smax.romanov@nginx.com
1691697Smax.romanov@nginx.com static const nxt_str_t wsgi = nxt_string("wsgi");
1701697Smax.romanov@nginx.com static const nxt_str_t asgi = nxt_string("asgi");
1711697Smax.romanov@nginx.com
1721592Smax.romanov@nginx.com app_conf = data->app;
1731592Smax.romanov@nginx.com c = &app_conf->u.python;
1741592Smax.romanov@nginx.com
1751592Smax.romanov@nginx.com if (c->home != NULL) {
1761592Smax.romanov@nginx.com len = nxt_strlen(c->home);
1771592Smax.romanov@nginx.com
1781592Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3
1791592Smax.romanov@nginx.com
1801592Smax.romanov@nginx.com path = nxt_malloc(len + sizeof(pyvenv));
1811592Smax.romanov@nginx.com if (nxt_slow_path(path == NULL)) {
1821592Smax.romanov@nginx.com nxt_alert(task, "Failed to allocate memory");
1831592Smax.romanov@nginx.com return NXT_ERROR;
1841592Smax.romanov@nginx.com }
1851592Smax.romanov@nginx.com
1861592Smax.romanov@nginx.com nxt_memcpy(path, c->home, len);
1871592Smax.romanov@nginx.com nxt_memcpy(path + len, pyvenv, sizeof(pyvenv));
1881592Smax.romanov@nginx.com
1891592Smax.romanov@nginx.com pep405 = (access(path, R_OK) == 0);
1901592Smax.romanov@nginx.com
1911592Smax.romanov@nginx.com nxt_free(path);
1921592Smax.romanov@nginx.com
1931592Smax.romanov@nginx.com if (pep405) {
1941592Smax.romanov@nginx.com size = (len + sizeof(bin_python)) * sizeof(wchar_t);
1951592Smax.romanov@nginx.com
1961592Smax.romanov@nginx.com } else {
1971592Smax.romanov@nginx.com size = (len + 1) * sizeof(wchar_t);
1981592Smax.romanov@nginx.com }
1991592Smax.romanov@nginx.com
2001592Smax.romanov@nginx.com nxt_py_home = nxt_malloc(size);
2011592Smax.romanov@nginx.com if (nxt_slow_path(nxt_py_home == NULL)) {
2021592Smax.romanov@nginx.com nxt_alert(task, "Failed to allocate memory");
2031592Smax.romanov@nginx.com return NXT_ERROR;
2041592Smax.romanov@nginx.com }
2051592Smax.romanov@nginx.com
2061592Smax.romanov@nginx.com if (pep405) {
2071592Smax.romanov@nginx.com mbstowcs(nxt_py_home, c->home, len);
2081592Smax.romanov@nginx.com mbstowcs(nxt_py_home + len, bin_python, sizeof(bin_python));
2091592Smax.romanov@nginx.com
2101592Smax.romanov@nginx.com } else {
2111592Smax.romanov@nginx.com mbstowcs(nxt_py_home, c->home, len + 1);
2122251Sa.clayton@nginx.com }
2132251Sa.clayton@nginx.com
2142251Sa.clayton@nginx.com ret = nxt_python3_init_config(pep405);
2152251Sa.clayton@nginx.com if (nxt_slow_path(ret == NXT_ERROR)) {
2162251Sa.clayton@nginx.com nxt_alert(task, "Failed to initialise config");
2172251Sa.clayton@nginx.com return NXT_ERROR;
2181592Smax.romanov@nginx.com }
2191592Smax.romanov@nginx.com
2201592Smax.romanov@nginx.com #else
2211592Smax.romanov@nginx.com nxt_py_home = nxt_malloc(len + 1);
2221592Smax.romanov@nginx.com if (nxt_slow_path(nxt_py_home == NULL)) {
2231592Smax.romanov@nginx.com nxt_alert(task, "Failed to allocate memory");
2241592Smax.romanov@nginx.com return NXT_ERROR;
2251592Smax.romanov@nginx.com }
2261592Smax.romanov@nginx.com
2271592Smax.romanov@nginx.com nxt_memcpy(nxt_py_home, c->home, len + 1);
2281592Smax.romanov@nginx.com Py_SetPythonHome(nxt_py_home);
2291592Smax.romanov@nginx.com #endif
2301592Smax.romanov@nginx.com }
2311592Smax.romanov@nginx.com
2321592Smax.romanov@nginx.com Py_InitializeEx(0);
2331592Smax.romanov@nginx.com
2341681Smax.romanov@nginx.com #if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7)
2351681Smax.romanov@nginx.com if (c->threads > 1) {
2361681Smax.romanov@nginx.com PyEval_InitThreads();
2371681Smax.romanov@nginx.com }
2381681Smax.romanov@nginx.com #endif
2391681Smax.romanov@nginx.com
2401592Smax.romanov@nginx.com obj = NULL;
2411592Smax.romanov@nginx.com
2421681Smax.romanov@nginx.com python_init.ctx_data = NULL;
2431681Smax.romanov@nginx.com
2441592Smax.romanov@nginx.com obj = PySys_GetObject((char *) "stderr");
2451592Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) {
2461592Smax.romanov@nginx.com nxt_alert(task, "Python failed to get \"sys.stderr\" object");
2471592Smax.romanov@nginx.com goto fail;
2481592Smax.romanov@nginx.com }
2491592Smax.romanov@nginx.com
2501592Smax.romanov@nginx.com nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush");
2511759Svbart@nginx.com
2521759Svbart@nginx.com /* obj is a Borrowed reference. */
2531759Svbart@nginx.com obj = NULL;
2541759Svbart@nginx.com
2551592Smax.romanov@nginx.com if (nxt_slow_path(nxt_py_stderr_flush == NULL)) {
2561592Smax.romanov@nginx.com nxt_alert(task, "Python failed to get \"flush\" attribute of "
2571592Smax.romanov@nginx.com "\"sys.stderr\" object");
2581592Smax.romanov@nginx.com goto fail;
2591592Smax.romanov@nginx.com }
2601592Smax.romanov@nginx.com
2611759Svbart@nginx.com if (nxt_slow_path(nxt_python_set_path(task, c->path) != NXT_OK)) {
2621759Svbart@nginx.com goto fail;
2631592Smax.romanov@nginx.com }
2641592Smax.romanov@nginx.com
2651592Smax.romanov@nginx.com obj = Py_BuildValue("[s]", "unit");
2661592Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) {
2671592Smax.romanov@nginx.com nxt_alert(task, "Python failed to create the \"sys.argv\" list");
2681592Smax.romanov@nginx.com goto fail;
2691592Smax.romanov@nginx.com }
2701592Smax.romanov@nginx.com
2711592Smax.romanov@nginx.com if (nxt_slow_path(PySys_SetObject((char *) "argv", obj) != 0)) {
2721592Smax.romanov@nginx.com nxt_alert(task, "Python failed to set the \"sys.argv\" list");
2731592Smax.romanov@nginx.com goto fail;
2741592Smax.romanov@nginx.com }
2751592Smax.romanov@nginx.com
2761592Smax.romanov@nginx.com Py_CLEAR(obj);
2771592Smax.romanov@nginx.com
2781872So.canty@f5.com n = (c->targets != NULL ? nxt_conf_object_members_count(c->targets) : 1);
2791872So.canty@f5.com
2801872So.canty@f5.com size = sizeof(nxt_python_targets_t) + n * sizeof(nxt_python_target_t);
2811592Smax.romanov@nginx.com
2821872So.canty@f5.com targets = nxt_unit_malloc(NULL, size);
2831872So.canty@f5.com if (nxt_slow_path(targets == NULL)) {
2841872So.canty@f5.com nxt_alert(task, "Could not allocate targets");
2851592Smax.romanov@nginx.com goto fail;
2861592Smax.romanov@nginx.com }
2871592Smax.romanov@nginx.com
2881872So.canty@f5.com memset(targets, 0, size);
2891601Smax.romanov@nginx.com
2901872So.canty@f5.com targets->count = n;
2911872So.canty@f5.com nxt_py_targets = targets;
2921872So.canty@f5.com
2931872So.canty@f5.com if (c->targets != NULL) {
2941872So.canty@f5.com next = 0;
2951592Smax.romanov@nginx.com
2961872So.canty@f5.com for (i = 0; /* void */; i++) {
2971872So.canty@f5.com cv = nxt_conf_next_object_member(c->targets, &name, &next);
2981872So.canty@f5.com if (cv == NULL) {
2991872So.canty@f5.com break;
3001872So.canty@f5.com }
3011592Smax.romanov@nginx.com
3021872So.canty@f5.com ret = nxt_python_set_target(task, &targets->target[i], cv);
3031872So.canty@f5.com if (nxt_slow_path(ret != NXT_OK)) {
3041872So.canty@f5.com goto fail;
3051872So.canty@f5.com }
3061872So.canty@f5.com }
3071592Smax.romanov@nginx.com
3081872So.canty@f5.com } else {
3091872So.canty@f5.com ret = nxt_python_set_target(task, &targets->target[0], app_conf->self);
3101872So.canty@f5.com if (nxt_slow_path(ret != NXT_OK)) {
3111872So.canty@f5.com goto fail;
3121872So.canty@f5.com }
3131872So.canty@f5.com }
3141592Smax.romanov@nginx.com
3151980Smax.romanov@nginx.com nxt_unit_default_init(task, &python_init, data->app);
3161592Smax.romanov@nginx.com
3171681Smax.romanov@nginx.com python_init.data = c;
3181681Smax.romanov@nginx.com python_init.callbacks.ready_handler = nxt_python_ready_handler;
3191592Smax.romanov@nginx.com
3201697Smax.romanov@nginx.com proto = c->protocol;
3211697Smax.romanov@nginx.com
3221697Smax.romanov@nginx.com if (proto.length == 0) {
3231872So.canty@f5.com proto = nxt_python_asgi_check(targets->target[0].application)
3241872So.canty@f5.com ? asgi : wsgi;
3251872So.canty@f5.com
3261872So.canty@f5.com for (i = 1; i < targets->count; i++) {
3271872So.canty@f5.com probe_proto = nxt_python_asgi_check(targets->target[i].application)
3281872So.canty@f5.com ? asgi : wsgi;
3291872So.canty@f5.com if (probe_proto.start != proto.start) {
3301872So.canty@f5.com nxt_alert(task, "A mix of ASGI & WSGI targets is forbidden, "
3311872So.canty@f5.com "specify protocol in config if incorrect");
3321872So.canty@f5.com goto fail;
3331872So.canty@f5.com }
3341872So.canty@f5.com }
3351697Smax.romanov@nginx.com }
3361697Smax.romanov@nginx.com
3371697Smax.romanov@nginx.com if (nxt_strstr_eq(&proto, &asgi)) {
3381681Smax.romanov@nginx.com rc = nxt_python_asgi_init(&python_init, &nxt_py_proto);
3391624Smax.romanov@nginx.com
3401624Smax.romanov@nginx.com } else {
3411681Smax.romanov@nginx.com rc = nxt_python_wsgi_init(&python_init, &nxt_py_proto);
3421681Smax.romanov@nginx.com }
3431681Smax.romanov@nginx.com
3441681Smax.romanov@nginx.com if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
3451681Smax.romanov@nginx.com goto fail;
3461624Smax.romanov@nginx.com }
3471624Smax.romanov@nginx.com
3481918Smax.romanov@nginx.com rc = nxt_py_proto.ctx_data_alloc(&python_init.ctx_data, 1);
3491681Smax.romanov@nginx.com if (nxt_slow_path(rc != NXT_UNIT_OK)) {
3501592Smax.romanov@nginx.com goto fail;
3511592Smax.romanov@nginx.com }
3521592Smax.romanov@nginx.com
3531681Smax.romanov@nginx.com rc = nxt_python_init_threads(c);
3541681Smax.romanov@nginx.com if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
3551681Smax.romanov@nginx.com goto fail;
3561681Smax.romanov@nginx.com }
3571681Smax.romanov@nginx.com
3581681Smax.romanov@nginx.com if (nxt_py_proto.startup != NULL) {
3591681Smax.romanov@nginx.com if (nxt_py_proto.startup(python_init.ctx_data) != NXT_UNIT_OK) {
3601681Smax.romanov@nginx.com goto fail;
3611681Smax.romanov@nginx.com }
3621681Smax.romanov@nginx.com }
3631681Smax.romanov@nginx.com
3641592Smax.romanov@nginx.com unit_ctx = nxt_unit_init(&python_init);
3651592Smax.romanov@nginx.com if (nxt_slow_path(unit_ctx == NULL)) {
3661592Smax.romanov@nginx.com goto fail;
3671592Smax.romanov@nginx.com }
3681592Smax.romanov@nginx.com
3691681Smax.romanov@nginx.com rc = nxt_py_proto.run(unit_ctx);
3701624Smax.romanov@nginx.com
3711681Smax.romanov@nginx.com nxt_python_join_threads(unit_ctx, c);
3721592Smax.romanov@nginx.com
3731592Smax.romanov@nginx.com nxt_unit_done(unit_ctx);
3741592Smax.romanov@nginx.com
3751681Smax.romanov@nginx.com nxt_py_proto.ctx_data_free(python_init.ctx_data);
3761681Smax.romanov@nginx.com
3771592Smax.romanov@nginx.com nxt_python_atexit();
3781592Smax.romanov@nginx.com
3791592Smax.romanov@nginx.com exit(rc);
3801592Smax.romanov@nginx.com
3811592Smax.romanov@nginx.com return NXT_OK;
3821592Smax.romanov@nginx.com
3831592Smax.romanov@nginx.com fail:
3841592Smax.romanov@nginx.com
3851681Smax.romanov@nginx.com nxt_python_join_threads(NULL, c);
3861681Smax.romanov@nginx.com
3871681Smax.romanov@nginx.com if (python_init.ctx_data != NULL) {
3881681Smax.romanov@nginx.com nxt_py_proto.ctx_data_free(python_init.ctx_data);
3891681Smax.romanov@nginx.com }
3901681Smax.romanov@nginx.com
3911592Smax.romanov@nginx.com Py_XDECREF(obj);
3921592Smax.romanov@nginx.com
3931592Smax.romanov@nginx.com nxt_python_atexit();
3941592Smax.romanov@nginx.com
3951592Smax.romanov@nginx.com return NXT_ERROR;
3961592Smax.romanov@nginx.com }
3971592Smax.romanov@nginx.com
3981592Smax.romanov@nginx.com
3991759Svbart@nginx.com static nxt_int_t
nxt_python_set_target(nxt_task_t * task,nxt_python_target_t * target,nxt_conf_value_t * conf)4001872So.canty@f5.com nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target,
4011872So.canty@f5.com nxt_conf_value_t *conf)
4021872So.canty@f5.com {
4031872So.canty@f5.com char *callable, *module_name;
4041872So.canty@f5.com PyObject *module, *obj;
4051872So.canty@f5.com nxt_str_t str;
4061872So.canty@f5.com nxt_conf_value_t *value;
4071872So.canty@f5.com
4081872So.canty@f5.com static nxt_str_t module_str = nxt_string("module");
4091872So.canty@f5.com static nxt_str_t callable_str = nxt_string("callable");
410*2273Sjeff.iadarola@gmail.com static nxt_str_t prefix_str = nxt_string("prefix");
4111872So.canty@f5.com
4121872So.canty@f5.com module = obj = NULL;
4131872So.canty@f5.com
4141872So.canty@f5.com value = nxt_conf_get_object_member(conf, &module_str, NULL);
4151872So.canty@f5.com if (nxt_slow_path(value == NULL)) {
4161872So.canty@f5.com goto fail;
4171872So.canty@f5.com }
4181872So.canty@f5.com
4191872So.canty@f5.com nxt_conf_get_string(value, &str);
4201872So.canty@f5.com
4211872So.canty@f5.com module_name = nxt_alloca(str.length + 1);
4221872So.canty@f5.com nxt_memcpy(module_name, str.start, str.length);
4231872So.canty@f5.com module_name[str.length] = '\0';
4241872So.canty@f5.com
4251872So.canty@f5.com module = PyImport_ImportModule(module_name);
4261872So.canty@f5.com if (nxt_slow_path(module == NULL)) {
4271872So.canty@f5.com nxt_alert(task, "Python failed to import module \"%s\"", module_name);
4281872So.canty@f5.com nxt_python_print_exception();
4291872So.canty@f5.com goto fail;
4301872So.canty@f5.com }
4311872So.canty@f5.com
4321872So.canty@f5.com value = nxt_conf_get_object_member(conf, &callable_str, NULL);
4331872So.canty@f5.com if (value == NULL) {
4341872So.canty@f5.com callable = nxt_alloca(12);
4351872So.canty@f5.com nxt_memcpy(callable, "application", 12);
4361872So.canty@f5.com
4371872So.canty@f5.com } else {
4381872So.canty@f5.com nxt_conf_get_string(value, &str);
4391872So.canty@f5.com
4401872So.canty@f5.com callable = nxt_alloca(str.length + 1);
4411872So.canty@f5.com nxt_memcpy(callable, str.start, str.length);
4421872So.canty@f5.com callable[str.length] = '\0';
4431872So.canty@f5.com }
4441872So.canty@f5.com
4451872So.canty@f5.com obj = PyDict_GetItemString(PyModule_GetDict(module), callable);
4461872So.canty@f5.com if (nxt_slow_path(obj == NULL)) {
4471872So.canty@f5.com nxt_alert(task, "Python failed to get \"%s\" from module \"%s\"",
4481932Smax.romanov@nginx.com callable, module_name);
4491872So.canty@f5.com goto fail;
4501872So.canty@f5.com }
4511872So.canty@f5.com
4521872So.canty@f5.com if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
4531872So.canty@f5.com nxt_alert(task, "\"%s\" in module \"%s\" is not a callable object",
4541932Smax.romanov@nginx.com callable, module_name);
4551872So.canty@f5.com goto fail;
4561872So.canty@f5.com }
4571872So.canty@f5.com
458*2273Sjeff.iadarola@gmail.com value = nxt_conf_get_object_member(conf, &prefix_str, NULL);
459*2273Sjeff.iadarola@gmail.com if (nxt_slow_path(nxt_python_set_prefix(task, target, value) != NXT_OK)) {
460*2273Sjeff.iadarola@gmail.com goto fail;
461*2273Sjeff.iadarola@gmail.com }
462*2273Sjeff.iadarola@gmail.com
4631872So.canty@f5.com target->application = obj;
4641872So.canty@f5.com obj = NULL;
4651872So.canty@f5.com
4661872So.canty@f5.com Py_INCREF(target->application);
4671872So.canty@f5.com Py_CLEAR(module);
4681872So.canty@f5.com
4691872So.canty@f5.com return NXT_OK;
4701872So.canty@f5.com
4711872So.canty@f5.com fail:
4721872So.canty@f5.com
4731872So.canty@f5.com Py_XDECREF(obj);
4741872So.canty@f5.com Py_XDECREF(module);
4751872So.canty@f5.com
4761872So.canty@f5.com return NXT_ERROR;
4771872So.canty@f5.com }
4781872So.canty@f5.com
4791872So.canty@f5.com
480*2273Sjeff.iadarola@gmail.com nxt_inline nxt_int_t
nxt_python_set_prefix(nxt_task_t * task,nxt_python_target_t * target,nxt_conf_value_t * value)481*2273Sjeff.iadarola@gmail.com nxt_python_set_prefix(nxt_task_t *task, nxt_python_target_t *target,
482*2273Sjeff.iadarola@gmail.com nxt_conf_value_t *value)
483*2273Sjeff.iadarola@gmail.com {
484*2273Sjeff.iadarola@gmail.com u_char *prefix;
485*2273Sjeff.iadarola@gmail.com nxt_str_t str;
486*2273Sjeff.iadarola@gmail.com
487*2273Sjeff.iadarola@gmail.com if (value == NULL) {
488*2273Sjeff.iadarola@gmail.com return NXT_OK;
489*2273Sjeff.iadarola@gmail.com }
490*2273Sjeff.iadarola@gmail.com
491*2273Sjeff.iadarola@gmail.com nxt_conf_get_string(value, &str);
492*2273Sjeff.iadarola@gmail.com
493*2273Sjeff.iadarola@gmail.com if (str.length == 0) {
494*2273Sjeff.iadarola@gmail.com return NXT_OK;
495*2273Sjeff.iadarola@gmail.com }
496*2273Sjeff.iadarola@gmail.com
497*2273Sjeff.iadarola@gmail.com if (str.start[str.length - 1] == '/') {
498*2273Sjeff.iadarola@gmail.com str.length--;
499*2273Sjeff.iadarola@gmail.com }
500*2273Sjeff.iadarola@gmail.com target->prefix.length = str.length;
501*2273Sjeff.iadarola@gmail.com prefix = nxt_malloc(str.length);
502*2273Sjeff.iadarola@gmail.com if (nxt_slow_path(prefix == NULL)) {
503*2273Sjeff.iadarola@gmail.com nxt_alert(task, "Failed to allocate target prefix string");
504*2273Sjeff.iadarola@gmail.com return NXT_ERROR;
505*2273Sjeff.iadarola@gmail.com }
506*2273Sjeff.iadarola@gmail.com
507*2273Sjeff.iadarola@gmail.com target->py_prefix = PyString_FromStringAndSize((char *)str.start,
508*2273Sjeff.iadarola@gmail.com str.length);
509*2273Sjeff.iadarola@gmail.com if (nxt_slow_path(target->py_prefix == NULL)) {
510*2273Sjeff.iadarola@gmail.com nxt_free(prefix);
511*2273Sjeff.iadarola@gmail.com nxt_alert(task, "Python failed to allocate target prefix "
512*2273Sjeff.iadarola@gmail.com "string");
513*2273Sjeff.iadarola@gmail.com return NXT_ERROR;
514*2273Sjeff.iadarola@gmail.com }
515*2273Sjeff.iadarola@gmail.com nxt_memcpy(prefix, str.start, str.length);
516*2273Sjeff.iadarola@gmail.com target->prefix.start = prefix;
517*2273Sjeff.iadarola@gmail.com
518*2273Sjeff.iadarola@gmail.com return NXT_OK;
519*2273Sjeff.iadarola@gmail.com }
520*2273Sjeff.iadarola@gmail.com
521*2273Sjeff.iadarola@gmail.com
5221872So.canty@f5.com static nxt_int_t
nxt_python_set_path(nxt_task_t * task,nxt_conf_value_t * value)5231759Svbart@nginx.com nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value)
5241759Svbart@nginx.com {
5251759Svbart@nginx.com int ret;
5261759Svbart@nginx.com PyObject *path, *sys;
5271759Svbart@nginx.com nxt_str_t str;
5281759Svbart@nginx.com nxt_uint_t n;
5291759Svbart@nginx.com nxt_conf_value_t *array;
5301759Svbart@nginx.com
5311759Svbart@nginx.com if (value == NULL) {
5321759Svbart@nginx.com return NXT_OK;
5331759Svbart@nginx.com }
5341759Svbart@nginx.com
5351759Svbart@nginx.com sys = PySys_GetObject((char *) "path");
5361759Svbart@nginx.com if (nxt_slow_path(sys == NULL)) {
5371759Svbart@nginx.com nxt_alert(task, "Python failed to get \"sys.path\" list");
5381759Svbart@nginx.com return NXT_ERROR;
5391759Svbart@nginx.com }
5401759Svbart@nginx.com
5411759Svbart@nginx.com /* sys is a Borrowed reference. */
5421759Svbart@nginx.com
5431759Svbart@nginx.com array = value;
5442077Salx.manpages@gmail.com n = nxt_conf_array_elements_count_or_1(array);
5451759Svbart@nginx.com
5461759Svbart@nginx.com while (n != 0) {
5471759Svbart@nginx.com n--;
5481759Svbart@nginx.com
5491759Svbart@nginx.com /*
5501759Svbart@nginx.com * Insertion in front of existing paths starting from the last element
5511759Svbart@nginx.com * to preserve original order while giving priority to the values
5521759Svbart@nginx.com * specified in the "path" option.
5531759Svbart@nginx.com */
5541759Svbart@nginx.com
5552077Salx.manpages@gmail.com value = nxt_conf_get_array_element_or_itself(array, n);
5561759Svbart@nginx.com
5571759Svbart@nginx.com nxt_conf_get_string(value, &str);
5581759Svbart@nginx.com
5591759Svbart@nginx.com path = PyString_FromStringAndSize((char *) str.start, str.length);
5601759Svbart@nginx.com if (nxt_slow_path(path == NULL)) {
5611759Svbart@nginx.com nxt_alert(task, "Python failed to create string object \"%V\"",
5621759Svbart@nginx.com &str);
5631759Svbart@nginx.com return NXT_ERROR;
5641759Svbart@nginx.com }
5651759Svbart@nginx.com
5661759Svbart@nginx.com ret = PyList_Insert(sys, 0, path);
5671759Svbart@nginx.com
5681759Svbart@nginx.com Py_DECREF(path);
5691759Svbart@nginx.com
5701759Svbart@nginx.com if (nxt_slow_path(ret != 0)) {
5711759Svbart@nginx.com nxt_alert(task, "Python failed to insert \"%V\" into \"sys.path\"",
5721759Svbart@nginx.com &str);
5731759Svbart@nginx.com return NXT_ERROR;
5741759Svbart@nginx.com }
5751759Svbart@nginx.com }
5761759Svbart@nginx.com
5771759Svbart@nginx.com return NXT_OK;
5781759Svbart@nginx.com }
5791759Svbart@nginx.com
5801759Svbart@nginx.com
5811681Smax.romanov@nginx.com static int
nxt_python_init_threads(nxt_python_app_conf_t * c)5821681Smax.romanov@nginx.com nxt_python_init_threads(nxt_python_app_conf_t *c)
5831681Smax.romanov@nginx.com {
5841681Smax.romanov@nginx.com int res;
5851681Smax.romanov@nginx.com uint32_t i;
5861681Smax.romanov@nginx.com nxt_py_thread_info_t *ti;
5871681Smax.romanov@nginx.com static pthread_attr_t attr;
5881681Smax.romanov@nginx.com
5891681Smax.romanov@nginx.com if (c->threads <= 1) {
5901681Smax.romanov@nginx.com return NXT_UNIT_OK;
5911681Smax.romanov@nginx.com }
5921681Smax.romanov@nginx.com
5931681Smax.romanov@nginx.com if (c->thread_stack_size > 0) {
5941681Smax.romanov@nginx.com res = pthread_attr_init(&attr);
5951681Smax.romanov@nginx.com if (nxt_slow_path(res != 0)) {
5961681Smax.romanov@nginx.com nxt_unit_alert(NULL, "thread attr init failed: %s (%d)",
5971681Smax.romanov@nginx.com strerror(res), res);
5981681Smax.romanov@nginx.com
5991681Smax.romanov@nginx.com return NXT_UNIT_ERROR;
6001681Smax.romanov@nginx.com }
6011681Smax.romanov@nginx.com
6021681Smax.romanov@nginx.com res = pthread_attr_setstacksize(&attr, c->thread_stack_size);
6031681Smax.romanov@nginx.com if (nxt_slow_path(res != 0)) {
6041681Smax.romanov@nginx.com nxt_unit_alert(NULL, "thread attr set stack size failed: %s (%d)",
6051681Smax.romanov@nginx.com strerror(res), res);
6061681Smax.romanov@nginx.com
6071681Smax.romanov@nginx.com return NXT_UNIT_ERROR;
6081681Smax.romanov@nginx.com }
6091681Smax.romanov@nginx.com
6101681Smax.romanov@nginx.com nxt_py_thread_attr = &attr;
6111681Smax.romanov@nginx.com }
6121681Smax.romanov@nginx.com
6131681Smax.romanov@nginx.com nxt_py_threads = nxt_unit_malloc(NULL, sizeof(nxt_py_thread_info_t)
6141681Smax.romanov@nginx.com * (c->threads - 1));
6151681Smax.romanov@nginx.com if (nxt_slow_path(nxt_py_threads == NULL)) {
6161681Smax.romanov@nginx.com nxt_unit_alert(NULL, "Failed to allocate thread info array");
6171681Smax.romanov@nginx.com
6181681Smax.romanov@nginx.com return NXT_UNIT_ERROR;
6191681Smax.romanov@nginx.com }
6201681Smax.romanov@nginx.com
6211681Smax.romanov@nginx.com memset(nxt_py_threads, 0, sizeof(nxt_py_thread_info_t) * (c->threads - 1));
6221681Smax.romanov@nginx.com
6231681Smax.romanov@nginx.com for (i = 0; i < c->threads - 1; i++) {
6241681Smax.romanov@nginx.com ti = &nxt_py_threads[i];
6251681Smax.romanov@nginx.com
6261918Smax.romanov@nginx.com res = nxt_py_proto.ctx_data_alloc(&ti->ctx_data, 0);
6271681Smax.romanov@nginx.com if (nxt_slow_path(res != NXT_UNIT_OK)) {
6281681Smax.romanov@nginx.com return NXT_UNIT_ERROR;
6291681Smax.romanov@nginx.com }
6301681Smax.romanov@nginx.com }
6311681Smax.romanov@nginx.com
6321681Smax.romanov@nginx.com return NXT_UNIT_OK;
6331681Smax.romanov@nginx.com }
6341681Smax.romanov@nginx.com
6351681Smax.romanov@nginx.com
6361681Smax.romanov@nginx.com static int
nxt_python_ready_handler(nxt_unit_ctx_t * ctx)6371681Smax.romanov@nginx.com nxt_python_ready_handler(nxt_unit_ctx_t *ctx)
6381681Smax.romanov@nginx.com {
6391681Smax.romanov@nginx.com int res;
6401681Smax.romanov@nginx.com uint32_t i;
6411681Smax.romanov@nginx.com nxt_py_thread_info_t *ti;
6421681Smax.romanov@nginx.com nxt_python_app_conf_t *c;
6431681Smax.romanov@nginx.com
6441681Smax.romanov@nginx.com c = ctx->unit->data;
6451681Smax.romanov@nginx.com
6461681Smax.romanov@nginx.com if (c->threads <= 1) {
6471681Smax.romanov@nginx.com return NXT_UNIT_OK;
6481681Smax.romanov@nginx.com }
6491681Smax.romanov@nginx.com
6501681Smax.romanov@nginx.com for (i = 0; i < c->threads - 1; i++) {
6511681Smax.romanov@nginx.com ti = &nxt_py_threads[i];
6521681Smax.romanov@nginx.com
6531681Smax.romanov@nginx.com ti->ctx = ctx;
6541681Smax.romanov@nginx.com
6551681Smax.romanov@nginx.com res = pthread_create(&ti->thread, nxt_py_thread_attr,
6561681Smax.romanov@nginx.com nxt_python_thread_func, ti);
6571681Smax.romanov@nginx.com
6581681Smax.romanov@nginx.com if (nxt_fast_path(res == 0)) {
6591681Smax.romanov@nginx.com nxt_unit_debug(ctx, "thread #%d created", (int) (i + 1));
6601681Smax.romanov@nginx.com
6611681Smax.romanov@nginx.com } else {
6621681Smax.romanov@nginx.com nxt_unit_alert(ctx, "thread #%d create failed: %s (%d)",
6631681Smax.romanov@nginx.com (int) (i + 1), strerror(res), res);
6641681Smax.romanov@nginx.com }
6651681Smax.romanov@nginx.com }
6661681Smax.romanov@nginx.com
6671681Smax.romanov@nginx.com return NXT_UNIT_OK;
6681681Smax.romanov@nginx.com }
6691681Smax.romanov@nginx.com
6701681Smax.romanov@nginx.com
6711681Smax.romanov@nginx.com static void *
nxt_python_thread_func(void * data)6721681Smax.romanov@nginx.com nxt_python_thread_func(void *data)
6731681Smax.romanov@nginx.com {
6741681Smax.romanov@nginx.com nxt_unit_ctx_t *ctx;
6751681Smax.romanov@nginx.com PyGILState_STATE gstate;
6761681Smax.romanov@nginx.com nxt_py_thread_info_t *ti;
6771681Smax.romanov@nginx.com
6781681Smax.romanov@nginx.com ti = data;
6791681Smax.romanov@nginx.com
6801681Smax.romanov@nginx.com nxt_unit_debug(ti->ctx, "worker thread #%d start",
6811681Smax.romanov@nginx.com (int) (ti - nxt_py_threads + 1));
6821681Smax.romanov@nginx.com
6831681Smax.romanov@nginx.com gstate = PyGILState_Ensure();
6841681Smax.romanov@nginx.com
6851681Smax.romanov@nginx.com if (nxt_py_proto.startup != NULL) {
6861681Smax.romanov@nginx.com if (nxt_py_proto.startup(ti->ctx_data) != NXT_UNIT_OK) {
6871681Smax.romanov@nginx.com goto fail;
6881681Smax.romanov@nginx.com }
6891681Smax.romanov@nginx.com }
6901681Smax.romanov@nginx.com
6911681Smax.romanov@nginx.com ctx = nxt_unit_ctx_alloc(ti->ctx, ti->ctx_data);
6921681Smax.romanov@nginx.com if (nxt_slow_path(ctx == NULL)) {
6931681Smax.romanov@nginx.com goto fail;
6941681Smax.romanov@nginx.com }
6951681Smax.romanov@nginx.com
6961681Smax.romanov@nginx.com (void) nxt_py_proto.run(ctx);
6971681Smax.romanov@nginx.com
6981681Smax.romanov@nginx.com nxt_unit_done(ctx);
6991681Smax.romanov@nginx.com
7001681Smax.romanov@nginx.com fail:
7011681Smax.romanov@nginx.com
7021681Smax.romanov@nginx.com PyGILState_Release(gstate);
7031681Smax.romanov@nginx.com
7041681Smax.romanov@nginx.com nxt_unit_debug(NULL, "worker thread #%d end",
7051681Smax.romanov@nginx.com (int) (ti - nxt_py_threads + 1));
7061681Smax.romanov@nginx.com
7071681Smax.romanov@nginx.com return NULL;
7081681Smax.romanov@nginx.com }
7091681Smax.romanov@nginx.com
7101681Smax.romanov@nginx.com
7111681Smax.romanov@nginx.com static void
nxt_python_join_threads(nxt_unit_ctx_t * ctx,nxt_python_app_conf_t * c)7121681Smax.romanov@nginx.com nxt_python_join_threads(nxt_unit_ctx_t *ctx, nxt_python_app_conf_t *c)
7131681Smax.romanov@nginx.com {
7141681Smax.romanov@nginx.com int res;
7151681Smax.romanov@nginx.com uint32_t i;
7161681Smax.romanov@nginx.com PyThreadState *thread_state;
7171681Smax.romanov@nginx.com nxt_py_thread_info_t *ti;
7181681Smax.romanov@nginx.com
7191681Smax.romanov@nginx.com if (nxt_py_threads == NULL) {
7201681Smax.romanov@nginx.com return;
7211681Smax.romanov@nginx.com }
7221681Smax.romanov@nginx.com
7231681Smax.romanov@nginx.com thread_state = PyEval_SaveThread();
7241681Smax.romanov@nginx.com
7251681Smax.romanov@nginx.com for (i = 0; i < c->threads - 1; i++) {
7261681Smax.romanov@nginx.com ti = &nxt_py_threads[i];
7271681Smax.romanov@nginx.com
7281681Smax.romanov@nginx.com if ((uintptr_t) ti->thread == 0) {
7291681Smax.romanov@nginx.com continue;
7301681Smax.romanov@nginx.com }
7311681Smax.romanov@nginx.com
7321681Smax.romanov@nginx.com res = pthread_join(ti->thread, NULL);
7331681Smax.romanov@nginx.com
7341681Smax.romanov@nginx.com if (nxt_fast_path(res == 0)) {
7351681Smax.romanov@nginx.com nxt_unit_debug(ctx, "thread #%d joined", (int) (i + 1));
7361681Smax.romanov@nginx.com
7371681Smax.romanov@nginx.com } else {
7381681Smax.romanov@nginx.com nxt_unit_alert(ctx, "thread #%d join failed: %s (%d)",
7391681Smax.romanov@nginx.com (int) (i + 1), strerror(res), res);
7401681Smax.romanov@nginx.com }
7411681Smax.romanov@nginx.com }
7421681Smax.romanov@nginx.com
7431681Smax.romanov@nginx.com PyEval_RestoreThread(thread_state);
7441681Smax.romanov@nginx.com
7451681Smax.romanov@nginx.com for (i = 0; i < c->threads - 1; i++) {
7461681Smax.romanov@nginx.com ti = &nxt_py_threads[i];
7471681Smax.romanov@nginx.com
7481681Smax.romanov@nginx.com if (ti->ctx_data != NULL) {
7491681Smax.romanov@nginx.com nxt_py_proto.ctx_data_free(ti->ctx_data);
7501681Smax.romanov@nginx.com }
7511681Smax.romanov@nginx.com }
7521681Smax.romanov@nginx.com
7531681Smax.romanov@nginx.com nxt_unit_free(NULL, nxt_py_threads);
7541681Smax.romanov@nginx.com }
7551681Smax.romanov@nginx.com
7561681Smax.romanov@nginx.com
7571681Smax.romanov@nginx.com int
nxt_python_init_strings(nxt_python_string_t * pstr)7581592Smax.romanov@nginx.com nxt_python_init_strings(nxt_python_string_t *pstr)
7591592Smax.romanov@nginx.com {
7601592Smax.romanov@nginx.com PyObject *obj;
7611592Smax.romanov@nginx.com
7621592Smax.romanov@nginx.com while (pstr->string.start != NULL) {
7631592Smax.romanov@nginx.com obj = PyString_FromStringAndSize((char *) pstr->string.start,
7641592Smax.romanov@nginx.com pstr->string.length);
7651592Smax.romanov@nginx.com if (nxt_slow_path(obj == NULL)) {
7661681Smax.romanov@nginx.com return NXT_UNIT_ERROR;
7671592Smax.romanov@nginx.com }
7681592Smax.romanov@nginx.com
7691592Smax.romanov@nginx.com PyUnicode_InternInPlace(&obj);
7701592Smax.romanov@nginx.com
7711592Smax.romanov@nginx.com *pstr->object_p = obj;
7721592Smax.romanov@nginx.com
7731592Smax.romanov@nginx.com pstr++;
7741592Smax.romanov@nginx.com }
7751592Smax.romanov@nginx.com
7761681Smax.romanov@nginx.com return NXT_UNIT_OK;
7771592Smax.romanov@nginx.com }
7781592Smax.romanov@nginx.com
7791592Smax.romanov@nginx.com
7801592Smax.romanov@nginx.com void
nxt_python_done_strings(nxt_python_string_t * pstr)7811592Smax.romanov@nginx.com nxt_python_done_strings(nxt_python_string_t *pstr)
7821592Smax.romanov@nginx.com {
7831592Smax.romanov@nginx.com PyObject *obj;
7841592Smax.romanov@nginx.com
7851592Smax.romanov@nginx.com while (pstr->string.start != NULL) {
7861592Smax.romanov@nginx.com obj = *pstr->object_p;
7871592Smax.romanov@nginx.com
7881592Smax.romanov@nginx.com Py_XDECREF(obj);
7891592Smax.romanov@nginx.com *pstr->object_p = NULL;
7901592Smax.romanov@nginx.com
7911592Smax.romanov@nginx.com pstr++;
7921592Smax.romanov@nginx.com }
7931592Smax.romanov@nginx.com }
7941592Smax.romanov@nginx.com
7951592Smax.romanov@nginx.com
7961592Smax.romanov@nginx.com static void
nxt_python_atexit(void)7971592Smax.romanov@nginx.com nxt_python_atexit(void)
7981592Smax.romanov@nginx.com {
799*2273Sjeff.iadarola@gmail.com nxt_int_t i;
800*2273Sjeff.iadarola@gmail.com nxt_python_target_t *target;
8011872So.canty@f5.com
8021681Smax.romanov@nginx.com if (nxt_py_proto.done != NULL) {
8031681Smax.romanov@nginx.com nxt_py_proto.done();
8041681Smax.romanov@nginx.com }
8051592Smax.romanov@nginx.com
8061592Smax.romanov@nginx.com Py_XDECREF(nxt_py_stderr_flush);
8071872So.canty@f5.com
8081872So.canty@f5.com if (nxt_py_targets != NULL) {
8091872So.canty@f5.com for (i = 0; i < nxt_py_targets->count; i++) {
810*2273Sjeff.iadarola@gmail.com target = &nxt_py_targets->target[i];
811*2273Sjeff.iadarola@gmail.com
812*2273Sjeff.iadarola@gmail.com Py_XDECREF(target->application);
813*2273Sjeff.iadarola@gmail.com Py_XDECREF(target->py_prefix);
814*2273Sjeff.iadarola@gmail.com
815*2273Sjeff.iadarola@gmail.com nxt_free(target->prefix.start);
8161872So.canty@f5.com }
8171872So.canty@f5.com
8181872So.canty@f5.com nxt_unit_free(NULL, nxt_py_targets);
8191872So.canty@f5.com }
8201592Smax.romanov@nginx.com
8211592Smax.romanov@nginx.com Py_Finalize();
8221592Smax.romanov@nginx.com
8231592Smax.romanov@nginx.com if (nxt_py_home != NULL) {
8241592Smax.romanov@nginx.com nxt_free(nxt_py_home);
8251592Smax.romanov@nginx.com }
8261592Smax.romanov@nginx.com }
8271592Smax.romanov@nginx.com
8281592Smax.romanov@nginx.com
8291592Smax.romanov@nginx.com void
nxt_python_print_exception(void)8301592Smax.romanov@nginx.com nxt_python_print_exception(void)
8311592Smax.romanov@nginx.com {
8321592Smax.romanov@nginx.com PyErr_Print();
8331592Smax.romanov@nginx.com
8341592Smax.romanov@nginx.com #if PY_MAJOR_VERSION == 3
8351592Smax.romanov@nginx.com /* The backtrace may be buffered in sys.stderr file object. */
8361592Smax.romanov@nginx.com {
8371592Smax.romanov@nginx.com PyObject *result;
8381592Smax.romanov@nginx.com
8391592Smax.romanov@nginx.com result = PyObject_CallFunction(nxt_py_stderr_flush, NULL);
8401592Smax.romanov@nginx.com if (nxt_slow_path(result == NULL)) {
8411592Smax.romanov@nginx.com PyErr_Clear();
8421592Smax.romanov@nginx.com return;
8431592Smax.romanov@nginx.com }
8441592Smax.romanov@nginx.com
8451592Smax.romanov@nginx.com Py_DECREF(result);
8461592Smax.romanov@nginx.com }
8471592Smax.romanov@nginx.com #endif
8481592Smax.romanov@nginx.com }
849