Skip to content

Commit fea8eb4

Browse files
Merge branch 'main' of https://github.com/python/cpython into jit-attr
2 parents a745bbd + e02ac1d commit fea8eb4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+825
-116
lines changed

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ jobs:
354354
with:
355355
persist-credentials: false
356356
- name: Build and test
357-
run: ./Android/android.py ci --fast-ci ${{ matrix.arch }}-linux-android
357+
run: python3 Platforms/Android ci --fast-ci ${{ matrix.arch }}-linux-android
358358

359359
build-ios:
360360
name: iOS

Doc/library/argparse.rst

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1970,7 +1970,7 @@ FileType objects
19701970
run and then use the :keyword:`with`-statement to manage the files.
19711971

19721972
.. versionchanged:: 3.4
1973-
Added the *encodings* and *errors* parameters.
1973+
Added the *encoding* and *errors* parameters.
19741974

19751975
.. deprecated:: 3.14
19761976

Include/internal/pycore_dict.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -292,7 +292,7 @@ _PyDict_NotifyEvent(PyDict_WatchEvent event,
292292
PyObject *value)
293293
{
294294
assert(Py_REFCNT((PyObject*)mp) > 0);
295-
int watcher_bits = FT_ATOMIC_LOAD_UINT64_RELAXED(mp->_ma_watcher_tag) & DICT_WATCHER_MASK;
295+
int watcher_bits = FT_ATOMIC_LOAD_UINT64_ACQUIRE(mp->_ma_watcher_tag) & DICT_WATCHER_MASK;
296296
if (watcher_bits) {
297297
RARE_EVENT_STAT_INC(watched_dict_modification);
298298
_PyDict_SendEvent(watcher_bits, event, mp, key, value);

Include/internal/pycore_pyatomic_ft_wrappers.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@ extern "C" {
4949
_Py_atomic_load_uint16_relaxed(&value)
5050
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) \
5151
_Py_atomic_load_uint32_relaxed(&value)
52+
#define FT_ATOMIC_LOAD_UINT64_ACQUIRE(value) \
53+
_Py_atomic_load_uint64_acquire(&value)
5254
#define FT_ATOMIC_LOAD_UINT64_RELAXED(value) \
5355
_Py_atomic_load_uint64_relaxed(&value)
5456
#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) \
@@ -154,6 +156,7 @@ extern "C" {
154156
#define FT_ATOMIC_LOAD_UINT8_RELAXED(value) value
155157
#define FT_ATOMIC_LOAD_UINT16_RELAXED(value) value
156158
#define FT_ATOMIC_LOAD_UINT32_RELAXED(value) value
159+
#define FT_ATOMIC_LOAD_UINT64_ACQUIRE(value) value
157160
#define FT_ATOMIC_LOAD_UINT64_RELAXED(value) value
158161
#define FT_ATOMIC_LOAD_ULONG_RELAXED(value) value
159162
#define FT_ATOMIC_STORE_PTR_RELAXED(value, new_value) value = new_value

Lib/asyncio/__main__.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -162,17 +162,29 @@ def interrupt(self) -> None:
162162
"ps", help="Display a table of all pending tasks in a process"
163163
)
164164
ps.add_argument("pid", type=int, help="Process ID to inspect")
165+
ps.add_argument(
166+
"--retries",
167+
type=int,
168+
default=3,
169+
help="Number of retries on transient attach errors",
170+
)
165171
pstree = subparsers.add_parser(
166172
"pstree", help="Display a tree of all pending tasks in a process"
167173
)
168174
pstree.add_argument("pid", type=int, help="Process ID to inspect")
175+
pstree.add_argument(
176+
"--retries",
177+
type=int,
178+
default=3,
179+
help="Number of retries on transient attach errors",
180+
)
169181
args = parser.parse_args()
170182
match args.command:
171183
case "ps":
172-
asyncio.tools.display_awaited_by_tasks_table(args.pid)
184+
asyncio.tools.display_awaited_by_tasks_table(args.pid, retries=args.retries)
173185
sys.exit(0)
174186
case "pstree":
175-
asyncio.tools.display_awaited_by_tasks_tree(args.pid)
187+
asyncio.tools.display_awaited_by_tasks_tree(args.pid, retries=args.retries)
176188
sys.exit(0)
177189
case None:
178190
pass # continue to the interactive shell

Lib/asyncio/tools.py

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -231,27 +231,38 @@ def exit_with_permission_help_text():
231231
print(
232232
"Error: The specified process cannot be attached to due to insufficient permissions.\n"
233233
"See the Python documentation for details on required privileges and troubleshooting:\n"
234-
"https://docs.python.org/3.14/howto/remote_debugging.html#permission-requirements\n"
234+
"https://docs.python.org/3/howto/remote_debugging.html#permission-requirements\n",
235+
file=sys.stderr,
235236
)
236237
sys.exit(1)
237238

238239

239-
def _get_awaited_by_tasks(pid: int) -> list:
240-
try:
241-
return get_all_awaited_by(pid)
242-
except RuntimeError as e:
243-
while e.__context__ is not None:
244-
e = e.__context__
245-
print(f"Error retrieving tasks: {e}")
246-
sys.exit(1)
247-
except PermissionError:
248-
exit_with_permission_help_text()
240+
_TRANSIENT_ERRORS = (RuntimeError, OSError, UnicodeDecodeError, MemoryError)
241+
242+
243+
def _get_awaited_by_tasks(pid: int, retries: int = 3) -> list:
244+
for attempt in range(retries + 1):
245+
try:
246+
return get_all_awaited_by(pid)
247+
except PermissionError:
248+
exit_with_permission_help_text()
249+
except ProcessLookupError:
250+
print(f"Error: process {pid} not found.", file=sys.stderr)
251+
sys.exit(1)
252+
except _TRANSIENT_ERRORS as e:
253+
if attempt < retries:
254+
continue
255+
if isinstance(e, RuntimeError):
256+
while e.__context__ is not None:
257+
e = e.__context__
258+
print(f"Error retrieving tasks: {e}", file=sys.stderr)
259+
sys.exit(1)
249260

250261

251-
def display_awaited_by_tasks_table(pid: int) -> None:
262+
def display_awaited_by_tasks_table(pid: int, retries: int = 3) -> None:
252263
"""Build and print a table of all pending tasks under `pid`."""
253264

254-
tasks = _get_awaited_by_tasks(pid)
265+
tasks = _get_awaited_by_tasks(pid, retries=retries)
255266
table = build_task_table(tasks)
256267
# Print the table in a simple tabular format
257268
print(
@@ -262,10 +273,10 @@ def display_awaited_by_tasks_table(pid: int) -> None:
262273
print(f"{row[0]:<10} {row[1]:<20} {row[2]:<20} {row[3]:<50} {row[4]:<50} {row[5]:<15} {row[6]:<15}")
263274

264275

265-
def display_awaited_by_tasks_tree(pid: int) -> None:
276+
def display_awaited_by_tasks_tree(pid: int, retries: int = 3) -> None:
266277
"""Build and print a tree of all pending tasks under `pid`."""
267278

268-
tasks = _get_awaited_by_tasks(pid)
279+
tasks = _get_awaited_by_tasks(pid, retries=retries)
269280
try:
270281
result = build_async_tree(tasks)
271282
except CycleFoundException as e:

Lib/configparser.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -315,12 +315,15 @@ def __init__(self, source, *args):
315315

316316
def append(self, lineno, line):
317317
self.errors.append((lineno, line))
318-
self.message += '\n\t[line %2d]: %s' % (lineno, repr(line))
318+
self.message += f'\n\t[line {lineno:2d}]: {line!r}'
319319

320320
def combine(self, others):
321+
messages = [self.message]
321322
for other in others:
322-
for error in other.errors:
323-
self.append(*error)
323+
for lineno, line in other.errors:
324+
self.errors.append((lineno, line))
325+
messages.append(f'\n\t[line {lineno:2d}]: {line!r}')
326+
self.message = "".join(messages)
324327
return self
325328

326329
@staticmethod

Lib/socket.py

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -649,18 +649,22 @@ def _fallback_socketpair(family=AF_INET, type=SOCK_STREAM, proto=0):
649649
# Authenticating avoids using a connection from something else
650650
# able to connect to {host}:{port} instead of us.
651651
# We expect only AF_INET and AF_INET6 families.
652-
try:
653-
if (
654-
ssock.getsockname() != csock.getpeername()
655-
or csock.getsockname() != ssock.getpeername()
656-
):
657-
raise ConnectionError("Unexpected peer connection")
658-
except:
659-
# getsockname() and getpeername() can fail
660-
# if either socket isn't connected.
661-
ssock.close()
662-
csock.close()
663-
raise
652+
#
653+
# Note that we skip this on WASI because on that platorm the client socket
654+
# may not have finished connecting by the time we've reached this point (gh-146139).
655+
if sys.platform != "wasi":
656+
try:
657+
if (
658+
ssock.getsockname() != csock.getpeername()
659+
or csock.getsockname() != ssock.getpeername()
660+
):
661+
raise ConnectionError("Unexpected peer connection")
662+
except:
663+
# getsockname() and getpeername() can fail
664+
# if either socket isn't connected.
665+
ssock.close()
666+
csock.close()
667+
raise
664668

665669
return (ssock, csock)
666670

Lib/statistics.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145
from collections import Counter, namedtuple, defaultdict
146146

147147
_SQRT2 = sqrt(2.0)
148+
_SQRT2PI = sqrt(tau)
148149
_random = random
149150

150151
## Exceptions ##############################################################
@@ -1257,11 +1258,11 @@ def samples(self, n, *, seed=None):
12571258

12581259
def pdf(self, x):
12591260
"Probability density function. P(x <= X < x+dx) / dx"
1260-
variance = self._sigma * self._sigma
1261-
if not variance:
1261+
sigma = self._sigma
1262+
if not sigma:
12621263
raise StatisticsError('pdf() not defined when sigma is zero')
1263-
diff = x - self._mu
1264-
return exp(diff * diff / (-2.0 * variance)) / sqrt(tau * variance)
1264+
z = (x - self._mu) / sigma
1265+
return exp(-0.5 * z * z) / (_SQRT2PI * sigma)
12651266

12661267
def cdf(self, x):
12671268
"Cumulative distribution function. P(X <= x)"

Lib/test/test_capi/test_opt.py

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2845,6 +2845,35 @@ def testfunc(n):
28452845
uops = get_opnames(ex)
28462846
self.assertNotIn("_CHECK_IS_NOT_PY_CALLABLE", uops)
28472847

2848+
def test_check_is_not_py_callable_ex(self):
2849+
def testfunc(n):
2850+
total = 0
2851+
xs = (1, 2, 3)
2852+
args = (xs,)
2853+
for _ in range(n):
2854+
total += len(*args)
2855+
return total
2856+
2857+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
2858+
self.assertEqual(res, 3 * TIER2_THRESHOLD)
2859+
self.assertIsNotNone(ex)
2860+
uops = get_opnames(ex)
2861+
self.assertNotIn("_CHECK_IS_NOT_PY_CALLABLE_EX", uops)
2862+
2863+
def test_check_is_not_py_callable_kw(self):
2864+
def testfunc(n):
2865+
total = 0
2866+
xs = (3, 1, 2)
2867+
for _ in range(n):
2868+
total += sorted(xs, reverse=False)[0]
2869+
return total
2870+
2871+
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
2872+
self.assertEqual(res, TIER2_THRESHOLD)
2873+
self.assertIsNotNone(ex)
2874+
uops = get_opnames(ex)
2875+
self.assertNotIn("_CHECK_IS_NOT_PY_CALLABLE_KW", uops)
2876+
28482877
def test_call_len_string(self):
28492878
def testfunc(n):
28502879
for _ in range(n):
@@ -4867,7 +4896,7 @@ def testfunc(*args):
48674896
# This is a sign the optimizer ran and didn't hit contradiction.
48684897
self.assertIn("_LOAD_CONST_INLINE_BORROW", uops)
48694898

4870-
def test_load_attr_getattribute_overridden_frame(self):
4899+
def test_load_attr_getattribute_frame(self):
48714900
class B:
48724901
def __getattribute__(self, name):
48734902
return len(name)
@@ -4881,8 +4910,10 @@ def testfunc(n):
48814910

48824911
res, ex = self._run_with_optimizer(testfunc, TIER2_THRESHOLD)
48834912
self.assertIsNotNone(ex)
4913+
self.assertEqual(res, 2 * TIER2_THRESHOLD)
48844914
uops = get_opnames(ex)
48854915
self.assertIn("_LOAD_ATTR_GETATTRIBUTE_OVERRIDDEN_FRAME", uops)
4916+
self.assertNotIn("_LOAD_GLOBAL_BUILTINS")
48864917

48874918
def test_unary_negative(self):
48884919
def testfunc(n):

0 commit comments

Comments
 (0)