Skip to content

Commit d8e061b

Browse files
committed
Solve issues with deadlocks on windows.
1 parent a582720 commit d8e061b

File tree

1 file changed

+77
-0
lines changed

1 file changed

+77
-0
lines changed

source/loaders/py_loader/source/py_loader_impl.c

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4302,6 +4302,80 @@ int py_loader_impl_finalize(loader_impl_py py_impl, const int host)
43024302
return 0;
43034303
}
43044304

4305+
#if defined(WIN32) || defined(_WIN32)
4306+
/* On Windows, threads are destroyed when atexit is executed, we should control this in order to avoid deadlocks */
4307+
static long py_loader_impl_asyncio_thread_native_id(loader_impl_py py_impl)
4308+
{
4309+
PyObject *thread_obj = PyObject_GetAttrString(py_impl->asyncio_loop, "t");
4310+
4311+
if (thread_obj == NULL)
4312+
{
4313+
return -1;
4314+
}
4315+
4316+
PyObject *native_id_obj = PyObject_GetAttrString(thread_obj, "native_id");
4317+
Py_DecRef(thread_obj);
4318+
4319+
if (thread_obj == NULL)
4320+
{
4321+
return -1;
4322+
}
4323+
4324+
long native_id = PyLong_AsLong(native_id_obj);
4325+
Py_DecRef(native_id_obj);
4326+
4327+
if (PyErr_Occurred())
4328+
{
4329+
py_loader_impl_error_print(py_impl);
4330+
return -1;
4331+
}
4332+
4333+
return native_id;
4334+
}
4335+
4336+
static int py_loader_impl_check_thread(loader_impl_py py_impl)
4337+
{
4338+
long thread_id = py_loader_impl_asyncio_thread_native_id(py_impl);
4339+
4340+
if (thread_id == -1)
4341+
{
4342+
return -1;
4343+
}
4344+
4345+
HANDLE thread_handle = OpenThread(THREAD_QUERY_INFORMATION | SYNCHRONIZE, FALSE, thread_id);
4346+
4347+
if (thread_handle == NULL)
4348+
{
4349+
return 1;
4350+
}
4351+
4352+
DWORD result = WaitForSingleObject(thread_handle, 0);
4353+
4354+
CloseHandle(thread_handle);
4355+
4356+
if (result == WAIT_TIMEOUT)
4357+
{
4358+
return 0;
4359+
}
4360+
else if (result == WAIT_OBJECT_0)
4361+
{
4362+
/* This workaround forces to skip thread waiting, so it avoids deadlocks */
4363+
PyObject *sys_modules = PyImport_GetModuleDict();
4364+
4365+
if (PyDict_DelItemString(sys_modules, "threading") < 0)
4366+
{
4367+
PyErr_Print();
4368+
}
4369+
4370+
return 1;
4371+
}
4372+
else
4373+
{
4374+
return -1;
4375+
}
4376+
}
4377+
#endif
4378+
43054379
int py_loader_impl_destroy(loader_impl impl)
43064380
{
43074381
const int host = loader_impl_get_option_host(impl);
@@ -4319,6 +4393,9 @@ int py_loader_impl_destroy(loader_impl impl)
43194393
py_loader_thread_acquire();
43204394

43214395
/* Stop event loop for async calls */
4396+
#if defined(WIN32) || defined(_WIN32)
4397+
if (py_loader_impl_check_thread(py_impl) == 0)
4398+
#endif
43224399
{
43234400
PyObject *args_tuple = PyTuple_New(2);
43244401
Py_IncRef(py_impl->asyncio_loop);

0 commit comments

Comments
 (0)