mirror of
https://github.com/bunny-lab-io/Borealis.git
synced 2025-07-28 08:08:28 -06:00
Removed the Requirement to Install Python and NodeJS (Now Bundled with Borealis)
This commit is contained in:
11
Dependencies/Python/Lib/test/test_free_threading/__init__.py
vendored
Normal file
11
Dependencies/Python/Lib/test/test_free_threading/__init__.py
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
import os
|
||||
import unittest
|
||||
|
||||
from test import support
|
||||
|
||||
|
||||
if not support.Py_GIL_DISABLED:
|
||||
raise unittest.SkipTest("GIL enabled")
|
||||
|
||||
def load_tests(*args):
|
||||
return support.load_package_tests(os.path.dirname(__file__), *args)
|
30
Dependencies/Python/Lib/test/test_free_threading/test_code.py
vendored
Normal file
30
Dependencies/Python/Lib/test/test_free_threading/test_code.py
vendored
Normal file
@ -0,0 +1,30 @@
|
||||
import unittest
|
||||
|
||||
from threading import Thread
|
||||
from unittest import TestCase
|
||||
|
||||
from test.support import threading_helper
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestCode(TestCase):
|
||||
def test_code_attrs(self):
|
||||
"""Test concurrent accesses to lazily initialized code attributes"""
|
||||
code_objects = []
|
||||
for _ in range(1000):
|
||||
code_objects.append(compile("a + b", "<string>", "eval"))
|
||||
|
||||
def run_in_thread():
|
||||
for code in code_objects:
|
||||
self.assertIsInstance(code.co_code, bytes)
|
||||
self.assertIsInstance(code.co_freevars, tuple)
|
||||
self.assertIsInstance(code.co_varnames, tuple)
|
||||
|
||||
threads = [Thread(target=run_in_thread) for _ in range(2)]
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
182
Dependencies/Python/Lib/test/test_free_threading/test_dict.py
vendored
Normal file
182
Dependencies/Python/Lib/test/test_free_threading/test_dict.py
vendored
Normal file
@ -0,0 +1,182 @@
|
||||
import gc
|
||||
import time
|
||||
import unittest
|
||||
import weakref
|
||||
|
||||
from ast import Or
|
||||
from functools import partial
|
||||
from threading import Thread
|
||||
from unittest import TestCase
|
||||
|
||||
try:
|
||||
import _testcapi
|
||||
except ImportError:
|
||||
_testcapi = None
|
||||
|
||||
from test.support import threading_helper
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestDict(TestCase):
|
||||
def test_racing_creation_shared_keys(self):
|
||||
"""Verify that creating dictionaries is thread safe when we
|
||||
have a type with shared keys"""
|
||||
class C(int):
|
||||
pass
|
||||
|
||||
self.racing_creation(C)
|
||||
|
||||
def test_racing_creation_no_shared_keys(self):
|
||||
"""Verify that creating dictionaries is thread safe when we
|
||||
have a type with an ordinary dict"""
|
||||
self.racing_creation(Or)
|
||||
|
||||
def test_racing_creation_inline_values_invalid(self):
|
||||
"""Verify that re-creating a dict after we have invalid inline values
|
||||
is thread safe"""
|
||||
class C:
|
||||
pass
|
||||
|
||||
def make_obj():
|
||||
a = C()
|
||||
# Make object, make inline values invalid, and then delete dict
|
||||
a.__dict__ = {}
|
||||
del a.__dict__
|
||||
return a
|
||||
|
||||
self.racing_creation(make_obj)
|
||||
|
||||
def test_racing_creation_nonmanaged_dict(self):
|
||||
"""Verify that explicit creation of an unmanaged dict is thread safe
|
||||
outside of the normal attribute setting code path"""
|
||||
def make_obj():
|
||||
def f(): pass
|
||||
return f
|
||||
|
||||
def set(func, name, val):
|
||||
# Force creation of the dict via PyObject_GenericGetDict
|
||||
func.__dict__[name] = val
|
||||
|
||||
self.racing_creation(make_obj, set)
|
||||
|
||||
def racing_creation(self, cls, set=setattr):
|
||||
objects = []
|
||||
processed = []
|
||||
|
||||
OBJECT_COUNT = 100
|
||||
THREAD_COUNT = 10
|
||||
CUR = 0
|
||||
|
||||
for i in range(OBJECT_COUNT):
|
||||
objects.append(cls())
|
||||
|
||||
def writer_func(name):
|
||||
last = -1
|
||||
while True:
|
||||
if CUR == last:
|
||||
continue
|
||||
elif CUR == OBJECT_COUNT:
|
||||
break
|
||||
|
||||
obj = objects[CUR]
|
||||
set(obj, name, name)
|
||||
last = CUR
|
||||
processed.append(name)
|
||||
|
||||
writers = []
|
||||
for x in range(THREAD_COUNT):
|
||||
writer = Thread(target=partial(writer_func, f"a{x:02}"))
|
||||
writers.append(writer)
|
||||
writer.start()
|
||||
|
||||
for i in range(OBJECT_COUNT):
|
||||
CUR = i
|
||||
while len(processed) != THREAD_COUNT:
|
||||
time.sleep(0.001)
|
||||
processed.clear()
|
||||
|
||||
CUR = OBJECT_COUNT
|
||||
|
||||
for writer in writers:
|
||||
writer.join()
|
||||
|
||||
for obj_idx, obj in enumerate(objects):
|
||||
assert (
|
||||
len(obj.__dict__) == THREAD_COUNT
|
||||
), f"{len(obj.__dict__)} {obj.__dict__!r} {obj_idx}"
|
||||
for i in range(THREAD_COUNT):
|
||||
assert f"a{i:02}" in obj.__dict__, f"a{i:02} missing at {obj_idx}"
|
||||
|
||||
def test_racing_set_dict(self):
|
||||
"""Races assigning to __dict__ should be thread safe"""
|
||||
|
||||
def f(): pass
|
||||
l = []
|
||||
THREAD_COUNT = 10
|
||||
class MyDict(dict): pass
|
||||
|
||||
def writer_func(l):
|
||||
for i in range(1000):
|
||||
d = MyDict()
|
||||
l.append(weakref.ref(d))
|
||||
f.__dict__ = d
|
||||
|
||||
lists = []
|
||||
writers = []
|
||||
for x in range(THREAD_COUNT):
|
||||
thread_list = []
|
||||
lists.append(thread_list)
|
||||
writer = Thread(target=partial(writer_func, thread_list))
|
||||
writers.append(writer)
|
||||
|
||||
for writer in writers:
|
||||
writer.start()
|
||||
|
||||
for writer in writers:
|
||||
writer.join()
|
||||
|
||||
f.__dict__ = {}
|
||||
gc.collect()
|
||||
|
||||
for thread_list in lists:
|
||||
for ref in thread_list:
|
||||
self.assertIsNone(ref())
|
||||
|
||||
@unittest.skipIf(_testcapi is None, 'need _testcapi module')
|
||||
def test_dict_version(self):
|
||||
dict_version = _testcapi.dict_version
|
||||
THREAD_COUNT = 10
|
||||
DICT_COUNT = 10000
|
||||
lists = []
|
||||
writers = []
|
||||
|
||||
def writer_func(thread_list):
|
||||
for i in range(DICT_COUNT):
|
||||
thread_list.append(dict_version({}))
|
||||
|
||||
for x in range(THREAD_COUNT):
|
||||
thread_list = []
|
||||
lists.append(thread_list)
|
||||
writer = Thread(target=partial(writer_func, thread_list))
|
||||
writers.append(writer)
|
||||
|
||||
for writer in writers:
|
||||
writer.start()
|
||||
|
||||
for writer in writers:
|
||||
writer.join()
|
||||
|
||||
total_len = 0
|
||||
values = set()
|
||||
for thread_list in lists:
|
||||
for v in thread_list:
|
||||
if v in values:
|
||||
print('dup', v, (v/4096)%256)
|
||||
values.add(v)
|
||||
total_len += len(thread_list)
|
||||
versions = set(dict_version for thread_list in lists for dict_version in thread_list)
|
||||
self.assertEqual(len(versions), THREAD_COUNT*DICT_COUNT)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
67
Dependencies/Python/Lib/test/test_free_threading/test_func_annotations.py
vendored
Normal file
67
Dependencies/Python/Lib/test/test_free_threading/test_func_annotations.py
vendored
Normal file
@ -0,0 +1,67 @@
|
||||
import concurrent.futures
|
||||
import unittest
|
||||
import inspect
|
||||
from threading import Thread, Barrier
|
||||
from unittest import TestCase
|
||||
|
||||
from test.support import threading_helper, Py_GIL_DISABLED
|
||||
|
||||
threading_helper.requires_working_threading(module=True)
|
||||
|
||||
|
||||
def get_func_annotation(f, b):
|
||||
b.wait()
|
||||
return inspect.get_annotations(f)
|
||||
|
||||
|
||||
def get_func_annotation_dunder(f, b):
|
||||
b.wait()
|
||||
return f.__annotations__
|
||||
|
||||
|
||||
def set_func_annotation(f, b):
|
||||
b.wait()
|
||||
f.__annotations__ = {'x': int, 'y': int, 'return': int}
|
||||
return f.__annotations__
|
||||
|
||||
|
||||
@unittest.skipUnless(Py_GIL_DISABLED, "Enable only in FT build")
|
||||
class TestFTFuncAnnotations(TestCase):
|
||||
NUM_THREADS = 8
|
||||
|
||||
def test_concurrent_read(self):
|
||||
def f(x: int) -> int:
|
||||
return x + 1
|
||||
|
||||
for _ in range(100):
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor:
|
||||
b = Barrier(self.NUM_THREADS)
|
||||
futures = {executor.submit(get_func_annotation, f, b): i for i in range(self.NUM_THREADS)}
|
||||
for fut in concurrent.futures.as_completed(futures):
|
||||
annotate = fut.result()
|
||||
self.assertIsNotNone(annotate)
|
||||
self.assertEqual(annotate, {'x': int, 'return': int})
|
||||
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor:
|
||||
b = Barrier(self.NUM_THREADS)
|
||||
futures = {executor.submit(get_func_annotation_dunder, f, b): i for i in range(self.NUM_THREADS)}
|
||||
for fut in concurrent.futures.as_completed(futures):
|
||||
annotate = fut.result()
|
||||
self.assertIsNotNone(annotate)
|
||||
self.assertEqual(annotate, {'x': int, 'return': int})
|
||||
|
||||
def test_concurrent_write(self):
|
||||
def bar(x: int, y: float) -> float:
|
||||
return y ** x
|
||||
|
||||
for _ in range(100):
|
||||
with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor:
|
||||
b = Barrier(self.NUM_THREADS)
|
||||
futures = {executor.submit(set_func_annotation, bar, b): i for i in range(self.NUM_THREADS)}
|
||||
for fut in concurrent.futures.as_completed(futures):
|
||||
annotate = fut.result()
|
||||
self.assertIsNotNone(annotate)
|
||||
self.assertEqual(annotate, {'x': int, 'y': int, 'return': int})
|
||||
|
||||
# func_get_annotations returns in-place dict, so bar.__annotations__ should be modified as well
|
||||
self.assertEqual(bar.__annotations__, {'x': int, 'y': int, 'return': int})
|
61
Dependencies/Python/Lib/test/test_free_threading/test_gc.py
vendored
Normal file
61
Dependencies/Python/Lib/test/test_free_threading/test_gc.py
vendored
Normal file
@ -0,0 +1,61 @@
|
||||
import unittest
|
||||
|
||||
import threading
|
||||
from threading import Thread
|
||||
from unittest import TestCase
|
||||
import gc
|
||||
|
||||
from test.support import threading_helper
|
||||
|
||||
|
||||
class MyObj:
|
||||
pass
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestGC(TestCase):
|
||||
def test_get_objects(self):
|
||||
event = threading.Event()
|
||||
|
||||
def gc_thread():
|
||||
for i in range(100):
|
||||
o = gc.get_objects()
|
||||
event.set()
|
||||
|
||||
def mutator_thread():
|
||||
while not event.is_set():
|
||||
o1 = MyObj()
|
||||
o2 = MyObj()
|
||||
o3 = MyObj()
|
||||
o4 = MyObj()
|
||||
|
||||
gcs = [Thread(target=gc_thread)]
|
||||
mutators = [Thread(target=mutator_thread) for _ in range(4)]
|
||||
with threading_helper.start_threads(gcs + mutators):
|
||||
pass
|
||||
|
||||
def test_get_referrers(self):
|
||||
event = threading.Event()
|
||||
|
||||
obj = MyObj()
|
||||
|
||||
def gc_thread():
|
||||
for i in range(100):
|
||||
o = gc.get_referrers(obj)
|
||||
event.set()
|
||||
|
||||
def mutator_thread():
|
||||
while not event.is_set():
|
||||
d1 = { "key": obj }
|
||||
d2 = { "key": obj }
|
||||
d3 = { "key": obj }
|
||||
d4 = { "key": obj }
|
||||
|
||||
gcs = [Thread(target=gc_thread) for _ in range(2)]
|
||||
mutators = [Thread(target=mutator_thread) for _ in range(4)]
|
||||
with threading_helper.start_threads(gcs + mutators):
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
76
Dependencies/Python/Lib/test/test_free_threading/test_list.py
vendored
Normal file
76
Dependencies/Python/Lib/test/test_free_threading/test_list.py
vendored
Normal file
@ -0,0 +1,76 @@
|
||||
import unittest
|
||||
|
||||
from threading import Thread
|
||||
from unittest import TestCase
|
||||
|
||||
from test.support import threading_helper
|
||||
|
||||
|
||||
NTHREAD = 10
|
||||
OBJECT_COUNT = 5_000
|
||||
|
||||
|
||||
class C:
|
||||
def __init__(self, v):
|
||||
self.v = v
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestList(TestCase):
|
||||
def test_racing_iter_append(self):
|
||||
l = []
|
||||
|
||||
def writer_func():
|
||||
for i in range(OBJECT_COUNT):
|
||||
l.append(C(i + OBJECT_COUNT))
|
||||
|
||||
def reader_func():
|
||||
while True:
|
||||
count = len(l)
|
||||
for i, x in enumerate(l):
|
||||
self.assertEqual(x.v, i + OBJECT_COUNT)
|
||||
if count == OBJECT_COUNT:
|
||||
break
|
||||
|
||||
writer = Thread(target=writer_func)
|
||||
readers = []
|
||||
for x in range(NTHREAD):
|
||||
reader = Thread(target=reader_func)
|
||||
readers.append(reader)
|
||||
reader.start()
|
||||
|
||||
writer.start()
|
||||
writer.join()
|
||||
for reader in readers:
|
||||
reader.join()
|
||||
|
||||
def test_racing_iter_extend(self):
|
||||
l = []
|
||||
|
||||
def writer_func():
|
||||
for i in range(OBJECT_COUNT):
|
||||
l.extend([C(i + OBJECT_COUNT)])
|
||||
|
||||
def reader_func():
|
||||
while True:
|
||||
count = len(l)
|
||||
for i, x in enumerate(l):
|
||||
self.assertEqual(x.v, i + OBJECT_COUNT)
|
||||
if count == OBJECT_COUNT:
|
||||
break
|
||||
|
||||
writer = Thread(target=writer_func)
|
||||
readers = []
|
||||
for x in range(NTHREAD):
|
||||
reader = Thread(target=reader_func)
|
||||
readers.append(reader)
|
||||
reader.start()
|
||||
|
||||
writer.start()
|
||||
writer.join()
|
||||
for reader in readers:
|
||||
reader.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
248
Dependencies/Python/Lib/test/test_free_threading/test_monitoring.py
vendored
Normal file
248
Dependencies/Python/Lib/test/test_free_threading/test_monitoring.py
vendored
Normal file
@ -0,0 +1,248 @@
|
||||
"""Tests monitoring, sys.settrace, and sys.setprofile in a multi-threaded
|
||||
environment to verify things are thread-safe in a free-threaded build"""
|
||||
|
||||
import sys
|
||||
import time
|
||||
import unittest
|
||||
import weakref
|
||||
|
||||
from sys import monitoring
|
||||
from test.support import threading_helper
|
||||
from threading import Thread, _PyRLock
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
class InstrumentationMultiThreadedMixin:
|
||||
thread_count = 10
|
||||
func_count = 50
|
||||
fib = 12
|
||||
|
||||
def after_threads(self):
|
||||
"""Runs once after all the threads have started"""
|
||||
pass
|
||||
|
||||
def during_threads(self):
|
||||
"""Runs repeatedly while the threads are still running"""
|
||||
pass
|
||||
|
||||
def work(self, n, funcs):
|
||||
"""Fibonacci function which also calls a bunch of random functions"""
|
||||
for func in funcs:
|
||||
func()
|
||||
if n < 2:
|
||||
return n
|
||||
return self.work(n - 1, funcs) + self.work(n - 2, funcs)
|
||||
|
||||
def start_work(self, n, funcs):
|
||||
# With the GIL builds we need to make sure that the hooks have
|
||||
# a chance to run as it's possible to run w/o releasing the GIL.
|
||||
time.sleep(0.1)
|
||||
self.work(n, funcs)
|
||||
|
||||
def after_test(self):
|
||||
"""Runs once after the test is done"""
|
||||
pass
|
||||
|
||||
def test_instrumentation(self):
|
||||
# Setup a bunch of functions which will need instrumentation...
|
||||
funcs = []
|
||||
for i in range(self.func_count):
|
||||
x = {}
|
||||
exec("def f(): pass", x)
|
||||
funcs.append(x["f"])
|
||||
|
||||
threads = []
|
||||
for i in range(self.thread_count):
|
||||
# Each thread gets a copy of the func list to avoid contention
|
||||
t = Thread(target=self.start_work, args=(self.fib, list(funcs)))
|
||||
t.start()
|
||||
threads.append(t)
|
||||
|
||||
self.after_threads()
|
||||
|
||||
while True:
|
||||
any_alive = False
|
||||
for t in threads:
|
||||
if t.is_alive():
|
||||
any_alive = True
|
||||
break
|
||||
|
||||
if not any_alive:
|
||||
break
|
||||
|
||||
self.during_threads()
|
||||
|
||||
self.after_test()
|
||||
|
||||
|
||||
class MonitoringTestMixin:
|
||||
def setUp(self):
|
||||
for i in range(6):
|
||||
if monitoring.get_tool(i) is None:
|
||||
self.tool_id = i
|
||||
monitoring.use_tool_id(i, self.__class__.__name__)
|
||||
break
|
||||
|
||||
def tearDown(self):
|
||||
monitoring.free_tool_id(self.tool_id)
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class SetPreTraceMultiThreaded(InstrumentationMultiThreadedMixin, TestCase):
|
||||
"""Sets tracing one time after the threads have started"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.called = False
|
||||
|
||||
def after_test(self):
|
||||
self.assertTrue(self.called)
|
||||
|
||||
def trace_func(self, frame, event, arg):
|
||||
self.called = True
|
||||
return self.trace_func
|
||||
|
||||
def after_threads(self):
|
||||
sys.settrace(self.trace_func)
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class MonitoringMultiThreaded(
|
||||
MonitoringTestMixin, InstrumentationMultiThreadedMixin, TestCase
|
||||
):
|
||||
"""Uses sys.monitoring and repeatedly toggles instrumentation on and off"""
|
||||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.set = False
|
||||
self.called = False
|
||||
monitoring.register_callback(
|
||||
self.tool_id, monitoring.events.LINE, self.callback
|
||||
)
|
||||
|
||||
def tearDown(self):
|
||||
monitoring.set_events(self.tool_id, 0)
|
||||
super().tearDown()
|
||||
|
||||
def callback(self, *args):
|
||||
self.called = True
|
||||
|
||||
def after_test(self):
|
||||
self.assertTrue(self.called)
|
||||
|
||||
def during_threads(self):
|
||||
if self.set:
|
||||
monitoring.set_events(
|
||||
self.tool_id, monitoring.events.CALL | monitoring.events.LINE
|
||||
)
|
||||
else:
|
||||
monitoring.set_events(self.tool_id, 0)
|
||||
self.set = not self.set
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class SetTraceMultiThreaded(InstrumentationMultiThreadedMixin, TestCase):
|
||||
"""Uses sys.settrace and repeatedly toggles instrumentation on and off"""
|
||||
|
||||
def setUp(self):
|
||||
self.set = False
|
||||
self.called = False
|
||||
|
||||
def after_test(self):
|
||||
self.assertTrue(self.called)
|
||||
|
||||
def tearDown(self):
|
||||
sys.settrace(None)
|
||||
|
||||
def trace_func(self, frame, event, arg):
|
||||
self.called = True
|
||||
return self.trace_func
|
||||
|
||||
def during_threads(self):
|
||||
if self.set:
|
||||
sys.settrace(self.trace_func)
|
||||
else:
|
||||
sys.settrace(None)
|
||||
self.set = not self.set
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class SetProfileMultiThreaded(InstrumentationMultiThreadedMixin, TestCase):
|
||||
"""Uses sys.setprofile and repeatedly toggles instrumentation on and off"""
|
||||
|
||||
def setUp(self):
|
||||
self.set = False
|
||||
self.called = False
|
||||
|
||||
def after_test(self):
|
||||
self.assertTrue(self.called)
|
||||
|
||||
def tearDown(self):
|
||||
sys.setprofile(None)
|
||||
|
||||
def trace_func(self, frame, event, arg):
|
||||
self.called = True
|
||||
return self.trace_func
|
||||
|
||||
def during_threads(self):
|
||||
if self.set:
|
||||
sys.setprofile(self.trace_func)
|
||||
else:
|
||||
sys.setprofile(None)
|
||||
self.set = not self.set
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class MonitoringMisc(MonitoringTestMixin, TestCase):
|
||||
def register_callback(self):
|
||||
def callback(*args):
|
||||
pass
|
||||
|
||||
for i in range(200):
|
||||
monitoring.register_callback(self.tool_id, monitoring.events.LINE, callback)
|
||||
|
||||
self.refs.append(weakref.ref(callback))
|
||||
|
||||
def test_register_callback(self):
|
||||
self.refs = []
|
||||
threads = []
|
||||
for i in range(50):
|
||||
t = Thread(target=self.register_callback)
|
||||
t.start()
|
||||
threads.append(t)
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
monitoring.register_callback(self.tool_id, monitoring.events.LINE, None)
|
||||
for ref in self.refs:
|
||||
self.assertEqual(ref(), None)
|
||||
|
||||
def test_set_local_trace_opcodes(self):
|
||||
def trace(frame, event, arg):
|
||||
frame.f_trace_opcodes = True
|
||||
return trace
|
||||
|
||||
loops = 1_000
|
||||
|
||||
sys.settrace(trace)
|
||||
try:
|
||||
l = _PyRLock()
|
||||
|
||||
def f():
|
||||
for i in range(loops):
|
||||
with l:
|
||||
pass
|
||||
|
||||
t = Thread(target=f)
|
||||
t.start()
|
||||
for i in range(loops):
|
||||
with l:
|
||||
pass
|
||||
t.join()
|
||||
finally:
|
||||
sys.settrace(None)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
41
Dependencies/Python/Lib/test/test_free_threading/test_set.py
vendored
Normal file
41
Dependencies/Python/Lib/test/test_free_threading/test_set.py
vendored
Normal file
@ -0,0 +1,41 @@
|
||||
import unittest
|
||||
|
||||
from threading import Thread, Barrier
|
||||
from unittest import TestCase
|
||||
|
||||
from test.support import threading_helper
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestSet(TestCase):
|
||||
def test_repr_clear(self):
|
||||
"""Test repr() of a set while another thread is calling clear()"""
|
||||
NUM_ITERS = 10
|
||||
NUM_REPR_THREADS = 10
|
||||
barrier = Barrier(NUM_REPR_THREADS + 1)
|
||||
s = {1, 2, 3, 4, 5, 6, 7, 8}
|
||||
|
||||
def clear_set():
|
||||
barrier.wait()
|
||||
s.clear()
|
||||
|
||||
def repr_set():
|
||||
barrier.wait()
|
||||
set_reprs.append(repr(s))
|
||||
|
||||
for _ in range(NUM_ITERS):
|
||||
set_reprs = []
|
||||
threads = [Thread(target=clear_set)]
|
||||
for _ in range(NUM_REPR_THREADS):
|
||||
threads.append(Thread(target=repr_set))
|
||||
for t in threads:
|
||||
t.start()
|
||||
for t in threads:
|
||||
t.join()
|
||||
|
||||
for set_repr in set_reprs:
|
||||
self.assertIn(set_repr, ("set()", "{1, 2, 3, 4, 5, 6, 7, 8}"))
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
43
Dependencies/Python/Lib/test/test_free_threading/test_slots.py
vendored
Normal file
43
Dependencies/Python/Lib/test/test_free_threading/test_slots.py
vendored
Normal file
@ -0,0 +1,43 @@
|
||||
import threading
|
||||
from test.support import threading_helper
|
||||
from unittest import TestCase
|
||||
|
||||
|
||||
def run_in_threads(targets):
|
||||
"""Run `targets` in separate threads"""
|
||||
threads = [
|
||||
threading.Thread(target=target)
|
||||
for target in targets
|
||||
]
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestSlots(TestCase):
|
||||
|
||||
def test_object(self):
|
||||
class Spam:
|
||||
__slots__ = [
|
||||
"eggs",
|
||||
]
|
||||
|
||||
def __init__(self, initial_value):
|
||||
self.eggs = initial_value
|
||||
|
||||
spam = Spam(0)
|
||||
iters = 20_000
|
||||
|
||||
def writer():
|
||||
for _ in range(iters):
|
||||
spam.eggs += 1
|
||||
|
||||
def reader():
|
||||
for _ in range(iters):
|
||||
eggs = spam.eggs
|
||||
assert type(eggs) is int
|
||||
assert 0 <= eggs <= iters
|
||||
|
||||
run_in_threads([writer, reader, reader, reader])
|
75
Dependencies/Python/Lib/test/test_free_threading/test_str.py
vendored
Normal file
75
Dependencies/Python/Lib/test/test_free_threading/test_str.py
vendored
Normal file
@ -0,0 +1,75 @@
|
||||
import sys
|
||||
import unittest
|
||||
|
||||
from itertools import cycle
|
||||
from threading import Event, Thread
|
||||
from unittest import TestCase
|
||||
|
||||
from test.support import threading_helper
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestStr(TestCase):
|
||||
def test_racing_join_extend(self):
|
||||
'''Test joining a string being extended by another thread'''
|
||||
l = []
|
||||
ITERS = 100
|
||||
READERS = 10
|
||||
done_event = Event()
|
||||
def writer_func():
|
||||
for i in range(ITERS):
|
||||
l.extend(map(str, range(i)))
|
||||
l.clear()
|
||||
done_event.set()
|
||||
def reader_func():
|
||||
while not done_event.is_set():
|
||||
''.join(l)
|
||||
writer = Thread(target=writer_func)
|
||||
readers = []
|
||||
for x in range(READERS):
|
||||
reader = Thread(target=reader_func)
|
||||
readers.append(reader)
|
||||
reader.start()
|
||||
|
||||
writer.start()
|
||||
writer.join()
|
||||
for reader in readers:
|
||||
reader.join()
|
||||
|
||||
def test_racing_join_replace(self):
|
||||
'''
|
||||
Test joining a string of characters being replaced with ephemeral
|
||||
strings by another thread.
|
||||
'''
|
||||
l = [*'abcdefg']
|
||||
MAX_ORDINAL = 1_000
|
||||
READERS = 10
|
||||
done_event = Event()
|
||||
|
||||
def writer_func():
|
||||
for i, c in zip(cycle(range(len(l))),
|
||||
map(chr, range(128, MAX_ORDINAL))):
|
||||
l[i] = c
|
||||
done_event.set()
|
||||
|
||||
def reader_func():
|
||||
while not done_event.is_set():
|
||||
''.join(l)
|
||||
''.join(l)
|
||||
''.join(l)
|
||||
''.join(l)
|
||||
|
||||
writer = Thread(target=writer_func)
|
||||
readers = []
|
||||
for x in range(READERS):
|
||||
reader = Thread(target=reader_func)
|
||||
readers.append(reader)
|
||||
reader.start()
|
||||
|
||||
writer.start()
|
||||
writer.join()
|
||||
for reader in readers:
|
||||
reader.join()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
57
Dependencies/Python/Lib/test/test_free_threading/test_tokenize.py
vendored
Normal file
57
Dependencies/Python/Lib/test/test_free_threading/test_tokenize.py
vendored
Normal file
@ -0,0 +1,57 @@
|
||||
import io
|
||||
import time
|
||||
import unittest
|
||||
import tokenize
|
||||
from functools import partial
|
||||
from threading import Thread
|
||||
|
||||
from test.support import threading_helper
|
||||
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestTokenize(unittest.TestCase):
|
||||
def test_tokenizer_iter(self):
|
||||
source = io.StringIO("for _ in a:\n pass")
|
||||
it = tokenize._tokenize.TokenizerIter(source.readline, extra_tokens=False)
|
||||
|
||||
tokens = []
|
||||
def next_token(it):
|
||||
while True:
|
||||
try:
|
||||
r = next(it)
|
||||
tokens.append(tokenize.TokenInfo._make(r))
|
||||
time.sleep(0.03)
|
||||
except StopIteration:
|
||||
return
|
||||
|
||||
threads = []
|
||||
for _ in range(5):
|
||||
threads.append(Thread(target=partial(next_token, it)))
|
||||
|
||||
for thread in threads:
|
||||
thread.start()
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
expected_tokens = [
|
||||
tokenize.TokenInfo(type=1, string='for', start=(1, 0), end=(1, 3), line='for _ in a:\n'),
|
||||
tokenize.TokenInfo(type=1, string='_', start=(1, 4), end=(1, 5), line='for _ in a:\n'),
|
||||
tokenize.TokenInfo(type=1, string='in', start=(1, 6), end=(1, 8), line='for _ in a:\n'),
|
||||
tokenize.TokenInfo(type=1, string='a', start=(1, 9), end=(1, 10), line='for _ in a:\n'),
|
||||
tokenize.TokenInfo(type=11, string=':', start=(1, 10), end=(1, 11), line='for _ in a:\n'),
|
||||
tokenize.TokenInfo(type=4, string='', start=(1, 11), end=(1, 11), line='for _ in a:\n'),
|
||||
tokenize.TokenInfo(type=5, string='', start=(2, -1), end=(2, -1), line=' pass'),
|
||||
tokenize.TokenInfo(type=1, string='pass', start=(2, 2), end=(2, 6), line=' pass'),
|
||||
tokenize.TokenInfo(type=4, string='', start=(2, 6), end=(2, 6), line=' pass'),
|
||||
tokenize.TokenInfo(type=6, string='', start=(2, -1), end=(2, -1), line=' pass'),
|
||||
tokenize.TokenInfo(type=0, string='', start=(2, -1), end=(2, -1), line=' pass'),
|
||||
]
|
||||
|
||||
tokens.sort()
|
||||
expected_tokens.sort()
|
||||
self.assertListEqual(tokens, expected_tokens)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
157
Dependencies/Python/Lib/test/test_free_threading/test_type.py
vendored
Normal file
157
Dependencies/Python/Lib/test/test_free_threading/test_type.py
vendored
Normal file
@ -0,0 +1,157 @@
|
||||
import threading
|
||||
import unittest
|
||||
|
||||
from concurrent.futures import ThreadPoolExecutor
|
||||
from threading import Thread
|
||||
from unittest import TestCase
|
||||
|
||||
from test import support
|
||||
from test.support import threading_helper
|
||||
|
||||
|
||||
|
||||
NTHREADS = 6
|
||||
BOTTOM = 0
|
||||
TOP = 1000
|
||||
ITERS = 100
|
||||
|
||||
class A:
|
||||
attr = 1
|
||||
|
||||
@threading_helper.requires_working_threading()
|
||||
class TestType(TestCase):
|
||||
def test_attr_cache(self):
|
||||
def read(id0):
|
||||
for _ in range(ITERS):
|
||||
for _ in range(BOTTOM, TOP):
|
||||
A.attr
|
||||
|
||||
def write(id0):
|
||||
for _ in range(ITERS):
|
||||
for _ in range(BOTTOM, TOP):
|
||||
# Make _PyType_Lookup cache hot first
|
||||
A.attr
|
||||
A.attr
|
||||
x = A.attr
|
||||
x += 1
|
||||
A.attr = x
|
||||
|
||||
|
||||
with ThreadPoolExecutor(NTHREADS) as pool:
|
||||
pool.submit(read, (1,))
|
||||
pool.submit(write, (1,))
|
||||
pool.shutdown(wait=True)
|
||||
|
||||
def test_attr_cache_consistency(self):
|
||||
class C:
|
||||
x = 0
|
||||
|
||||
DONE = False
|
||||
def writer_func():
|
||||
for i in range(3000):
|
||||
C.x
|
||||
C.x
|
||||
C.x += 1
|
||||
nonlocal DONE
|
||||
DONE = True
|
||||
|
||||
def reader_func():
|
||||
while True:
|
||||
# We should always see a greater value read from the type than the
|
||||
# dictionary
|
||||
a = C.__dict__['x']
|
||||
b = C.x
|
||||
self.assertGreaterEqual(b, a)
|
||||
|
||||
if DONE:
|
||||
break
|
||||
|
||||
self.run_one(writer_func, reader_func)
|
||||
|
||||
def test_attr_cache_consistency_subclass(self):
|
||||
class C:
|
||||
x = 0
|
||||
|
||||
class D(C):
|
||||
pass
|
||||
|
||||
DONE = False
|
||||
def writer_func():
|
||||
for i in range(3000):
|
||||
D.x
|
||||
D.x
|
||||
C.x += 1
|
||||
nonlocal DONE
|
||||
DONE = True
|
||||
|
||||
def reader_func():
|
||||
while True:
|
||||
# We should always see a greater value read from the type than the
|
||||
# dictionary
|
||||
a = C.__dict__['x']
|
||||
b = D.x
|
||||
self.assertGreaterEqual(b, a)
|
||||
|
||||
if DONE:
|
||||
break
|
||||
|
||||
self.run_one(writer_func, reader_func)
|
||||
|
||||
def test___class___modification(self):
|
||||
loops = 200
|
||||
|
||||
class Foo:
|
||||
pass
|
||||
|
||||
class Bar:
|
||||
pass
|
||||
|
||||
thing = Foo()
|
||||
def work():
|
||||
foo = thing
|
||||
for _ in range(loops):
|
||||
foo.__class__ = Bar
|
||||
type(foo)
|
||||
foo.__class__ = Foo
|
||||
type(foo)
|
||||
|
||||
|
||||
threads = []
|
||||
for i in range(NTHREADS):
|
||||
thread = threading.Thread(target=work)
|
||||
thread.start()
|
||||
threads.append(thread)
|
||||
|
||||
for thread in threads:
|
||||
thread.join()
|
||||
|
||||
def test_object_class_change(self):
|
||||
class Base:
|
||||
def __init__(self):
|
||||
self.attr = 123
|
||||
class ClassA(Base):
|
||||
pass
|
||||
class ClassB(Base):
|
||||
pass
|
||||
|
||||
obj = ClassA()
|
||||
# keep reference to __dict__
|
||||
d = obj.__dict__
|
||||
obj.__class__ = ClassB
|
||||
|
||||
|
||||
def run_one(self, writer_func, reader_func):
|
||||
writer = Thread(target=writer_func)
|
||||
readers = []
|
||||
for x in range(30):
|
||||
reader = Thread(target=reader_func)
|
||||
readers.append(reader)
|
||||
reader.start()
|
||||
|
||||
writer.start()
|
||||
writer.join()
|
||||
for reader in readers:
|
||||
reader.join()
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
Reference in New Issue
Block a user