nxt_python.c (1624:e46b1b422545) nxt_python.c (1681:542b5b8c0647)
1
2/*
3 * Copyright (C) NGINX, Inc.
4 */
5
6
7#include <Python.h>
8
9#include <nxt_main.h>
10#include <nxt_router.h>
11#include <nxt_unit.h>
12
13#include <python/nxt_python.h>
14
15#include NXT_PYTHON_MOUNTS_H
16
17
1
2/*
3 * Copyright (C) NGINX, Inc.
4 */
5
6
7#include <Python.h>
8
9#include <nxt_main.h>
10#include <nxt_router.h>
11#include <nxt_unit.h>
12
13#include <python/nxt_python.h>
14
15#include NXT_PYTHON_MOUNTS_H
16
17
18typedef struct {
19 pthread_t thread;
20 nxt_unit_ctx_t *ctx;
21 void *ctx_data;
22} nxt_py_thread_info_t;
23
24
18static nxt_int_t nxt_python_start(nxt_task_t *task,
19 nxt_process_data_t *data);
25static nxt_int_t nxt_python_start(nxt_task_t *task,
26 nxt_process_data_t *data);
27static int nxt_python_init_threads(nxt_python_app_conf_t *c);
28static int nxt_python_ready_handler(nxt_unit_ctx_t *ctx);
29static void *nxt_python_thread_func(void *main_ctx);
30static void nxt_python_join_threads(nxt_unit_ctx_t *ctx,
31 nxt_python_app_conf_t *c);
20static void nxt_python_atexit(void);
21
22static uint32_t compat[] = {
23 NXT_VERNUM, NXT_DEBUG,
24};
25
26
27NXT_EXPORT nxt_app_module_t nxt_app_module = {

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

39PyObject *nxt_py_application;
40
41#if PY_MAJOR_VERSION == 3
42static wchar_t *nxt_py_home;
43#else
44static char *nxt_py_home;
45#endif
46
32static void nxt_python_atexit(void);
33
34static uint32_t compat[] = {
35 NXT_VERNUM, NXT_DEBUG,
36};
37
38
39NXT_EXPORT nxt_app_module_t nxt_app_module = {

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

51PyObject *nxt_py_application;
52
53#if PY_MAJOR_VERSION == 3
54static wchar_t *nxt_py_home;
55#else
56static char *nxt_py_home;
57#endif
58
59static pthread_attr_t *nxt_py_thread_attr;
60static nxt_py_thread_info_t *nxt_py_threads;
61static nxt_python_proto_t nxt_py_proto;
47
62
63
48static nxt_int_t
49nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
50{
64static nxt_int_t
65nxt_python_start(nxt_task_t *task, nxt_process_data_t *data)
66{
51 int rc, asgi;
67 int rc;
52 char *nxt_py_module;
53 size_t len;
54 PyObject *obj, *pypath, *module;
55 const char *callable;
56 nxt_unit_ctx_t *unit_ctx;
57 nxt_unit_init_t python_init;
58 nxt_common_app_conf_t *app_conf;
59 nxt_python_app_conf_t *c;

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

119
120 nxt_memcpy(nxt_py_home, c->home, len + 1);
121 Py_SetPythonHome(nxt_py_home);
122#endif
123 }
124
125 Py_InitializeEx(0);
126
68 char *nxt_py_module;
69 size_t len;
70 PyObject *obj, *pypath, *module;
71 const char *callable;
72 nxt_unit_ctx_t *unit_ctx;
73 nxt_unit_init_t python_init;
74 nxt_common_app_conf_t *app_conf;
75 nxt_python_app_conf_t *c;

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

135
136 nxt_memcpy(nxt_py_home, c->home, len + 1);
137 Py_SetPythonHome(nxt_py_home);
138#endif
139 }
140
141 Py_InitializeEx(0);
142
143#if PY_VERSION_HEX < NXT_PYTHON_VER(3, 7)
144 if (c->threads > 1) {
145 PyEval_InitThreads();
146 }
147#endif
148
127 module = NULL;
128 obj = NULL;
129
149 module = NULL;
150 obj = NULL;
151
152 python_init.ctx_data = NULL;
153
130 obj = PySys_GetObject((char *) "stderr");
131 if (nxt_slow_path(obj == NULL)) {
132 nxt_alert(task, "Python failed to get \"sys.stderr\" object");
133 goto fail;
134 }
135
136 nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush");
137 if (nxt_slow_path(nxt_py_stderr_flush == NULL)) {

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

211 obj = NULL;
212
213 Py_INCREF(nxt_py_application);
214
215 Py_CLEAR(module);
216
217 nxt_unit_default_init(task, &python_init);
218
154 obj = PySys_GetObject((char *) "stderr");
155 if (nxt_slow_path(obj == NULL)) {
156 nxt_alert(task, "Python failed to get \"sys.stderr\" object");
157 goto fail;
158 }
159
160 nxt_py_stderr_flush = PyObject_GetAttrString(obj, "flush");
161 if (nxt_slow_path(nxt_py_stderr_flush == NULL)) {

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

235 obj = NULL;
236
237 Py_INCREF(nxt_py_application);
238
239 Py_CLEAR(module);
240
241 nxt_unit_default_init(task, &python_init);
242
243 python_init.data = c;
219 python_init.shm_limit = data->app->shm_limit;
244 python_init.shm_limit = data->app->shm_limit;
245 python_init.callbacks.ready_handler = nxt_python_ready_handler;
220
246
221 asgi = nxt_python_asgi_check(nxt_py_application);
247 if (nxt_python_asgi_check(nxt_py_application)) {
248 rc = nxt_python_asgi_init(&python_init, &nxt_py_proto);
222
249
223 if (asgi) {
224 rc = nxt_python_asgi_init(task, &python_init);
225
226 } else {
250 } else {
227 rc = nxt_python_wsgi_init(task, &python_init);
251 rc = nxt_python_wsgi_init(&python_init, &nxt_py_proto);
228 }
229
252 }
253
230 if (nxt_slow_path(rc == NXT_ERROR)) {
254 if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
231 goto fail;
232 }
233
255 goto fail;
256 }
257
258 rc = nxt_py_proto.ctx_data_alloc(&python_init.ctx_data);
259 if (nxt_slow_path(rc != NXT_UNIT_OK)) {
260 goto fail;
261 }
262
263 rc = nxt_python_init_threads(c);
264 if (nxt_slow_path(rc == NXT_UNIT_ERROR)) {
265 goto fail;
266 }
267
268 if (nxt_py_proto.startup != NULL) {
269 if (nxt_py_proto.startup(python_init.ctx_data) != NXT_UNIT_OK) {
270 goto fail;
271 }
272 }
273
234 unit_ctx = nxt_unit_init(&python_init);
235 if (nxt_slow_path(unit_ctx == NULL)) {
236 goto fail;
237 }
238
274 unit_ctx = nxt_unit_init(&python_init);
275 if (nxt_slow_path(unit_ctx == NULL)) {
276 goto fail;
277 }
278
239 if (asgi) {
240 rc = nxt_python_asgi_run(unit_ctx);
279 rc = nxt_py_proto.run(unit_ctx);
241
280
242 } else {
243 rc = nxt_python_wsgi_run(unit_ctx);
244 }
281 nxt_python_join_threads(unit_ctx, c);
245
246 nxt_unit_done(unit_ctx);
247
282
283 nxt_unit_done(unit_ctx);
284
285 nxt_py_proto.ctx_data_free(python_init.ctx_data);
286
248 nxt_python_atexit();
249
250 exit(rc);
251
252 return NXT_OK;
253
254fail:
255
287 nxt_python_atexit();
288
289 exit(rc);
290
291 return NXT_OK;
292
293fail:
294
295 nxt_python_join_threads(NULL, c);
296
297 if (python_init.ctx_data != NULL) {
298 nxt_py_proto.ctx_data_free(python_init.ctx_data);
299 }
300
256 Py_XDECREF(obj);
257 Py_XDECREF(module);
258
259 nxt_python_atexit();
260
261 return NXT_ERROR;
262}
263
264
301 Py_XDECREF(obj);
302 Py_XDECREF(module);
303
304 nxt_python_atexit();
305
306 return NXT_ERROR;
307}
308
309
265nxt_int_t
310static int
311nxt_python_init_threads(nxt_python_app_conf_t *c)
312{
313 int res;
314 uint32_t i;
315 nxt_py_thread_info_t *ti;
316 static pthread_attr_t attr;
317
318 if (c->threads <= 1) {
319 return NXT_UNIT_OK;
320 }
321
322 if (c->thread_stack_size > 0) {
323 res = pthread_attr_init(&attr);
324 if (nxt_slow_path(res != 0)) {
325 nxt_unit_alert(NULL, "thread attr init failed: %s (%d)",
326 strerror(res), res);
327
328 return NXT_UNIT_ERROR;
329 }
330
331 res = pthread_attr_setstacksize(&attr, c->thread_stack_size);
332 if (nxt_slow_path(res != 0)) {
333 nxt_unit_alert(NULL, "thread attr set stack size failed: %s (%d)",
334 strerror(res), res);
335
336 return NXT_UNIT_ERROR;
337 }
338
339 nxt_py_thread_attr = &attr;
340 }
341
342 nxt_py_threads = nxt_unit_malloc(NULL, sizeof(nxt_py_thread_info_t)
343 * (c->threads - 1));
344 if (nxt_slow_path(nxt_py_threads == NULL)) {
345 nxt_unit_alert(NULL, "Failed to allocate thread info array");
346
347 return NXT_UNIT_ERROR;
348 }
349
350 memset(nxt_py_threads, 0, sizeof(nxt_py_thread_info_t) * (c->threads - 1));
351
352 for (i = 0; i < c->threads - 1; i++) {
353 ti = &nxt_py_threads[i];
354
355 res = nxt_py_proto.ctx_data_alloc(&ti->ctx_data);
356 if (nxt_slow_path(res != NXT_UNIT_OK)) {
357 return NXT_UNIT_ERROR;
358 }
359 }
360
361 return NXT_UNIT_OK;
362}
363
364
365static int
366nxt_python_ready_handler(nxt_unit_ctx_t *ctx)
367{
368 int res;
369 uint32_t i;
370 nxt_py_thread_info_t *ti;
371 nxt_python_app_conf_t *c;
372
373 if (nxt_py_proto.ready != NULL) {
374 res = nxt_py_proto.ready(ctx);
375 if (nxt_slow_path(res != NXT_UNIT_OK)) {
376 return NXT_UNIT_ERROR;
377 }
378 }
379
380 /* Worker thread context. */
381 if (!nxt_unit_is_main_ctx(ctx)) {
382 return NXT_UNIT_OK;
383 }
384
385 c = ctx->unit->data;
386
387 if (c->threads <= 1) {
388 return NXT_UNIT_OK;
389 }
390
391 for (i = 0; i < c->threads - 1; i++) {
392 ti = &nxt_py_threads[i];
393
394 ti->ctx = ctx;
395
396 res = pthread_create(&ti->thread, nxt_py_thread_attr,
397 nxt_python_thread_func, ti);
398
399 if (nxt_fast_path(res == 0)) {
400 nxt_unit_debug(ctx, "thread #%d created", (int) (i + 1));
401
402 } else {
403 nxt_unit_alert(ctx, "thread #%d create failed: %s (%d)",
404 (int) (i + 1), strerror(res), res);
405 }
406 }
407
408 return NXT_UNIT_OK;
409}
410
411
412static void *
413nxt_python_thread_func(void *data)
414{
415 nxt_unit_ctx_t *ctx;
416 PyGILState_STATE gstate;
417 nxt_py_thread_info_t *ti;
418
419 ti = data;
420
421 nxt_unit_debug(ti->ctx, "worker thread #%d start",
422 (int) (ti - nxt_py_threads + 1));
423
424 gstate = PyGILState_Ensure();
425
426 if (nxt_py_proto.startup != NULL) {
427 if (nxt_py_proto.startup(ti->ctx_data) != NXT_UNIT_OK) {
428 goto fail;
429 }
430 }
431
432 ctx = nxt_unit_ctx_alloc(ti->ctx, ti->ctx_data);
433 if (nxt_slow_path(ctx == NULL)) {
434 goto fail;
435 }
436
437 (void) nxt_py_proto.run(ctx);
438
439 nxt_unit_done(ctx);
440
441fail:
442
443 PyGILState_Release(gstate);
444
445 nxt_unit_debug(NULL, "worker thread #%d end",
446 (int) (ti - nxt_py_threads + 1));
447
448 return NULL;
449}
450
451
452static void
453nxt_python_join_threads(nxt_unit_ctx_t *ctx, nxt_python_app_conf_t *c)
454{
455 int res;
456 uint32_t i;
457 PyThreadState *thread_state;
458 nxt_py_thread_info_t *ti;
459
460 if (nxt_py_threads == NULL) {
461 return;
462 }
463
464 thread_state = PyEval_SaveThread();
465
466 for (i = 0; i < c->threads - 1; i++) {
467 ti = &nxt_py_threads[i];
468
469 if ((uintptr_t) ti->thread == 0) {
470 continue;
471 }
472
473 res = pthread_join(ti->thread, NULL);
474
475 if (nxt_fast_path(res == 0)) {
476 nxt_unit_debug(ctx, "thread #%d joined", (int) (i + 1));
477
478 } else {
479 nxt_unit_alert(ctx, "thread #%d join failed: %s (%d)",
480 (int) (i + 1), strerror(res), res);
481 }
482 }
483
484 PyEval_RestoreThread(thread_state);
485
486 for (i = 0; i < c->threads - 1; i++) {
487 ti = &nxt_py_threads[i];
488
489 if (ti->ctx_data != NULL) {
490 nxt_py_proto.ctx_data_free(ti->ctx_data);
491 }
492 }
493
494 nxt_unit_free(NULL, nxt_py_threads);
495}
496
497
498int
266nxt_python_init_strings(nxt_python_string_t *pstr)
267{
268 PyObject *obj;
269
270 while (pstr->string.start != NULL) {
271 obj = PyString_FromStringAndSize((char *) pstr->string.start,
272 pstr->string.length);
273 if (nxt_slow_path(obj == NULL)) {
499nxt_python_init_strings(nxt_python_string_t *pstr)
500{
501 PyObject *obj;
502
503 while (pstr->string.start != NULL) {
504 obj = PyString_FromStringAndSize((char *) pstr->string.start,
505 pstr->string.length);
506 if (nxt_slow_path(obj == NULL)) {
274 return NXT_ERROR;
507 return NXT_UNIT_ERROR;
275 }
276
277 PyUnicode_InternInPlace(&obj);
278
279 *pstr->object_p = obj;
280
281 pstr++;
282 }
283
508 }
509
510 PyUnicode_InternInPlace(&obj);
511
512 *pstr->object_p = obj;
513
514 pstr++;
515 }
516
284 return NXT_OK;
517 return NXT_UNIT_OK;
285}
286
287
288void
289nxt_python_done_strings(nxt_python_string_t *pstr)
290{
291 PyObject *obj;
292

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

299 pstr++;
300 }
301}
302
303
304static void
305nxt_python_atexit(void)
306{
518}
519
520
521void
522nxt_python_done_strings(nxt_python_string_t *pstr)
523{
524 PyObject *obj;
525

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

532 pstr++;
533 }
534}
535
536
537static void
538nxt_python_atexit(void)
539{
307 nxt_python_wsgi_done();
308 nxt_python_asgi_done();
540 if (nxt_py_proto.done != NULL) {
541 nxt_py_proto.done();
542 }
309
310 Py_XDECREF(nxt_py_stderr_flush);
311 Py_XDECREF(nxt_py_application);
312
313 Py_Finalize();
314
315 if (nxt_py_home != NULL) {
316 nxt_free(nxt_py_home);

--- 24 unchanged lines hidden ---
543
544 Py_XDECREF(nxt_py_stderr_flush);
545 Py_XDECREF(nxt_py_application);
546
547 Py_Finalize();
548
549 if (nxt_py_home != NULL) {
550 nxt_free(nxt_py_home);

--- 24 unchanged lines hidden ---