Skip to content

Commit 734fe91

Browse files
committed
Solved deadlock in python windows.
1 parent 1447a08 commit 734fe91

File tree

5 files changed

+53
-7
lines changed

5 files changed

+53
-7
lines changed

source/loaders/py_loader/include/py_loader/py_loader_impl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ PY_LOADER_NO_EXPORT int py_loader_impl_finalizer_object(loader_impl impl, PyObje
6262

6363
PY_LOADER_NO_EXPORT PyObject *py_loader_impl_capsule_new_null(void);
6464

65+
PY_LOADER_NO_EXPORT int py_loader_impl_initialize_asyncio_module(loader_impl_py py_impl, const int host);
66+
6567
#ifdef __cplusplus
6668
}
6769
#endif

source/loaders/py_loader/source/py_loader_impl.c

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2610,7 +2610,12 @@ int py_loader_impl_initialize_argv(loader_impl_py py_impl, int argc, char **argv
26102610

26112611
static void PyCFunction_dealloc(PyObject *obj)
26122612
{
2613-
py_loader_thread_acquire();
2613+
const int gil_status = PyGILState_Check();
2614+
2615+
if (gil_status == 0)
2616+
{
2617+
py_loader_thread_acquire();
2618+
}
26142619

26152620
/* Check if we are passing our own hook to the callback */
26162621
if (PyCFunction_Check(obj) && PyCFunction_GET_FUNCTION(obj) == py_loader_impl_function_type_invoke)
@@ -2624,6 +2629,7 @@ static void PyCFunction_dealloc(PyObject *obj)
26242629

26252630
loader_impl_py_function_type_invoke_state invoke_state = PyCapsule_GetPointer(invoke_state_capsule, NULL);
26262631

2632+
/* Release the GIL and let the destroy be executed outside of Python (if it belongs to another language) */
26272633
py_loader_thread_release();
26282634
value_type_destroy(invoke_state->callback);
26292635
py_loader_thread_acquire();
@@ -2636,7 +2642,10 @@ static void PyCFunction_dealloc(PyObject *obj)
26362642
/* Call to the original meth_dealloc function */
26372643
py_loader_impl_pycfunction_dealloc(obj);
26382644

2639-
py_loader_thread_release();
2645+
if (gil_status == 0)
2646+
{
2647+
py_loader_thread_release();
2648+
}
26402649
}
26412650

26422651
loader_impl_data py_loader_impl_initialize(loader_impl impl, configuration config)
@@ -2760,10 +2769,16 @@ loader_impl_data py_loader_impl_initialize(loader_impl impl, configuration confi
27602769
goto error_after_import;
27612770
}
27622771

2763-
/* Initialize asyncio module for supporting async */
2764-
if (py_loader_impl_initialize_asyncio_module(py_impl, host) != 0)
2772+
#if defined(WIN32) || defined(_WIN32)
2773+
/* On Windows, the initialization of this module deadlocks, we delay it to the port on this case */
2774+
if (host == 0)
2775+
#endif
27652776
{
2766-
goto error_after_thread_background_module;
2777+
/* Initialize asyncio module for supporting async */
2778+
if (py_loader_impl_initialize_asyncio_module(py_impl, host) != 0)
2779+
{
2780+
goto error_after_thread_background_module;
2781+
}
27672782
}
27682783

27692784
/* Initialize custom dict type */

source/loaders/py_loader/source/py_loader_port.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -890,6 +890,26 @@ static PyObject *py_loader_port_atexit(PyObject *self, PyObject *args)
890890
return Py_ReturnNone();
891891
}
892892

893+
static PyObject *py_loader_port_asyncio_initialize(PyObject *self, PyObject *args)
894+
{
895+
loader_impl impl = loader_get_impl(py_loader_tag);
896+
const int host = loader_impl_get_option_host(impl);
897+
loader_impl_py py_impl = loader_impl_get(impl);
898+
899+
(void)self;
900+
(void)args;
901+
902+
if (impl != NULL)
903+
{
904+
if (py_loader_impl_initialize_asyncio_module(py_impl, host) != 0)
905+
{
906+
PyErr_SetString(PyExc_RuntimeErrorPtr(), "Failed to initialize asyncio module of Python Loader on MetaCall.");
907+
}
908+
}
909+
910+
return Py_ReturnNone();
911+
}
912+
893913
static PyMethodDef metacall_methods[] = {
894914
{ "metacall_load_from_file", py_loader_port_load_from_file, METH_VARARGS,
895915
"Loads a script from file." },
@@ -913,6 +933,8 @@ static PyMethodDef metacall_methods[] = {
913933
"Get the data which a value of type Pointer is pointing to." },
914934
{ "py_loader_port_atexit", py_loader_port_atexit, METH_NOARGS,
915935
"At exit function that will be executed when Python is host, for internal cleanup purposes." },
936+
{ "py_loader_port_asyncio_initialize", py_loader_port_asyncio_initialize, METH_NOARGS,
937+
"Initialization function that will be executed when Python is host, for internal initialization purposes." },
916938
{ NULL, NULL, 0, NULL }
917939
};
918940

source/loaders/py_loader/source/py_loader_threading.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ int py_loader_thread_initialize(const int host)
6969

7070
if (host == 1)
7171
{
72-
int gil_status = PyGILState_Check();
72+
const int gil_status = PyGILState_Check();
7373

7474
PyGILState_STATE gstate = PyGILState_Ensure();
7575
main_thread_state = PyThreadState_Get();

source/ports/py_port/metacall/api.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,14 @@ def metacall_module_load():
9595

9696
# Python Port must have been loaded at this point
9797
if 'py_port_impl_module' in sys.modules:
98-
return sys.modules['py_port_impl_module']
98+
port = sys.modules['py_port_impl_module']
99+
100+
# For some reason, Windows deadlocks on initializing asyncio
101+
# but if it is delayed, it works, so we initialize it after here
102+
if sys.platform == 'win32':
103+
port.py_loader_port_asyncio_initialize()
104+
105+
return port
99106
else:
100107
raise ImportError(
101108
'MetaCall was found but failed to load'

0 commit comments

Comments
 (0)