Skip to content

Commit 5b9891f

Browse files
Merge branch 'main' into gh-100926-ctypes-pointers-cache
2 parents 87f8cf3 + 3d4ac1a commit 5b9891f

24 files changed

Lines changed: 450 additions & 446 deletions

Doc/library/sys.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,9 @@ always available. Unless explicitly noted otherwise, all variables are read-only
12471247

12481248
.. versionadded:: 3.13
12491249

1250+
.. impl-detail::
1251+
1252+
It is not guaranteed to exist in all implementations of Python.
12501253

12511254
.. function:: is_finalizing()
12521255

Doc/whatsnew/3.12.rst

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,14 @@ pathlib
811811
:meth:`pathlib.Path.rglob` and :meth:`pathlib.PurePath.match` for matching
812812
the path's case sensitivity, allowing for more precise control over the matching process.
813813

814+
platform
815+
--------
816+
817+
* Add support for detecting Windows 11 and Windows Server releases past 2012.
818+
Previously, lookups on Windows Server platforms newer than Windows Server 2012
819+
and on Windows 11 would return ``Windows-10``.
820+
(Contributed by Steve Dower in :gh:`89545`.)
821+
814822
pdb
815823
---
816824

Include/internal/pycore_cell.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
#define Py_INTERNAL_CELL_H
33

44
#include "pycore_critical_section.h"
5+
#include "pycore_object.h"
6+
#include "pycore_stackref.h"
57

68
#ifdef __cplusplus
79
extern "C" {
@@ -19,7 +21,7 @@ PyCell_SwapTakeRef(PyCellObject *cell, PyObject *value)
1921
PyObject *old_value;
2022
Py_BEGIN_CRITICAL_SECTION(cell);
2123
old_value = cell->ob_ref;
22-
cell->ob_ref = value;
24+
FT_ATOMIC_STORE_PTR_RELEASE(cell->ob_ref, value);
2325
Py_END_CRITICAL_SECTION();
2426
return old_value;
2527
}
@@ -37,11 +39,36 @@ PyCell_GetRef(PyCellObject *cell)
3739
{
3840
PyObject *res;
3941
Py_BEGIN_CRITICAL_SECTION(cell);
42+
#ifdef Py_GIL_DISABLED
43+
res = _Py_XNewRefWithLock(cell->ob_ref);
44+
#else
4045
res = Py_XNewRef(cell->ob_ref);
46+
#endif
4147
Py_END_CRITICAL_SECTION();
4248
return res;
4349
}
4450

51+
static inline _PyStackRef
52+
_PyCell_GetStackRef(PyCellObject *cell)
53+
{
54+
PyObject *value;
55+
#ifdef Py_GIL_DISABLED
56+
value = _Py_atomic_load_ptr(&cell->ob_ref);
57+
if (value == NULL) {
58+
return PyStackRef_NULL;
59+
}
60+
_PyStackRef ref;
61+
if (_Py_TryIncrefCompareStackRef(&cell->ob_ref, value, &ref)) {
62+
return ref;
63+
}
64+
#endif
65+
value = PyCell_GetRef(cell);
66+
if (value == NULL) {
67+
return PyStackRef_NULL;
68+
}
69+
return PyStackRef_FromPyObjectSteal(value);
70+
}
71+
4572
#ifdef __cplusplus
4673
}
4774
#endif

Include/internal/pycore_opcode_metadata.h

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Include/internal/pycore_uop_metadata.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Lib/test/test_free_threading/test_dict.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,7 @@ def writer_func(name):
7474
last = -1
7575
while True:
7676
if CUR == last:
77+
time.sleep(0.001)
7778
continue
7879
elif CUR == OBJECT_COUNT:
7980
break

Lib/test/test_free_threading/test_func_annotations.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,13 @@ def set_func_annotation(f, b):
2727

2828
@unittest.skipUnless(Py_GIL_DISABLED, "Enable only in FT build")
2929
class TestFTFuncAnnotations(TestCase):
30-
NUM_THREADS = 8
30+
NUM_THREADS = 4
3131

3232
def test_concurrent_read(self):
3333
def f(x: int) -> int:
3434
return x + 1
3535

36-
for _ in range(100):
36+
for _ in range(10):
3737
with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor:
3838
b = Barrier(self.NUM_THREADS)
3939
futures = {executor.submit(get_func_annotation, f, b): i for i in range(self.NUM_THREADS)}
@@ -54,7 +54,7 @@ def test_concurrent_write(self):
5454
def bar(x: int, y: float) -> float:
5555
return y ** x
5656

57-
for _ in range(100):
57+
for _ in range(10):
5858
with concurrent.futures.ThreadPoolExecutor(max_workers=self.NUM_THREADS) as executor:
5959
b = Barrier(self.NUM_THREADS)
6060
futures = {executor.submit(set_func_annotation, bar, b): i for i in range(self.NUM_THREADS)}

Lib/test/test_free_threading/test_gc.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,24 +35,30 @@ def mutator_thread():
3535
pass
3636

3737
def test_get_referrers(self):
38+
NUM_GC = 2
39+
NUM_MUTATORS = 4
40+
41+
b = threading.Barrier(NUM_GC + NUM_MUTATORS)
3842
event = threading.Event()
3943

4044
obj = MyObj()
4145

4246
def gc_thread():
47+
b.wait()
4348
for i in range(100):
4449
o = gc.get_referrers(obj)
4550
event.set()
4651

4752
def mutator_thread():
53+
b.wait()
4854
while not event.is_set():
4955
d1 = { "key": obj }
5056
d2 = { "key": obj }
5157
d3 = { "key": obj }
5258
d4 = { "key": obj }
5359

54-
gcs = [Thread(target=gc_thread) for _ in range(2)]
55-
mutators = [Thread(target=mutator_thread) for _ in range(4)]
60+
gcs = [Thread(target=gc_thread) for _ in range(NUM_GC)]
61+
mutators = [Thread(target=mutator_thread) for _ in range(NUM_MUTATORS)]
5662
with threading_helper.start_threads(gcs + mutators):
5763
pass
5864

Lib/test/test_free_threading/test_list.py

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,22 +20,25 @@ class TestList(TestCase):
2020
def test_racing_iter_append(self):
2121
l = []
2222

23-
def writer_func():
23+
barrier = Barrier(NTHREAD + 1)
24+
def writer_func(l):
25+
barrier.wait()
2426
for i in range(OBJECT_COUNT):
2527
l.append(C(i + OBJECT_COUNT))
2628

27-
def reader_func():
29+
def reader_func(l):
30+
barrier.wait()
2831
while True:
2932
count = len(l)
3033
for i, x in enumerate(l):
3134
self.assertEqual(x.v, i + OBJECT_COUNT)
3235
if count == OBJECT_COUNT:
3336
break
3437

35-
writer = Thread(target=writer_func)
38+
writer = Thread(target=writer_func, args=(l,))
3639
readers = []
3740
for x in range(NTHREAD):
38-
reader = Thread(target=reader_func)
41+
reader = Thread(target=reader_func, args=(l,))
3942
readers.append(reader)
4043
reader.start()
4144

@@ -47,11 +50,14 @@ def reader_func():
4750
def test_racing_iter_extend(self):
4851
l = []
4952

53+
barrier = Barrier(NTHREAD + 1)
5054
def writer_func():
55+
barrier.wait()
5156
for i in range(OBJECT_COUNT):
5257
l.extend([C(i + OBJECT_COUNT)])
5358

5459
def reader_func():
60+
barrier.wait()
5561
while True:
5662
count = len(l)
5763
for i, x in enumerate(l):

Lib/test/test_free_threading/test_monitoring.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
from sys import monitoring
1010
from test.support import threading_helper
11-
from threading import Thread, _PyRLock
11+
from threading import Thread, _PyRLock, Barrier
1212
from unittest import TestCase
1313

1414

@@ -194,7 +194,9 @@ def during_threads(self):
194194

195195
@threading_helper.requires_working_threading()
196196
class MonitoringMisc(MonitoringTestMixin, TestCase):
197-
def register_callback(self):
197+
def register_callback(self, barrier):
198+
barrier.wait()
199+
198200
def callback(*args):
199201
pass
200202

@@ -206,8 +208,9 @@ def callback(*args):
206208
def test_register_callback(self):
207209
self.refs = []
208210
threads = []
209-
for i in range(50):
210-
t = Thread(target=self.register_callback)
211+
barrier = Barrier(5)
212+
for i in range(5):
213+
t = Thread(target=self.register_callback, args=(barrier,))
211214
t.start()
212215
threads.append(t)
213216

0 commit comments

Comments
 (0)