https://github.com/python/cpython/commit/b62f612a266e8640bc9440cc4562b0bfe7d8755f
commit: b62f612a266e8640bc9440cc4562b0bfe7d8755f
branch: 3.15
author: Victor Stinner <[email protected]>
committer: vstinner <[email protected]>
date: 2026-10-20T14:49:48-05:00
summary:
[3.15] gh-159603: Use pthread_attr_get_np() on FreeBSD (#159604) (#159928)
gh-159603: Use pthread_attr_get_np() on FreeBSD (#159604)
Use pthread_attr_get_np() on FreeBSD to get the stack size (and guard
size) of the current thread.
Check if pthread_attr_get_np() function and <pthread_np.h> header are
available in configure.
Update test_json.test_recursion. On FreeBSD 16 with a default stack size of
512 MB, the json C implementation no longer raises RecursionError in
test_highly_nested_objects_encoding(). Reduce also max_depth from 5,000 to
2,000 so test_highly_nested_objects_encoding() of the Python implementation
only takes 1.6 seconds, instead of 12 seconds.
(cherry picked from commit 71ba39dc057941fb8ea032b813862a215bb3d5aa)
files:
A
Misc/NEWS.d/next/Core_and_Builtins/2026-10-17-02-47-26.gh-issue-159603.OFagJz.rst
M Lib/test/test_json/test_recursion.py
M Python/ceval.c
M configure
M configure.ac
M pyconfig.h.in
diff --git a/Lib/test/test_json/test_recursion.py
b/Lib/test/test_json/test_recursion.py
index 17c7afe6417d887..e7e0783f9decb19 100644
--- a/Lib/test/test_json/test_recursion.py
+++ b/Lib/test/test_json/test_recursion.py
@@ -91,22 +91,35 @@ def test_highly_nested_objects_decoding(self):
@support.skip_emscripten_stack_overflow()
@support.requires_resource('cpu')
def test_highly_nested_objects_encoding(self):
- # See #12051
+ # See issue gh-56260
+
+ # With max_depth=2_000 on Linux, the Python implementation takes around
+ # 2 seconds to raise RecursionError, whereas the C implementation only
+ # takes around 160 ms.
+ max_depth = 2_000
l, d = [], {}
- for x in range(500_000):
+ for x in range(max_depth * 10):
l, d = [l], {'k':d}
- with self.assertRaises(RecursionError):
- with support.infinite_recursion(5000):
+
+ # Don't use assertRaises(RecursionError): on FreeBSD 16 with a default
+ # stack size of 512 MiB, the C implementation doesn't raise
+ # RecursionError.
+ try:
+ with support.infinite_recursion(max_depth):
self.dumps(l)
- with self.assertRaises(RecursionError):
- with support.infinite_recursion(5000):
+ except RecursionError:
+ pass
+ try:
+ with support.infinite_recursion(max_depth):
self.dumps(d)
+ except RecursionError:
+ pass
@support.skip_if_huge_c_stack()
@support.skip_emscripten_stack_overflow()
@support.skip_wasi_stack_overflow()
def test_endless_recursion(self):
- # See #12051
+ # See issue gh-56260
class EndlessJSONEncoder(self.json.JSONEncoder):
def default(self, o):
"""If check_circular is False, this will keep adding another
list."""
diff --git
a/Misc/NEWS.d/next/Core_and_Builtins/2026-10-17-02-47-26.gh-issue-159603.OFagJz.rst
b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-17-02-47-26.gh-issue-159603.OFagJz.rst
new file mode 100644
index 000000000000000..bd46b85509dbc2b
--- /dev/null
+++
b/Misc/NEWS.d/next/Core_and_Builtins/2026-10-17-02-47-26.gh-issue-159603.OFagJz.rst
@@ -0,0 +1,2 @@
+On FreeBSD, call ``pthread_attr_get_np()`` to get the stack size (and guard
+size) of the current thread. Patch by Victor Stinner.
diff --git a/Python/ceval.c b/Python/ceval.c
index b132f9ba8331dcd..04b61c59c72b380 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -3,6 +3,11 @@
#include "ceval.h"
#include "pycore_long.h"
+#ifdef HAVE_PTHREAD_NP_H
+# include <pthread_np.h> // pthread_attr_get_np()
+#endif
+
+
int
Py_GetRecursionLimit(void)
{
@@ -159,13 +164,18 @@ hardware_stack_limits(uintptr_t *base, uintptr_t *top,
uintptr_t sp)
// limits compared to the old stack size estimation. musl doesn't give
// us a way to detect it, so we have to assume any non-glibc,
// non-Android Linux is musl and mustn't rely on pthread_getattr_np.
-# if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(_AIX) && \
- !defined(__NetBSD__) && \
- (defined(__GLIBC__) || defined(__ANDROID__) || !defined(__linux__))
+# if (defined(HAVE_PTHREAD_GETATTR_NP) ||
defined(_Py_HAVE_PTHREAD_ATTR_GET_NP)) \
+ && !defined(_AIX) && !defined(__NetBSD__) \
+ && (defined(__GLIBC__) || defined(__ANDROID__) || !defined(__linux__))
size_t stack_size, guard_size;
void *stack_addr;
pthread_attr_t attr;
+#ifdef _Py_HAVE_PTHREAD_ATTR_GET_NP
+ int err = pthread_attr_init(&attr);
+ err |= pthread_attr_get_np(pthread_self(), &attr);
+#else
int err = pthread_getattr_np(pthread_self(), &attr);
+#endif
if (err == 0) {
err = pthread_attr_getguardsize(&attr, &guard_size);
err |= pthread_attr_getstack(&attr, &stack_addr, &stack_size);
diff --git a/configure b/configure
index 11e43108ed12100..5a728e8ba68a3a1 100755
--- a/configure
+++ b/configure
@@ -11896,6 +11896,12 @@ if test "x$ac_cv_header_pthread_h" = xyes
then :
printf "%s\n" "#define HAVE_PTHREAD_H 1" >>confdefs.h
+fi
+ac_fn_c_check_header_compile "$LINENO" "pthread_np.h"
"ac_cv_header_pthread_np_h" "$ac_includes_default"
+if test "x$ac_cv_header_pthread_np_h" = xyes
+then :
+ printf "%s\n" "#define HAVE_PTHREAD_NP_H 1" >>confdefs.h
+
fi
ac_fn_c_check_header_compile "$LINENO" "pty.h" "ac_cv_header_pty_h"
"$ac_includes_default"
if test "x$ac_cv_header_pty_h" = xyes
@@ -21212,6 +21218,49 @@ fi
+# FreeBSD pthread_attr_get_np()
+
+
+ { printf "%s\n" "$as_me:${as_lineno-$LINENO}: checking for
pthread_attr_get_np" >&5
+printf %s "checking for pthread_attr_get_np... " >&6; }
+if test ${ac_cv_func_pthread_attr_get_np+y}
+then :
+ printf %s "(cached) " >&6
+else case e in #(
+ e) cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <pthread_np.h>
+int
+main (void)
+{
+void *x=pthread_attr_get_np
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"
+then :
+ ac_cv_func_pthread_attr_get_np=yes
+else case e in #(
+ e) ac_cv_func_pthread_attr_get_np=no ;;
+esac
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.beam conftest.$ac_ext
+ ;;
+esac
+fi
+{ printf "%s\n" "$as_me:${as_lineno-$LINENO}: result:
$ac_cv_func_pthread_attr_get_np" >&5
+printf "%s\n" "$ac_cv_func_pthread_attr_get_np" >&6; }
+ if test "x$ac_cv_func_pthread_attr_get_np" = xyes
+then :
+
+printf "%s\n" "#define _Py_HAVE_PTHREAD_ATTR_GET_NP 1" >>confdefs.h
+
+fi
+
+
+
+
# os.statx uses Linux's statx function. AIX also has a function named statx,
diff --git a/configure.ac b/configure.ac
index 26f603e6232acf9..08cfd620afb1eeb 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3168,7 +3168,8 @@ AC_CHECK_HEADERS([ \
alloca.h asm/types.h bluetooth.h conio.h direct.h dlfcn.h endian.h errno.h
fcntl.h grp.h \
io.h langinfo.h libintl.h libutil.h linux/auxvec.h sys/auxv.h linux/fs.h
linux/limits.h linux/memfd.h \
linux/netfilter_ipv4.h linux/random.h linux/soundcard.h linux/sched.h \
- linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h
netpacket/packet.h poll.h process.h pthread.h pty.h \
+ linux/tipc.h linux/wait.h netdb.h net/ethernet.h netinet/in.h
netpacket/packet.h \
+ poll.h process.h pthread.h pthread_np.h pty.h \
sched.h setjmp.h shadow.h signal.h spawn.h sys/audioio.h sys/bsdtty.h
sys/devpoll.h \
sys/endian.h sys/epoll.h sys/event.h sys/eventfd.h sys/file.h sys/ioctl.h
sys/kern_control.h \
sys/loadavg.h sys/lock.h sys/memfd.h sys/mkdev.h sys/mman.h sys/modem.h
sys/param.h sys/pidfd.h sys/poll.h \
@@ -5523,6 +5524,8 @@ AC_CHECK_FUNCS([ \
])
PY_CHECK_FUNC_PRIVATE([strerror_r], [@%:@include <string.h>])
+# FreeBSD pthread_attr_get_np()
+PY_CHECK_FUNC_PRIVATE([pthread_attr_get_np], [@%:@include <pthread_np.h>])
# os.statx uses Linux's statx function. AIX also has a function named statx,
diff --git a/pyconfig.h.in b/pyconfig.h.in
index facf6435648e2d8..dfc28a51944f52a 100644
--- a/pyconfig.h.in
+++ b/pyconfig.h.in
@@ -1048,6 +1048,9 @@
/* Define to 1 if you have the 'pthread_kill' function. */
#undef HAVE_PTHREAD_KILL
+/* Define to 1 if you have the <pthread_np.h> header file. */
+#undef HAVE_PTHREAD_NP_H
+
/* Define to 1 if you have the 'pthread_setname_np' function. */
#undef HAVE_PTHREAD_SETNAME_NP
@@ -2094,6 +2097,9 @@
/* Define if you have the 'PR_SET_VMA_ANON_NAME' constant. */
#undef _Py_HAVE_PR_SET_VMA_ANON_NAME
+/* Define if you have the 'pthread_attr_get_np' function. */
+#undef _Py_HAVE_PTHREAD_ATTR_GET_NP
+
/* Define if you have the 'strerror_r' function. */
#undef _Py_HAVE_STRERROR_R
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]