@@ -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+
43054379int 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