bpo-40280: Detect missing threading on WASM platforms (GH-32352)

Co-authored-by: Brett Cannon <brett@python.org>
This commit is contained in:
Christian Heimes 2022-04-07 10:22:47 +03:00 committed by GitHub
parent 5aee46b31b
commit 2b16a08bc7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
33 changed files with 103 additions and 21 deletions

View File

@ -17,6 +17,7 @@ import unittest
from test import support from test import support
from test.support import os_helper from test.support import os_helper
from test.support.script_helper import assert_python_ok from test.support.script_helper import assert_python_ok
from test.support import threading_helper
# http://bugs.python.org/issue4373 # http://bugs.python.org/issue4373
# Don't load the xx module more than once. # Don't load the xx module more than once.
@ -165,6 +166,7 @@ class BuildExtTestCase(TempdirManager,
self.assertIn(lib, cmd.rpath) self.assertIn(lib, cmd.rpath)
self.assertIn(incl, cmd.include_dirs) self.assertIn(incl, cmd.include_dirs)
@threading_helper.requires_working_threading()
def test_optional_extension(self): def test_optional_extension(self):
# this extension will fail, but let's ignore this failure # this extension will fail, but let's ignore this failure

View File

@ -20,6 +20,7 @@ from test.libregrtest.pgo import setup_pgo_tests
from test.libregrtest.utils import removepy, count, format_duration, printlist from test.libregrtest.utils import removepy, count, format_duration, printlist
from test import support from test import support
from test.support import os_helper from test.support import os_helper
from test.support import threading_helper
# bpo-38203: Maximum delay in seconds to exit Python (call Py_Finalize()). # bpo-38203: Maximum delay in seconds to exit Python (call Py_Finalize()).
@ -676,7 +677,8 @@ class Regrtest:
except SystemExit as exc: except SystemExit as exc:
# bpo-38203: Python can hang at exit in Py_Finalize(), especially # bpo-38203: Python can hang at exit in Py_Finalize(), especially
# on threading._shutdown() call: put a timeout # on threading._shutdown() call: put a timeout
faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True) if threading_helper.can_start_thread:
faulthandler.dump_traceback_later(EXIT_TIMEOUT, exit=True)
sys.exit(exc.code) sys.exit(exc.code)

View File

@ -1380,6 +1380,7 @@ class AbstractUnpickleTests:
self.check_unpickling_error(self.truncated_errors, p) self.check_unpickling_error(self.truncated_errors, p)
@threading_helper.reap_threads @threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_unpickle_module_race(self): def test_unpickle_module_race(self):
# https://bugs.python.org/issue34572 # https://bugs.python.org/issue34572
locker_module = dedent(""" locker_module = dedent("""

View File

@ -4,6 +4,7 @@ import functools
import sys import sys
import threading import threading
import time import time
import unittest
from test import support from test import support
@ -210,7 +211,7 @@ class catch_threading_exception:
def _can_start_thread() -> bool: def _can_start_thread() -> bool:
"""Detect if Python can start new threads. """Detect whether Python can start new threads.
Some WebAssembly platforms do not provide a working pthread Some WebAssembly platforms do not provide a working pthread
implementation. Thread support is stubbed and any attempt implementation. Thread support is stubbed and any attempt
@ -234,3 +235,15 @@ def _can_start_thread() -> bool:
return True return True
can_start_thread = _can_start_thread() can_start_thread = _can_start_thread()
def requires_working_threading(*, module=False):
"""Skip tests or modules that require working threading.
Can be used as a function/class decorator or to skip an entire module.
"""
msg = "requires threading support"
if module:
if not can_start_thread:
raise unittest.SkipTest(msg)
else:
return unittest.skipUnless(can_start_thread, msg)

View File

@ -496,6 +496,7 @@ class BZ2FileTest(BaseTest):
else: else:
self.fail("1/0 didn't raise an exception") self.fail("1/0 didn't raise an exception")
@threading_helper.requires_working_threading()
def testThreading(self): def testThreading(self):
# Issue #7205: Using a BZ2File from several threads shouldn't deadlock. # Issue #7205: Using a BZ2File from several threads shouldn't deadlock.
data = b"1" * 2**20 data = b"1" * 2**20

View File

@ -710,6 +710,7 @@ class TestPendingCalls(unittest.TestCase):
if False and support.verbose: if False and support.verbose:
print("(%i)"%(len(l),)) print("(%i)"%(len(l),))
@threading_helper.requires_working_threading()
def test_pendingcalls_threaded(self): def test_pendingcalls_threaded(self):
#do every callback on a separate thread #do every callback on a separate thread
@ -840,6 +841,7 @@ class SubinterpreterTest(unittest.TestCase):
class TestThreadState(unittest.TestCase): class TestThreadState(unittest.TestCase):
@threading_helper.reap_threads @threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_thread_state(self): def test_thread_state(self):
# some extra thread-state tests driven via _testcapi # some extra thread-state tests driven via _testcapi
def target(): def target():

View File

@ -6,6 +6,7 @@ import random
import time import time
import unittest import unittest
import weakref import weakref
from test.support import threading_helper
try: try:
from _testcapi import hamt from _testcapi import hamt
@ -341,6 +342,7 @@ class ContextTest(unittest.TestCase):
ctx1.run(ctx1_fun) ctx1.run(ctx1_fun)
@isolated_context @isolated_context
@threading_helper.requires_working_threading()
def test_context_threads_1(self): def test_context_threads_1(self):
cvar = contextvars.ContextVar('cvar') cvar = contextvars.ContextVar('cvar')

View File

@ -39,6 +39,7 @@ from test.support import (TestFailed,
run_with_locale, cpython_only, run_with_locale, cpython_only,
darwin_malloc_err_warning) darwin_malloc_err_warning)
from test.support.import_helper import import_fresh_module from test.support.import_helper import import_fresh_module
from test.support import threading_helper
from test.support import warnings_helper from test.support import warnings_helper
import random import random
import inspect import inspect
@ -1591,6 +1592,8 @@ def thfunc2(cls):
for sig in Overflow, Underflow, DivisionByZero, InvalidOperation: for sig in Overflow, Underflow, DivisionByZero, InvalidOperation:
cls.assertFalse(thiscontext.flags[sig]) cls.assertFalse(thiscontext.flags[sig])
@threading_helper.requires_working_threading()
class ThreadingTest(unittest.TestCase): class ThreadingTest(unittest.TestCase):
'''Unit tests for thread local contexts in Decimal.''' '''Unit tests for thread local contexts in Decimal.'''

View File

@ -3285,6 +3285,7 @@ Foo
addrs = utils.getaddresses([Header('Al Person <aperson@dom.ain>')]) addrs = utils.getaddresses([Header('Al Person <aperson@dom.ain>')])
self.assertEqual(addrs[0][1], 'aperson@dom.ain') self.assertEqual(addrs[0][1], 'aperson@dom.ain')
@threading_helper.requires_working_threading()
def test_make_msgid_collisions(self): def test_make_msgid_collisions(self):
# Test make_msgid uniqueness, even with multiple threads # Test make_msgid uniqueness, even with multiple threads
class MsgidsThread(Thread): class MsgidsThread(Thread):

View File

@ -2949,6 +2949,7 @@ class OldTestFlag(unittest.TestCase):
self.assertEqual(str(Color.BLUE), 'blue') self.assertEqual(str(Color.BLUE), 'blue')
@threading_helper.reap_threads @threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_unique_composite(self): def test_unique_composite(self):
# override __eq__ to be identity only # override __eq__ to be identity only
class TestFlag(Flag): class TestFlag(Flag):
@ -3481,6 +3482,7 @@ class OldTestIntFlag(unittest.TestCase):
self.assertEqual(str(Color.BLUE), 'blue') self.assertEqual(str(Color.BLUE), 'blue')
@threading_helper.reap_threads @threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_unique_composite(self): def test_unique_composite(self):
# override __eq__ to be identity only # override __eq__ to be identity only
class TestFlag(IntFlag): class TestFlag(IntFlag):

View File

@ -1637,6 +1637,7 @@ class TestLRU:
for attr in self.module.WRAPPER_ASSIGNMENTS: for attr in self.module.WRAPPER_ASSIGNMENTS:
self.assertEqual(getattr(g, attr), getattr(f, attr)) self.assertEqual(getattr(g, attr), getattr(f, attr))
@threading_helper.requires_working_threading()
def test_lru_cache_threaded(self): def test_lru_cache_threaded(self):
n, m = 5, 11 n, m = 5, 11
def orig(x, y): def orig(x, y):
@ -1685,6 +1686,7 @@ class TestLRU:
finally: finally:
sys.setswitchinterval(orig_si) sys.setswitchinterval(orig_si)
@threading_helper.requires_working_threading()
def test_lru_cache_threaded2(self): def test_lru_cache_threaded2(self):
# Simultaneous call with the same arguments # Simultaneous call with the same arguments
n, m = 5, 7 n, m = 5, 7
@ -1712,6 +1714,7 @@ class TestLRU:
pause.reset() pause.reset()
self.assertEqual(f.cache_info(), (0, (i+1)*n, m*n, i+1)) self.assertEqual(f.cache_info(), (0, (i+1)*n, m*n, i+1))
@threading_helper.requires_working_threading()
def test_lru_cache_threaded3(self): def test_lru_cache_threaded3(self):
@self.module.lru_cache(maxsize=2) @self.module.lru_cache(maxsize=2)
def f(x): def f(x):
@ -2914,6 +2917,7 @@ class TestCachedProperty(unittest.TestCase):
self.assertEqual(item.get_cost(), 4) self.assertEqual(item.get_cost(), 4)
self.assertEqual(item.cached_cost, 3) self.assertEqual(item.cached_cost, 3)
@threading_helper.requires_working_threading()
def test_threaded(self): def test_threaded(self):
go = threading.Event() go = threading.Event()
item = CachedCostItemWait(go) item = CachedCostItemWait(go)

View File

@ -365,6 +365,7 @@ class GCTests(unittest.TestCase):
v = {1: v, 2: Ouch()} v = {1: v, 2: Ouch()}
gc.disable() gc.disable()
@threading_helper.requires_working_threading()
def test_trashcan_threads(self): def test_trashcan_threads(self):
# Issue #13992: trashcan mechanism should be thread-safe # Issue #13992: trashcan mechanism should be thread-safe
NESTING = 60 NESTING = 60

View File

@ -915,6 +915,7 @@ class HashLibTestCase(unittest.TestCase):
) )
@threading_helper.reap_threads @threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_threaded_hashing(self): def test_threaded_hashing(self):
# Updating the same hash object from several threads at once # Updating the same hash object from several threads at once
# using data chunk sizes containing the same byte sequences. # using data chunk sizes containing the same byte sequences.

View File

@ -448,6 +448,7 @@ class ImportTests(unittest.TestCase):
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
os.does_not_exist os.does_not_exist
@threading_helper.requires_working_threading()
def test_concurrency(self): def test_concurrency(self):
# bpo 38091: this is a hack to slow down the code that calls # bpo 38091: this is a hack to slow down the code that calls
# has_deadlock(); the logic was itself sometimes deadlocking. # has_deadlock(); the logic was itself sometimes deadlocking.

View File

@ -12,6 +12,9 @@ from test.support import threading_helper
from test import lock_tests from test import lock_tests
threading_helper.requires_working_threading(module=True)
class ModuleLockAsRLockTests: class ModuleLockAsRLockTests:
locktype = classmethod(lambda cls: cls.LockType("some_lock")) locktype = classmethod(lambda cls: cls.LockType("some_lock"))
@ -146,4 +149,4 @@ def setUpModule():
if __name__ == '__main__': if __name__ == '__main__':
unittets.main() unittest.main()

View File

@ -19,6 +19,8 @@ from test.support.import_helper import forget
from test.support.os_helper import (TESTFN, unlink, rmtree) from test.support.os_helper import (TESTFN, unlink, rmtree)
from test.support import script_helper, threading_helper from test.support import script_helper, threading_helper
threading_helper.requires_working_threading(module=True)
def task(N, done, done_tasks, errors): def task(N, done, done_tasks, errors):
try: try:
# We don't use modulefinder but still import it in order to stress # We don't use modulefinder but still import it in order to stress

View File

@ -1451,6 +1451,7 @@ class BufferedReaderTest(unittest.TestCase, CommonBufferedTests):
self.assertEqual(b"abcdefg", bufio.read()) self.assertEqual(b"abcdefg", bufio.read())
@support.requires_resource('cpu') @support.requires_resource('cpu')
@threading_helper.requires_working_threading()
def test_threads(self): def test_threads(self):
try: try:
# Write out many bytes with exactly the same number of 0's, # Write out many bytes with exactly the same number of 0's,
@ -1825,6 +1826,7 @@ class BufferedWriterTest(unittest.TestCase, CommonBufferedTests):
self.assertEqual(f.tell(), buffer_size + 2) self.assertEqual(f.tell(), buffer_size + 2)
@support.requires_resource('cpu') @support.requires_resource('cpu')
@threading_helper.requires_working_threading()
def test_threads(self): def test_threads(self):
try: try:
# Write out many bytes from many threads and test they were # Write out many bytes from many threads and test they were
@ -1895,6 +1897,7 @@ class BufferedWriterTest(unittest.TestCase, CommonBufferedTests):
self.assertRaises(OSError, b.close) # exception not swallowed self.assertRaises(OSError, b.close) # exception not swallowed
self.assertTrue(b.closed) self.assertTrue(b.closed)
@threading_helper.requires_working_threading()
def test_slow_close_from_thread(self): def test_slow_close_from_thread(self):
# Issue #31976 # Issue #31976
rawio = self.SlowFlushRawIO() rawio = self.SlowFlushRawIO()
@ -3287,6 +3290,7 @@ class TextIOWrapperTest(unittest.TestCase):
self.assertEqual(f.errors, "replace") self.assertEqual(f.errors, "replace")
@support.no_tracing @support.no_tracing
@threading_helper.requires_working_threading()
def test_threads_write(self): def test_threads_write(self):
# Issue6750: concurrent writes could duplicate data # Issue6750: concurrent writes could duplicate data
event = threading.Event() event = threading.Event()
@ -4362,9 +4366,11 @@ class CMiscIOTest(MiscIOTest):
else: else:
self.assertFalse(err.strip('.!')) self.assertFalse(err.strip('.!'))
@threading_helper.requires_working_threading()
def test_daemon_threads_shutdown_stdout_deadlock(self): def test_daemon_threads_shutdown_stdout_deadlock(self):
self.check_daemon_threads_shutdown_deadlock('stdout') self.check_daemon_threads_shutdown_deadlock('stdout')
@threading_helper.requires_working_threading()
def test_daemon_threads_shutdown_stderr_deadlock(self): def test_daemon_threads_shutdown_stderr_deadlock(self):
self.check_daemon_threads_shutdown_deadlock('stderr') self.check_daemon_threads_shutdown_deadlock('stderr')

View File

@ -1,6 +1,7 @@
import doctest import doctest
import unittest import unittest
from test import support from test import support
from test.support import threading_helper
from itertools import * from itertools import *
import weakref import weakref
from decimal import Decimal from decimal import Decimal
@ -1533,6 +1534,7 @@ class TestBasicOps(unittest.TestCase):
with self.assertRaisesRegex(RuntimeError, "tee"): with self.assertRaisesRegex(RuntimeError, "tee"):
next(a) next(a)
@threading_helper.requires_working_threading()
def test_tee_concurrent(self): def test_tee_concurrent(self):
start = threading.Event() start = threading.Event()
finish = threading.Event() finish = threading.Event()

View File

@ -630,6 +630,7 @@ class HandlerTest(BaseTest):
@unittest.skipIf( @unittest.skipIf(
support.is_emscripten, "Emscripten cannot fstat unlinked files." support.is_emscripten, "Emscripten cannot fstat unlinked files."
) )
@threading_helper.requires_working_threading()
def test_race(self): def test_race(self):
# Issue #14632 refers. # Issue #14632 refers.
def remove_loop(fname, tries): def remove_loop(fname, tries):
@ -679,6 +680,7 @@ class HandlerTest(BaseTest):
# This helps ensure that when fork exists (the important concept) that the # This helps ensure that when fork exists (the important concept) that the
# register_at_fork mechanism is also present and used. # register_at_fork mechanism is also present and used.
@support.requires_fork() @support.requires_fork()
@threading_helper.requires_working_threading()
def test_post_fork_child_no_deadlock(self): def test_post_fork_child_no_deadlock(self):
"""Ensure child logging locks are not held; bpo-6721 & bpo-36533.""" """Ensure child logging locks are not held; bpo-6721 & bpo-36533."""
class _OurHandler(logging.Handler): class _OurHandler(logging.Handler):
@ -1063,6 +1065,7 @@ if hasattr(socket, "AF_UNIX"):
# - end of server_helper section # - end of server_helper section
@support.requires_working_socket() @support.requires_working_socket()
@threading_helper.requires_working_threading()
class SMTPHandlerTest(BaseTest): class SMTPHandlerTest(BaseTest):
# bpo-14314, bpo-19665, bpo-34092: don't wait forever # bpo-14314, bpo-19665, bpo-34092: don't wait forever
TIMEOUT = support.LONG_TIMEOUT TIMEOUT = support.LONG_TIMEOUT
@ -1172,6 +1175,7 @@ class MemoryHandlerTest(BaseTest):
# assert that no new lines have been added # assert that no new lines have been added
self.assert_log_lines(lines) # no change self.assert_log_lines(lines) # no change
@threading_helper.requires_working_threading()
def test_race_between_set_target_and_flush(self): def test_race_between_set_target_and_flush(self):
class MockRaceConditionHandler: class MockRaceConditionHandler:
def __init__(self, mem_hdlr): def __init__(self, mem_hdlr):
@ -1687,6 +1691,7 @@ class ConfigFileTest(BaseTest):
@support.requires_working_socket() @support.requires_working_socket()
@threading_helper.requires_working_threading()
class SocketHandlerTest(BaseTest): class SocketHandlerTest(BaseTest):
"""Test for SocketHandler objects.""" """Test for SocketHandler objects."""
@ -1802,6 +1807,7 @@ class UnixSocketHandlerTest(SocketHandlerTest):
os_helper.unlink(self.address) os_helper.unlink(self.address)
@support.requires_working_socket() @support.requires_working_socket()
@threading_helper.requires_working_threading()
class DatagramHandlerTest(BaseTest): class DatagramHandlerTest(BaseTest):
"""Test for DatagramHandler.""" """Test for DatagramHandler."""
@ -1884,6 +1890,7 @@ class UnixDatagramHandlerTest(DatagramHandlerTest):
os_helper.unlink(self.address) os_helper.unlink(self.address)
@support.requires_working_socket() @support.requires_working_socket()
@threading_helper.requires_working_threading()
class SysLogHandlerTest(BaseTest): class SysLogHandlerTest(BaseTest):
"""Test for SysLogHandler using UDP.""" """Test for SysLogHandler using UDP."""
@ -1994,6 +2001,7 @@ class IPv6SysLogHandlerTest(SysLogHandlerTest):
super(IPv6SysLogHandlerTest, self).tearDown() super(IPv6SysLogHandlerTest, self).tearDown()
@support.requires_working_socket() @support.requires_working_socket()
@threading_helper.requires_working_threading()
class HTTPHandlerTest(BaseTest): class HTTPHandlerTest(BaseTest):
"""Test for HTTPHandler.""" """Test for HTTPHandler."""
@ -3575,6 +3583,7 @@ class LogRecordFactoryTest(BaseTest):
]) ])
@threading_helper.requires_working_threading()
class QueueHandlerTest(BaseTest): class QueueHandlerTest(BaseTest):
# Do not bother with a logger name group. # Do not bother with a logger name group.
expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$" expected_log_pat = r"^[\w.]+ -> (\w+): (\d+)$"
@ -3684,6 +3693,7 @@ if hasattr(logging.handlers, 'QueueListener'):
import multiprocessing import multiprocessing
from unittest.mock import patch from unittest.mock import patch
@threading_helper.requires_working_threading()
class QueueListenerTest(BaseTest): class QueueListenerTest(BaseTest):
""" """
Tests based on patch submitted for issue #27930. Ensure that Tests based on patch submitted for issue #27930. Ensure that

View File

@ -87,6 +87,7 @@ class BlockingTestMixin:
self.fail("trigger thread ended but event never set") self.fail("trigger thread ended but event never set")
@threading_helper.requires_working_threading()
class BaseQueueTestMixin(BlockingTestMixin): class BaseQueueTestMixin(BlockingTestMixin):
def setUp(self): def setUp(self):
self.cum = 0 self.cum = 0
@ -289,6 +290,8 @@ class CPriorityQueueTest(PriorityQueueTest, unittest.TestCase):
# A Queue subclass that can provoke failure at a moment's notice :) # A Queue subclass that can provoke failure at a moment's notice :)
class FailingQueueException(Exception): pass class FailingQueueException(Exception): pass
@threading_helper.requires_working_threading()
class FailingQueueTest(BlockingTestMixin): class FailingQueueTest(BlockingTestMixin):
def setUp(self): def setUp(self):
@ -464,6 +467,7 @@ class BaseSimpleQueueTest:
return return
results.append(val) results.append(val)
@threading_helper.requires_working_threading()
def run_threads(self, n_threads, q, inputs, feed_func, consume_func): def run_threads(self, n_threads, q, inputs, feed_func, consume_func):
results = [] results = []
sentinel = None sentinel = None

View File

@ -58,6 +58,7 @@ class TestCase(unittest.TestCase):
scheduler.run() scheduler.run()
self.assertEqual(l, [0.01, 0.02, 0.03, 0.04, 0.05]) self.assertEqual(l, [0.01, 0.02, 0.03, 0.04, 0.05])
@threading_helper.requires_working_threading()
def test_enter_concurrent(self): def test_enter_concurrent(self):
q = queue.Queue() q = queue.Queue()
fun = q.put fun = q.put
@ -111,6 +112,7 @@ class TestCase(unittest.TestCase):
scheduler.run() scheduler.run()
self.assertEqual(l, [0.02, 0.03, 0.04]) self.assertEqual(l, [0.02, 0.03, 0.04])
@threading_helper.requires_working_threading()
def test_cancel_concurrent(self): def test_cancel_concurrent(self):
q = queue.Queue() q = queue.Queue()
fun = q.put fun = q.put

View File

@ -14,6 +14,7 @@ import unittest
from test import support from test import support
from test.support import os_helper from test.support import os_helper
from test.support.script_helper import assert_python_ok, spawn_python from test.support.script_helper import assert_python_ok, spawn_python
from test.support import threading_helper
try: try:
import _testcapi import _testcapi
except ImportError: except ImportError:
@ -876,6 +877,7 @@ class PendingSignalsTests(unittest.TestCase):
@unittest.skipUnless(hasattr(signal, 'pthread_kill'), @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
'need signal.pthread_kill()') 'need signal.pthread_kill()')
@threading_helper.requires_working_threading()
def test_pthread_kill(self): def test_pthread_kill(self):
code = """if 1: code = """if 1:
import signal import signal
@ -1012,6 +1014,7 @@ class PendingSignalsTests(unittest.TestCase):
'need signal.sigwait()') 'need signal.sigwait()')
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
'need signal.pthread_sigmask()') 'need signal.pthread_sigmask()')
@threading_helper.requires_working_threading()
def test_sigwait_thread(self): def test_sigwait_thread(self):
# Check that calling sigwait() from a thread doesn't suspend the whole # Check that calling sigwait() from a thread doesn't suspend the whole
# process. A new interpreter is spawned to avoid problems when mixing # process. A new interpreter is spawned to avoid problems when mixing
@ -1067,6 +1070,7 @@ class PendingSignalsTests(unittest.TestCase):
@unittest.skipUnless(hasattr(signal, 'pthread_sigmask'), @unittest.skipUnless(hasattr(signal, 'pthread_sigmask'),
'need signal.pthread_sigmask()') 'need signal.pthread_sigmask()')
@threading_helper.requires_working_threading()
def test_pthread_sigmask(self): def test_pthread_sigmask(self):
code = """if 1: code = """if 1:
import signal import signal
@ -1144,6 +1148,7 @@ class PendingSignalsTests(unittest.TestCase):
@unittest.skipUnless(hasattr(signal, 'pthread_kill'), @unittest.skipUnless(hasattr(signal, 'pthread_kill'),
'need signal.pthread_kill()') 'need signal.pthread_kill()')
@threading_helper.requires_working_threading()
def test_pthread_kill_main_thread(self): def test_pthread_kill_main_thread(self):
# Test that a signal can be sent to the main thread with pthread_kill() # Test that a signal can be sent to the main thread with pthread_kill()
# before any other thread has been created (see issue #12392). # before any other thread has been created (see issue #12392).
@ -1298,6 +1303,7 @@ class StressTest(unittest.TestCase):
@unittest.skipUnless(hasattr(signal, "SIGUSR1"), @unittest.skipUnless(hasattr(signal, "SIGUSR1"),
"test needs SIGUSR1") "test needs SIGUSR1")
@threading_helper.requires_working_threading()
def test_stress_modifying_handlers(self): def test_stress_modifying_handlers(self):
# bpo-43406: race condition between trip_signal() and signal.signal # bpo-43406: race condition between trip_signal() and signal.signal
signum = signal.SIGUSR1 signum = signal.SIGUSR1

View File

@ -123,15 +123,18 @@ class TestSupport(unittest.TestCase):
os_helper.unlink(mod_filename) os_helper.unlink(mod_filename)
os_helper.rmtree('__pycache__') os_helper.rmtree('__pycache__')
@support.requires_working_socket()
def test_HOST(self): def test_HOST(self):
s = socket.create_server((socket_helper.HOST, 0)) s = socket.create_server((socket_helper.HOST, 0))
s.close() s.close()
@support.requires_working_socket()
def test_find_unused_port(self): def test_find_unused_port(self):
port = socket_helper.find_unused_port() port = socket_helper.find_unused_port()
s = socket.create_server((socket_helper.HOST, port)) s = socket.create_server((socket_helper.HOST, port))
s.close() s.close()
@support.requires_working_socket()
def test_bind_port(self): def test_bind_port(self):
s = socket.socket() s = socket.socket()
socket_helper.bind_port(s) socket_helper.bind_port(s)

View File

@ -401,6 +401,7 @@ class SysModuleTest(unittest.TestCase):
# sys._current_frames() is a CPython-only gimmick. # sys._current_frames() is a CPython-only gimmick.
@threading_helper.reap_threads @threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_current_frames(self): def test_current_frames(self):
import threading import threading
import traceback import traceback
@ -466,6 +467,7 @@ class SysModuleTest(unittest.TestCase):
t.join() t.join()
@threading_helper.reap_threads @threading_helper.reap_threads
@threading_helper.requires_working_threading()
def test_current_exceptions(self): def test_current_exceptions(self):
import threading import threading
import traceback import traceback
@ -1176,11 +1178,12 @@ class UnraisableHookTest(unittest.TestCase):
for moduleName in 'builtins', '__main__', 'some_module': for moduleName in 'builtins', '__main__', 'some_module':
with self.subTest(moduleName=moduleName): with self.subTest(moduleName=moduleName):
A.B.X.__module__ = moduleName A.B.X.__module__ = moduleName
with test.support.captured_stderr() as stderr, \ with test.support.captured_stderr() as stderr, test.support.swap_attr(
test.support.swap_attr(sys, 'unraisablehook', sys, 'unraisablehook', sys.__unraisablehook__
sys.__unraisablehook__): ):
expected = self.write_unraisable_exc( expected = self.write_unraisable_exc(
A.B.X(), "msg", "obj"); A.B.X(), "msg", "obj"
)
report = stderr.getvalue() report = stderr.getvalue()
self.assertIn(A.B.X.__qualname__, report) self.assertIn(A.B.X.__qualname__, report)
if moduleName in ['builtins', '__main__']: if moduleName in ['builtins', '__main__']:

View File

@ -9,6 +9,8 @@ import weakref
from test import lock_tests from test import lock_tests
threading_helper.requires_working_threading(module=True)
NUMTASKS = 10 NUMTASKS = 10
NUMTRIPS = 3 NUMTRIPS = 3
POLL_SLEEP = 0.010 # seconds = 10 ms POLL_SLEEP = 0.010 # seconds = 10 ms

View File

@ -21,6 +21,7 @@ import io
import threading import threading
from traceback import print_exc from traceback import print_exc
threading_helper.requires_working_threading(module=True)
NUM_THREADS = 20 NUM_THREADS = 20
FILES_PER_THREAD = 50 FILES_PER_THREAD = 50

View File

@ -25,6 +25,7 @@ from unittest import mock
from test import lock_tests from test import lock_tests
from test import support from test import support
threading_helper.requires_working_threading(module=True)
# Between fork() and exec(), only async-safe functions are allowed (issues # Between fork() and exec(), only async-safe functions are allowed (issues
# #12316 and #11870), and fork() from a worker thread is known to trigger # #12316 and #11870), and fork() from a worker thread is known to trigger

View File

@ -12,6 +12,9 @@ import threading
import _threading_local import _threading_local
threading_helper.requires_working_threading(module=True)
class Weak(object): class Weak(object):
pass pass

View File

@ -36,6 +36,7 @@ def send_signals():
os.kill(process_pid, signal.SIGUSR2) os.kill(process_pid, signal.SIGUSR2)
signalled_all.release() signalled_all.release()
@threading_helper.requires_working_threading()
class ThreadSignals(unittest.TestCase): class ThreadSignals(unittest.TestCase):
def test_signals(self): def test_signals(self):

View File

@ -14,6 +14,7 @@ import random
from test import support from test import support
from test.support import script_helper, ALWAYS_EQ from test.support import script_helper, ALWAYS_EQ
from test.support import gc_collect from test.support import gc_collect
from test.support import threading_helper
# Used in ReferencesTestCase.test_ref_created_during_del() . # Used in ReferencesTestCase.test_ref_created_during_del() .
ref_from_del = None ref_from_del = None
@ -1851,6 +1852,7 @@ class MappingTestCase(TestBase):
dict = weakref.WeakKeyDictionary() dict = weakref.WeakKeyDictionary()
self.assertRegex(repr(dict), '<WeakKeyDictionary at 0x.*>') self.assertRegex(repr(dict), '<WeakKeyDictionary at 0x.*>')
@threading_helper.requires_working_threading()
def test_threaded_weak_valued_setdefault(self): def test_threaded_weak_valued_setdefault(self):
d = weakref.WeakValueDictionary() d = weakref.WeakValueDictionary()
with collect_in_thread(): with collect_in_thread():
@ -1859,6 +1861,7 @@ class MappingTestCase(TestBase):
self.assertIsNot(x, None) # we never put None in there! self.assertIsNot(x, None) # we never put None in there!
del x del x
@threading_helper.requires_working_threading()
def test_threaded_weak_valued_pop(self): def test_threaded_weak_valued_pop(self):
d = weakref.WeakValueDictionary() d = weakref.WeakValueDictionary()
with collect_in_thread(): with collect_in_thread():
@ -1867,6 +1870,7 @@ class MappingTestCase(TestBase):
x = d.pop(10, 10) x = d.pop(10, 10)
self.assertIsNot(x, None) # we never put None in there! self.assertIsNot(x, None) # we never put None in there!
@threading_helper.requires_working_threading()
def test_threaded_weak_valued_consistency(self): def test_threaded_weak_valued_consistency(self):
# Issue #28427: old keys should not remove new values from # Issue #28427: old keys should not remove new values from
# WeakValueDictionary when collecting from another thread. # WeakValueDictionary when collecting from another thread.
@ -1940,21 +1944,25 @@ class MappingTestCase(TestBase):
if exc: if exc:
raise exc[0] raise exc[0]
@threading_helper.requires_working_threading()
def test_threaded_weak_key_dict_copy(self): def test_threaded_weak_key_dict_copy(self):
# Issue #35615: Weakref keys or values getting GC'ed during dict # Issue #35615: Weakref keys or values getting GC'ed during dict
# copying should not result in a crash. # copying should not result in a crash.
self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, False) self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, False)
@threading_helper.requires_working_threading()
def test_threaded_weak_key_dict_deepcopy(self): def test_threaded_weak_key_dict_deepcopy(self):
# Issue #35615: Weakref keys or values getting GC'ed during dict # Issue #35615: Weakref keys or values getting GC'ed during dict
# copying should not result in a crash. # copying should not result in a crash.
self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, True) self.check_threaded_weak_dict_copy(weakref.WeakKeyDictionary, True)
@threading_helper.requires_working_threading()
def test_threaded_weak_value_dict_copy(self): def test_threaded_weak_value_dict_copy(self):
# Issue #35615: Weakref keys or values getting GC'ed during dict # Issue #35615: Weakref keys or values getting GC'ed during dict
# copying should not result in a crash. # copying should not result in a crash.
self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, False) self.check_threaded_weak_dict_copy(weakref.WeakValueDictionary, False)
@threading_helper.requires_working_threading()
def test_threaded_weak_value_dict_deepcopy(self): def test_threaded_weak_value_dict_deepcopy(self):
# Issue #35615: Weakref keys or values getting GC'ed during dict # Issue #35615: Weakref keys or values getting GC'ed during dict
# copying should not result in a crash. # copying should not result in a crash.

View File

@ -0,0 +1 @@
Threading tests are now skipped on WASM targets without pthread support.

10
configure generated vendored
View File

@ -6311,15 +6311,7 @@ esac
else else
case $ac_sys_system in #( enable_wasm_dynamic_linking=missing
Emscripten) :
enable_wasm_dynamic_linking=no ;; #(
WASI) :
enable_wasm_dynamic_linking=no ;; #(
*) :
enable_wasm_dynamic_linking=missing
;;
esac
fi fi

View File

@ -1122,11 +1122,7 @@ AC_ARG_ENABLE([wasm-dynamic-linking],
[AC_MSG_ERROR([--enable-wasm-dynamic-linking only applies to Emscripten and WASI])] [AC_MSG_ERROR([--enable-wasm-dynamic-linking only applies to Emscripten and WASI])]
) )
], [ ], [
AS_CASE([$ac_sys_system], enable_wasm_dynamic_linking=missing
[Emscripten], [enable_wasm_dynamic_linking=no],
[WASI], [enable_wasm_dynamic_linking=no],
[enable_wasm_dynamic_linking=missing]
)
]) ])
AC_MSG_RESULT([$enable_wasm_dynamic_linking]) AC_MSG_RESULT([$enable_wasm_dynamic_linking])