1# -*- coding: utf-8 -*- 2import multiprocessing 3import threading 4 5from pybind11_tests import gil_scoped as m 6 7 8def _run_in_process(target, *args, **kwargs): 9 """Runs target in process and returns its exitcode after 10s (None if still alive).""" 10 process = multiprocessing.Process(target=target, args=args, kwargs=kwargs) 11 process.daemon = True 12 try: 13 process.start() 14 # Do not need to wait much, 10s should be more than enough. 15 process.join(timeout=10) 16 return process.exitcode 17 finally: 18 if process.is_alive(): 19 process.terminate() 20 21 22def _python_to_cpp_to_python(): 23 """Calls different C++ functions that come back to Python.""" 24 25 class ExtendedVirtClass(m.VirtClass): 26 def virtual_func(self): 27 pass 28 29 def pure_virtual_func(self): 30 pass 31 32 extended = ExtendedVirtClass() 33 m.test_callback_py_obj(lambda: None) 34 m.test_callback_std_func(lambda: None) 35 m.test_callback_virtual_func(extended) 36 m.test_callback_pure_virtual_func(extended) 37 38 39def _python_to_cpp_to_python_from_threads(num_threads, parallel=False): 40 """Calls different C++ functions that come back to Python, from Python threads.""" 41 threads = [] 42 for _ in range(num_threads): 43 thread = threading.Thread(target=_python_to_cpp_to_python) 44 thread.daemon = True 45 thread.start() 46 if parallel: 47 threads.append(thread) 48 else: 49 thread.join() 50 for thread in threads: 51 thread.join() 52 53 54# TODO: FIXME, sometimes returns -11 (segfault) instead of 0 on macOS Python 3.9 55def test_python_to_cpp_to_python_from_thread(): 56 """Makes sure there is no GIL deadlock when running in a thread. 57 58 It runs in a separate process to be able to stop and assert if it deadlocks. 59 """ 60 assert _run_in_process(_python_to_cpp_to_python_from_threads, 1) == 0 61 62 63# TODO: FIXME on macOS Python 3.9 64def test_python_to_cpp_to_python_from_thread_multiple_parallel(): 65 """Makes sure there is no GIL deadlock when running in a thread multiple times in parallel. 66 67 It runs in a separate process to be able to stop and assert if it deadlocks. 68 """ 69 assert _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=True) == 0 70 71 72# TODO: FIXME on macOS Python 3.9 73def test_python_to_cpp_to_python_from_thread_multiple_sequential(): 74 """Makes sure there is no GIL deadlock when running in a thread multiple times sequentially. 75 76 It runs in a separate process to be able to stop and assert if it deadlocks. 77 """ 78 assert ( 79 _run_in_process(_python_to_cpp_to_python_from_threads, 8, parallel=False) == 0 80 ) 81 82 83# TODO: FIXME on macOS Python 3.9 84def test_python_to_cpp_to_python_from_process(): 85 """Makes sure there is no GIL deadlock when using processes. 86 87 This test is for completion, but it was never an issue. 88 """ 89 assert _run_in_process(_python_to_cpp_to_python) == 0 90 91 92def test_cross_module_gil(): 93 """Makes sure that the GIL can be acquired by another module from a GIL-released state.""" 94 m.test_cross_module_gil() # Should not raise a SIGSEGV 95