Skip to content

Commit 3cb131b

Browse files
authored
asgi context alloc and free up depending on asyncio runner identifier
1 parent dc23781 commit 3cb131b

File tree

1 file changed

+145
-2
lines changed

1 file changed

+145
-2
lines changed

src/python/nxt_python_asgi.c

Lines changed: 145 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -199,8 +199,7 @@ nxt_python_asgi_init(nxt_unit_init_t *init, nxt_python_proto_t *proto)
199199

200200
return NXT_UNIT_OK;
201201
}
202-
203-
202+
#if NXT_HAVE_ASYNCIO_RUNNER
204203
static int
205204
nxt_python_asgi_ctx_data_alloc(void **pdata, int main)
206205
{
@@ -346,6 +345,150 @@ nxt_python_asgi_ctx_data_free(void *data)
346345

347346
nxt_unit_free(NULL, ctx_data);
348347
}
348+
#else
349+
350+
static int
351+
nxt_python_asgi_ctx_data_alloc(void **pdata, int main)
352+
{
353+
uint32_t i;
354+
PyObject *asyncio, *loop, *event_loop, *obj;
355+
const char *event_loop_func;
356+
nxt_py_asgi_ctx_data_t *ctx_data;
357+
358+
ctx_data = nxt_unit_malloc(NULL, sizeof(nxt_py_asgi_ctx_data_t));
359+
if (nxt_slow_path(ctx_data == NULL)) {
360+
nxt_unit_alert(NULL, "Failed to allocate context data");
361+
return NXT_UNIT_ERROR;
362+
}
363+
364+
memset(ctx_data, 0, sizeof(nxt_py_asgi_ctx_data_t));
365+
366+
nxt_queue_init(&ctx_data->drain_queue);
367+
368+
struct {
369+
const char *key;
370+
PyObject **handler;
371+
372+
} handlers[] = {
373+
{ "create_task", &ctx_data->loop_create_task },
374+
{ "add_reader", &ctx_data->loop_add_reader },
375+
{ "remove_reader", &ctx_data->loop_remove_reader },
376+
{ "call_soon", &ctx_data->loop_call_soon },
377+
{ "run_until_complete", &ctx_data->loop_run_until_complete },
378+
{ "create_future", &ctx_data->loop_create_future },
379+
};
380+
381+
loop = NULL;
382+
383+
asyncio = PyImport_ImportModule("asyncio");
384+
if (nxt_slow_path(asyncio == NULL)) {
385+
nxt_unit_alert(NULL, "Python failed to import module 'asyncio'");
386+
nxt_python_print_exception();
387+
goto fail;
388+
}
389+
390+
event_loop_func = main ? "get_event_loop" : "new_event_loop";
391+
392+
event_loop = PyDict_GetItemString(PyModule_GetDict(asyncio),
393+
event_loop_func);
394+
if (nxt_slow_path(event_loop == NULL)) {
395+
nxt_unit_alert(NULL,
396+
"Python failed to get '%s' from module 'asyncio'",
397+
event_loop_func);
398+
goto fail;
399+
}
400+
401+
if (nxt_slow_path(PyCallable_Check(event_loop) == 0)) {
402+
nxt_unit_alert(NULL,
403+
"'asyncio.%s' is not a callable object",
404+
event_loop_func);
405+
goto fail;
406+
}
407+
408+
loop = PyObject_CallObject(event_loop, NULL);
409+
if (nxt_slow_path(loop == NULL)) {
410+
nxt_unit_alert(NULL, "Python failed to call 'asyncio.%s'",
411+
event_loop_func);
412+
goto fail;
413+
}
414+
415+
for (i = 0; i < nxt_nitems(handlers); i++) {
416+
obj = PyObject_GetAttrString(loop, handlers[i].key);
417+
if (nxt_slow_path(obj == NULL)) {
418+
nxt_unit_alert(NULL, "Python failed to get 'loop.%s'",
419+
handlers[i].key);
420+
goto fail;
421+
}
422+
423+
*handlers[i].handler = obj;
424+
425+
if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
426+
nxt_unit_alert(NULL, "'loop.%s' is not a callable object",
427+
handlers[i].key);
428+
goto fail;
429+
}
430+
}
431+
432+
obj = PyObject_CallObject(ctx_data->loop_create_future, NULL);
433+
if (nxt_slow_path(obj == NULL)) {
434+
nxt_unit_alert(NULL, "Python failed to create Future ");
435+
nxt_python_print_exception();
436+
goto fail;
437+
}
438+
439+
ctx_data->quit_future = obj;
440+
441+
obj = PyObject_GetAttrString(ctx_data->quit_future, "set_result");
442+
if (nxt_slow_path(obj == NULL)) {
443+
nxt_unit_alert(NULL, "Python failed to get 'future.set_result'");
444+
goto fail;
445+
}
446+
447+
ctx_data->quit_future_set_result = obj;
448+
449+
if (nxt_slow_path(PyCallable_Check(obj) == 0)) {
450+
nxt_unit_alert(NULL, "'future.set_result' is not a callable object");
451+
goto fail;
452+
}
453+
454+
Py_DECREF(loop);
455+
Py_DECREF(asyncio);
456+
457+
*pdata = ctx_data;
458+
459+
return NXT_UNIT_OK;
460+
461+
fail:
462+
463+
nxt_python_asgi_ctx_data_free(ctx_data);
464+
465+
Py_XDECREF(loop);
466+
Py_XDECREF(asyncio);
467+
468+
return NXT_UNIT_ERROR;
469+
}
470+
471+
472+
static void
473+
nxt_python_asgi_ctx_data_free(void *data)
474+
{
475+
nxt_py_asgi_ctx_data_t *ctx_data;
476+
477+
ctx_data = data;
478+
479+
Py_XDECREF(ctx_data->loop_run_until_complete);
480+
Py_XDECREF(ctx_data->loop_create_future);
481+
Py_XDECREF(ctx_data->loop_create_task);
482+
Py_XDECREF(ctx_data->loop_call_soon);
483+
Py_XDECREF(ctx_data->loop_add_reader);
484+
Py_XDECREF(ctx_data->loop_remove_reader);
485+
Py_XDECREF(ctx_data->quit_future);
486+
Py_XDECREF(ctx_data->quit_future_set_result);
487+
488+
nxt_unit_free(NULL, ctx_data);
489+
}
490+
#endif
491+
349492

350493

351494
static int

0 commit comments

Comments
 (0)