@@ -138,6 +138,12 @@ def test_all_basic_tests_completeness():
138
138
assert len (ALL_BASIC_TESTS ) == num_found
139
139
140
140
141
+ # Issue #2754:
142
+ ThreadSanitizer_exitcode_66_message = (
143
+ "ThreadSanitizer: starting new threads after multi-threaded fork is not supported."
144
+ )
145
+
146
+
141
147
def _run_in_process (target , * args , ** kwargs ):
142
148
"""Runs target in process and returns its exitcode after 10s (None if still alive)."""
143
149
process = multiprocessing .Process (target = target , args = args , kwargs = kwargs )
@@ -146,6 +152,8 @@ def _run_in_process(target, *args, **kwargs):
146
152
process .start ()
147
153
# Do not need to wait much, 10s should be more than enough.
148
154
process .join (timeout = 10 )
155
+ if process .exitcode == 66 :
156
+ pass # NICE-TO-HAVE: Check output for ThreadSanitizer_exitcode_66_message
149
157
return process .exitcode
150
158
finally :
151
159
if process .is_alive ():
@@ -166,26 +174,20 @@ def _run_in_threads(target, num_threads, parallel):
166
174
thread .join ()
167
175
168
176
169
- # m.defined_THREAD_SANITIZER is used below to skip tests triggering this error (#2754):
170
- # ThreadSanitizer: starting new threads after multi-threaded fork is not supported.
171
-
172
177
# TODO: FIXME, sometimes returns -11 (segfault) instead of 0 on macOS Python 3.9
173
- @pytest .mark .skipif (
174
- m .defined_THREAD_SANITIZER , reason = "Not compatible with ThreadSanitizer"
175
- )
176
178
@pytest .mark .parametrize ("test_fn" , ALL_BASIC_TESTS )
177
179
def test_run_in_process_one_thread (test_fn ):
178
180
"""Makes sure there is no GIL deadlock when running in a thread.
179
181
180
182
It runs in a separate process to be able to stop and assert if it deadlocks.
181
183
"""
182
- assert _run_in_process (_run_in_threads , test_fn , num_threads = 1 , parallel = False ) == 0
184
+ exitcode = _run_in_process (_run_in_threads , test_fn , num_threads = 1 , parallel = False )
185
+ if exitcode == 66 and m .defined_THREAD_SANITIZER :
186
+ pytest .skip (ThreadSanitizer_exitcode_66_message )
187
+ assert exitcode == 0
183
188
184
189
185
190
# TODO: FIXME on macOS Python 3.9
186
- @pytest .mark .skipif (
187
- m .defined_THREAD_SANITIZER , reason = "Not compatible with ThreadSanitizer"
188
- )
189
191
@pytest .mark .parametrize ("test_fn" , ALL_BASIC_TESTS )
190
192
def test_run_in_process_multiple_threads_parallel (test_fn ):
191
193
"""Makes sure there is no GIL deadlock when running in a thread multiple times in parallel.
@@ -195,20 +197,22 @@ def test_run_in_process_multiple_threads_parallel(test_fn):
195
197
exitcode = _run_in_process (_run_in_threads , test_fn , num_threads = 8 , parallel = True )
196
198
if exitcode is None and env .PYPY and env .WIN : # Seems to be flaky.
197
199
pytest .skip ("Ignoring unexpected exitcode None (PYPY WIN)" )
200
+ if exitcode == 66 and m .defined_THREAD_SANITIZER :
201
+ pytest .skip (ThreadSanitizer_exitcode_66_message )
198
202
assert exitcode == 0
199
203
200
204
201
205
# TODO: FIXME on macOS Python 3.9
202
- @pytest .mark .skipif (
203
- m .defined_THREAD_SANITIZER , reason = "Not compatible with ThreadSanitizer"
204
- )
205
206
@pytest .mark .parametrize ("test_fn" , ALL_BASIC_TESTS )
206
207
def test_run_in_process_multiple_threads_sequential (test_fn ):
207
208
"""Makes sure there is no GIL deadlock when running in a thread multiple times sequentially.
208
209
209
210
It runs in a separate process to be able to stop and assert if it deadlocks.
210
211
"""
211
- assert _run_in_process (_run_in_threads , test_fn , num_threads = 8 , parallel = False ) == 0
212
+ exitcode = _run_in_process (_run_in_threads , test_fn , num_threads = 8 , parallel = False )
213
+ if exitcode == 66 and m .defined_THREAD_SANITIZER :
214
+ pytest .skip (ThreadSanitizer_exitcode_66_message )
215
+ assert exitcode == 0
212
216
213
217
214
218
# TODO: FIXME on macOS Python 3.9
@@ -218,15 +222,9 @@ def test_run_in_process_direct(test_fn):
218
222
219
223
This test is for completion, but it was never an issue.
220
224
"""
221
- if m .defined_THREAD_SANITIZER and test_fn in (
222
- test_cross_module_gil_nested_custom_released ,
223
- test_cross_module_gil_nested_custom_acquired ,
224
- test_cross_module_gil_nested_pybind11_released ,
225
- test_cross_module_gil_nested_pybind11_acquired ,
226
- test_multi_acquire_release_cross_module ,
227
- ):
228
- pytest .skip ("Not compatible with ThreadSanitizer" )
229
225
exitcode = _run_in_process (test_fn )
230
226
if exitcode is None and env .PYPY and env .WIN : # Seems to be flaky.
231
227
pytest .skip ("Ignoring unexpected exitcode None (PYPY WIN)" )
228
+ if exitcode == 66 and m .defined_THREAD_SANITIZER :
229
+ pytest .skip (ThreadSanitizer_exitcode_66_message )
232
230
assert exitcode == 0
0 commit comments