nxt_python.c (1759:196b4d90c8cc) nxt_python.c (1872:9f8df8b810e0)
1
2/*
3 * Copyright (C) NGINX, Inc.
4 */
5
6
7#include <Python.h>
8

--- 10 unchanged lines hidden (view full) ---

19 pthread_t thread;
20 nxt_unit_ctx_t *ctx;
21 void *ctx_data;
22} nxt_py_thread_info_t;
23
24
25static nxt_int_t nxt_python_start(nxt_task_t *task,
26 nxt_process_data_t *data);
1
2/*
3 * Copyright (C) NGINX, Inc.
4 */
5
6
7#include <Python.h>
8

--- 10 unchanged lines hidden (view full) ---

19 pthread_t thread;
20 nxt_unit_ctx_t *ctx;
21 void *ctx_data;
22} nxt_py_thread_info_t;
23
24
25static nxt_int_t nxt_python_start(nxt_task_t *task,
26 nxt_process_data_t *data);
27static nxt_int_t nxt_python_set_target(nxt_task_t *task,
28 nxt_python_target_t *target, nxt_conf_value_t *conf);
27static nxt_int_t nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value);
28static int nxt_python_init_threads(nxt_python_app_conf_t *c);
29static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx);
30static void *nxt_python_thread_func(void *main_ctx);
31static void nxt_python_join_threads(nxt_unit_ctx_t *ctx,
32 nxt_python_app_conf_t *c);
33static void nxt_python_atexit(void);
34

--- 9 unchanged lines hidden (view full) ---

44 PY_VERSION,
45 nxt_python_mounts,
46 nxt_nitems(nxt_python_mounts),
47 NULL,
48 nxt_python_start,
49};
50
51static PyObject *nxt_py_stderr_flush;
29static nxt_int_t nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value);
30static int nxt_python_init_threads(nxt_python_app_conf_t *c);
31static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx);
32static void *nxt_python_thread_func(void *main_ctx);
33static void nxt_python_join_threads(nxt_unit_ctx_t *ctx,
34 nxt_python_app_conf_t *c);
35static void nxt_python_atexit(void);
36

--- 9 unchanged lines hidden (view full) ---

46 PY_VERSION,
47 nxt_python_mounts,
48 nxt_nitems(nxt_python_mounts),
49 NULL,
50 nxt_python_start,
51};
52
53static PyObject *nxt_py_stderr_flush;
52PyObject *nxt_py_application;
54nxt_python_targets_t *nxt_py_targets;
53
54#if PY_MAJOR_VERSION == 3
55static wchar_t *nxt_py_home;
56#else
57static char *nxt_py_home;
58#endif
59
60static pthread_attr_t *nxt_py_thread_attr;
61static nxt_py_thread_info_t *nxt_py_threads;
62static nxt_python_proto_t nxt_py_proto;
63
64
65static nxt_int_t
66nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
67{
68 int rc;
55
56#if PY_MAJOR_VERSION == 3
57static wchar_t *nxt_py_home;
58#else
59static char *nxt_py_home;
60#endif
61
62static pthread_attr_t *nxt_py_thread_attr;
63static nxt_py_thread_info_t *nxt_py_threads;
64static nxt_python_proto_t nxt_py_proto;
65
66
67static nxt_int_t
68nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
69{
70 int rc;
69 char *nxt_py_module;
70 size_t len;
71 size_t len, size;
72 uint32_t next;
71 PyObject *obj, *module;
73 PyObject *obj, *module;
72 nxt_str_t proto;
73 const char *callable;
74 nxt_str_t proto, probe_proto, name;
75 nxt_int_t ret, n, i;
74 nxt_unit_ctx_t *unit_ctx;
75 nxt_unit_init_t python_init;
76 nxt_unit_ctx_t *unit_ctx;
77 nxt_unit_init_t python_init;
78 nxt_conf_value_t *cv;
79 nxt_python_targets_t *targets;
76 nxt_common_app_conf_t *app_conf;
77 nxt_python_app_conf_t *c;
78#if PY_MAJOR_VERSION == 3
79 char *path;
80 nxt_common_app_conf_t *app_conf;
81 nxt_python_app_conf_t *c;
82#if PY_MAJOR_VERSION == 3
83 char *path;
80 size_t size;
81 nxt_int_t pep405;
82
83 static const char pyvenv[] = "/pyvenv.cfg";
84 static const char bin_python[] = "/bin/python";
85#endif
86
87 static const nxt_str_t wsgi = nxt_string("wsgi");
88 static const nxt_str_t asgi = nxt_string("asgi");

--- 96 unchanged lines hidden (view full) ---

185
186 if (nxt_slow_path(PySys_SetObject((char *) "argv", obj) != 0)) {
187 nxt_alert(task, "Python failed to set the \"sys.argv\" list");
188 goto fail;
189 }
190
191 Py_CLEAR(obj);
192
84 nxt_int_t pep405;
85
86 static const char pyvenv[] = "/pyvenv.cfg";
87 static const char bin_python[] = "/bin/python";
88#endif
89
90 static const nxt_str_t wsgi = nxt_string("wsgi");
91 static const nxt_str_t asgi = nxt_string("asgi");

--- 96 unchanged lines hidden (view full) ---

188
189 if (nxt_slow_path(PySys_SetObject((char *) "argv", obj) != 0)) {
190 nxt_alert(task, "Python failed to set the \"sys.argv\" list");
191 goto fail;
192 }
193
194 Py_CLEAR(obj);
195
193 nxt_py_module = nxt_alloca(c->module.length + 1);
194 nxt_memcpy(nxt_py_module, c->module.start, c->module.length);
195 nxt_py_module[c->module.length] = '\0';
196 n = (c->targets != NULL ? nxt_conf_object_members_count(c->targets) : 1);
196
197
197 module = PyImport_ImportModule(nxt_py_module);
198 if (nxt_slow_path(module == NULL)) {
199 nxt_alert(task, "Python failed to import module \"%s\"", nxt_py_module);
200 nxt_python_print_exception();
198 size = sizeof(nxt_python_targets_t) + n * sizeof(nxt_python_target_t);
199
200 targets = nxt_unit_malloc(NULL, size);
201 if (nxt_slow_path(targets == NULL)) {
202 nxt_alert(task, "Could not allocate targets");
201 goto fail;
202 }
203
203 goto fail;
204 }
205
204 callable = (c->callable != NULL) ? c->callable : "application";
206 memset(targets, 0, size);
205
207
206 obj = PyDict_GetItemString(PyModule_GetDict(module), callable);
207 if (nxt_slow_path(obj == NULL)) {
208 nxt_alert(task, "Python failed to get \"%s\" "
209 "from module \"%s\"", callable, nxt_py_module);
210 goto fail;
211 }
208 targets->count = n;
209 nxt_py_targets = targets;
212
210
213 if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
214 nxt_alert(task, "\"%s\" in module \"%s\" "
215 "is not a callable object", callable, nxt_py_module);
216 goto fail;
217 }
211 if (c->targets != NULL) {
212 next = 0;
218
213
219 nxt_py_application = obj;
220 obj = NULL;
214 for (i = 0; /* void */; i++) {
215 cv = nxt_conf_next_object_member(c->targets, &name, &next);
216 if (cv == NULL) {
217 break;
218 }
221
219
222 Py_INCREF(nxt_py_application);
220 ret = nxt_python_set_target(task, &targets->target[i], cv);
221 if (nxt_slow_path(ret != NXT_OK)) {
222 goto fail;
223 }
224 }
223
225
224 Py_CLEAR(module);
226 } else {
227 ret = nxt_python_set_target(task, &targets->target[0], app_conf->self);
228 if (nxt_slow_path(ret != NXT_OK)) {
229 goto fail;
230 }
231 }
225
226 nxt_unit_default_init(task, &python_init);
227
228 python_init.data = c;
229 python_init.shm_limit = data->app->shm_limit;
230 python_init.callbacks.ready_handler = nxt_python_ready_handler;
231
232 proto = c->protocol;
233
234 if (proto.length == 0) {
232
233 nxt_unit_default_init(task, &python_init);
234
235 python_init.data = c;
236 python_init.shm_limit = data->app->shm_limit;
237 python_init.callbacks.ready_handler = nxt_python_ready_handler;
238
239 proto = c->protocol;
240
241 if (proto.length == 0) {
235 proto = nxt_python_asgi_check(nxt_py_application) ? asgi : wsgi;
242 proto = nxt_python_asgi_check(targets->target[0].application)
243 ? asgi : wsgi;
244
245 for (i = 1; i < targets->count; i++) {
246 probe_proto = nxt_python_asgi_check(targets->target[i].application)
247 ? asgi : wsgi;
248 if (probe_proto.start != proto.start) {
249 nxt_alert(task, "A mix of ASGI & WSGI targets is forbidden, "
250 "specify protocol in config if incorrect");
251 goto fail;
252 }
253 }
236 }
237
238 if (nxt_strstr_eq(&proto, &asgi)) {
239 rc = nxt_python_asgi_init(&python_init, &nxt_py_proto);
240
241 } else {
242 rc = nxt_python_wsgi_init(&python_init, &nxt_py_proto);
243 }

--- 50 unchanged lines hidden (view full) ---

294
295 nxt_python_atexit();
296
297 return NXT_ERROR;
298}
299
300
301static nxt_int_t
254 }
255
256 if (nxt_strstr_eq(&proto, &asgi)) {
257 rc = nxt_python_asgi_init(&python_init, &nxt_py_proto);
258
259 } else {
260 rc = nxt_python_wsgi_init(&python_init, &nxt_py_proto);
261 }

--- 50 unchanged lines hidden (view full) ---

312
313 nxt_python_atexit();
314
315 return NXT_ERROR;
316}
317
318
319static nxt_int_t
320nxt_python_set_target(nxt_task_t *task, nxt_python_target_t *target,
321 nxt_conf_value_t *conf)
322{
323 char *callable, *module_name;
324 PyObject *module, *obj;
325 nxt_str_t str;
326 nxt_conf_value_t *value;
327
328 static nxt_str_t module_str = nxt_string("module");
329 static nxt_str_t callable_str = nxt_string("callable");
330
331 module = obj = NULL;
332
333 value = nxt_conf_get_object_member(conf, &module_str, NULL);
334 if (nxt_slow_path(value == NULL)) {
335 goto fail;
336 }
337
338 nxt_conf_get_string(value, &str);
339
340 module_name = nxt_alloca(str.length + 1);
341 nxt_memcpy(module_name, str.start, str.length);
342 module_name[str.length] = '\0';
343
344 module = PyImport_ImportModule(module_name);
345 if (nxt_slow_path(module == NULL)) {
346 nxt_alert(task, "Python failed to import module \"%s\"", module_name);
347 nxt_python_print_exception();
348 goto fail;
349 }
350
351 value = nxt_conf_get_object_member(conf, &callable_str, NULL);
352 if (value == NULL) {
353 callable = nxt_alloca(12);
354 nxt_memcpy(callable, "application", 12);
355
356 } else {
357 nxt_conf_get_string(value, &str);
358
359 callable = nxt_alloca(str.length + 1);
360 nxt_memcpy(callable, str.start, str.length);
361 callable[str.length] = '\0';
362 }
363
364 obj = PyDict_GetItemString(PyModule_GetDict(module), callable);
365 if (nxt_slow_path(obj == NULL)) {
366 nxt_alert(task, "Python failed to get \"%s\" from module \"%s\"",
367 callable, module);
368 goto fail;
369 }
370
371 if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
372 nxt_alert(task, "\"%s\" in module \"%s\" is not a callable object",
373 callable, module);
374 goto fail;
375 }
376
377 target->application = obj;
378 obj = NULL;
379
380 Py_INCREF(target->application);
381 Py_CLEAR(module);
382
383 return NXT_OK;
384
385fail:
386
387 Py_XDECREF(obj);
388 Py_XDECREF(module);
389
390 return NXT_ERROR;
391}
392
393
394static nxt_int_t
302nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value)
303{
304 int ret;
305 PyObject *path, *sys;
306 nxt_str_t str;
307 nxt_uint_t n;
308 nxt_conf_value_t *array;
309

--- 281 unchanged lines hidden (view full) ---

591 pstr++;
592 }
593}
594
595
596static void
597nxt_python_atexit(void)
598{
395nxt_python_set_path(nxt_task_t *task, nxt_conf_value_t *value)
396{
397 int ret;
398 PyObject *path, *sys;
399 nxt_str_t str;
400 nxt_uint_t n;
401 nxt_conf_value_t *array;
402

--- 281 unchanged lines hidden (view full) ---

684 pstr++;
685 }
686}
687
688
689static void
690nxt_python_atexit(void)
691{
692 nxt_int_t i;
693
599 if (nxt_py_proto.done != NULL) {
600 nxt_py_proto.done();
601 }
602
603 Py_XDECREF(nxt_py_stderr_flush);
694 if (nxt_py_proto.done != NULL) {
695 nxt_py_proto.done();
696 }
697
698 Py_XDECREF(nxt_py_stderr_flush);
604 Py_XDECREF(nxt_py_application);
605
699
700 if (nxt_py_targets != NULL) {
701 for (i = 0; i < nxt_py_targets->count; i++) {
702 Py_XDECREF(nxt_py_targets->target[i].application);
703 }
704
705 nxt_unit_free(NULL, nxt_py_targets);
706 }
707
606 Py_Finalize();
607
608 if (nxt_py_home != NULL) {
609 nxt_free(nxt_py_home);
610 }
611}
612
613

--- 20 unchanged lines hidden ---
708 Py_Finalize();
709
710 if (nxt_py_home != NULL) {
711 nxt_free(nxt_py_home);
712 }
713}
714
715

--- 20 unchanged lines hidden ---