@@ -1531,6 +1531,63 @@ All of the following functions must be called after :c:func:`Py_Initialize`.
15311531 .. versionadded:: 3.11
15321532
15331533
1534+ .. c:function:: int PyUnstable_ThreadState_SetStackProtection(PyThreadState *tstate, void *stack_start_addr, size_t stack_size)
1535+
1536+ Set the stack protection start address and stack protection size
1537+ of a Python thread state.
1538+
1539+ On success, return ``0``.
1540+ On failure, set an exception and return ``-1``.
1541+
1542+ CPython implements :ref:`recursion control <recursion>` for C code by raising
1543+ :py:exc:`RecursionError` when it notices that the machine execution stack is close
1544+ to overflow. See for example the :c:func:`Py_EnterRecursiveCall` function.
1545+ For this, it needs to know the location of the current thread's stack, which it
1546+ normally gets from the operating system.
1547+ When the stack is changed, for example using context switching techniques like the
1548+ Boost library's ``boost::context``, you must call
1549+ :c:func:`~PyUnstable_ThreadState_SetStackProtection` to inform CPython of the change.
1550+
1551+ Call :c:func:`~PyUnstable_ThreadState_SetStackProtection` either before
1552+ or after changing the stack.
1553+ Do not call any other Python C API between the call and the stack
1554+ change.
1555+
1556+ See :c:func:`PyUnstable_ThreadState_ResetStackProtection` for undoing this operation.
1557+
1558+ .. versionadded:: next
1559+
1560+ .. warning::
1561+
1562+ This function was added in a bugfix release, and
1563+ extensions that use it will be incompatible with Python 3.14.0.
1564+ Most packaging tools for Python are not able to handle this
1565+ incompatibility automatically, and will need explicit configuration.
1566+ When using PyPA standards (wheels and source distributions),
1567+ specify ``Requires-Python: != 3.14.0.*`` in
1568+ `core metadata <https://packaging.python.org/en/latest/specifications/core-metadata/#requires-python>`_.
1569+
1570+
1571+ .. c:function:: void PyUnstable_ThreadState_ResetStackProtection(PyThreadState *tstate)
1572+
1573+ Reset the stack protection start address and stack protection size
1574+ of a Python thread state to the operating system defaults.
1575+
1576+ See :c:func:`PyUnstable_ThreadState_SetStackProtection` for an explanation.
1577+
1578+ .. versionadded:: next
1579+
1580+ .. warning::
1581+
1582+ This function was added in a bugfix release, and
1583+ extensions that use it will be incompatible with Python 3.14.0.
1584+ Most packaging tools for Python are not able to handle this
1585+ incompatibility automatically, and will need explicit configuration.
1586+ When using PyPA standards (wheels and source distributions),
1587+ specify ``Requires-Python: != 3.14.0.*`` in
1588+ `core metadata <https://packaging.python.org/en/latest/specifications/core-metadata/#requires-python>`_.
1589+
1590+
15341591.. c:function:: PyInterpreterState* PyInterpreterState_Get(void)
15351592
15361593 Get the current interpreter.
@@ -2651,3 +2708,220 @@ code triggered by the finalizer blocks and calls :c:func:`PyEval_SaveThread`.
26512708 In the default build, this macro expands to ``}``.
26522709
26532710 .. versionadded:: 3.13
2711+
2712+
2713+ Legacy Locking APIs
2714+ -------------------
2715+
2716+ These APIs are obsolete since Python 3.13 with the introduction of
2717+ :c:type:`PyMutex`.
2718+
2719+ .. versionchanged:: 3.15
2720+ These APIs are now a simple wrapper around ``PyMutex``.
2721+
2722+
2723+ .. c:type:: PyThread_type_lock
2724+
2725+ A pointer to a mutual exclusion lock.
2726+
2727+
2728+ .. c:type:: PyLockStatus
2729+
2730+ The result of acquiring a lock with a timeout.
2731+
2732+ .. c:namespace:: NULL
2733+
2734+ .. c:enumerator:: PY_LOCK_FAILURE
2735+
2736+ Failed to acquire the lock.
2737+
2738+ .. c:enumerator:: PY_LOCK_ACQUIRED
2739+
2740+ The lock was successfully acquired.
2741+
2742+ .. c:enumerator:: PY_LOCK_INTR
2743+
2744+ The lock was interrupted by a signal.
2745+
2746+
2747+ .. c:function:: PyThread_type_lock PyThread_allocate_lock(void)
2748+
2749+ Allocate a new lock.
2750+
2751+ On success, this function returns a lock; on failure, this
2752+ function returns ``0`` without an exception set.
2753+
2754+ The caller does not need to hold an :term:`attached thread state`.
2755+
2756+ .. versionchanged:: 3.15
2757+ This function now always uses :c:type:`PyMutex`. In prior versions, this
2758+ would use a lock provided by the operating system.
2759+
2760+
2761+ .. c:function:: void PyThread_free_lock(PyThread_type_lock lock)
2762+
2763+ Destroy *lock*. The lock should not be held by any thread when calling
2764+ this.
2765+
2766+ The caller does not need to hold an :term:`attached thread state`.
2767+
2768+
2769+ .. c:function:: PyLockStatus PyThread_acquire_lock_timed(PyThread_type_lock lock, long long microseconds, int intr_flag)
2770+
2771+ Acquire *lock* with a timeout.
2772+
2773+ This will wait for *microseconds* microseconds to acquire the lock. If the
2774+ timeout expires, this function returns :c:enumerator:`PY_LOCK_FAILURE`.
2775+ If *microseconds* is ``-1``, this will wait indefinitely until the lock has
2776+ been released.
2777+
2778+ If *intr_flag* is ``1``, acquiring the lock may be interrupted by a signal,
2779+ in which case this function returns :c:enumerator:`PY_LOCK_INTR`. Upon
2780+ interruption, it's generally expected that the caller makes a call to
2781+ :c:func:`Py_MakePendingCalls` to propagate an exception to Python code.
2782+
2783+ If the lock is successfully acquired, this function returns
2784+ :c:enumerator:`PY_LOCK_ACQUIRED`.
2785+
2786+ The caller does not need to hold an :term:`attached thread state`.
2787+
2788+
2789+ .. c:function:: int PyThread_acquire_lock(PyThread_type_lock lock, int waitflag)
2790+
2791+ Acquire *lock*.
2792+
2793+ If *waitflag* is ``1`` and another thread currently holds the lock, this
2794+ function will wait until the lock can be acquired and will always return
2795+ ``1``.
2796+
2797+ If *waitflag* is ``0`` and another thread holds the lock, this function will
2798+ not wait and instead return ``0``. If the lock is not held by any other
2799+ thread, then this function will acquire it and return ``1``.
2800+
2801+ Unlike :c:func:`PyThread_acquire_lock_timed`, acquiring the lock cannot be
2802+ interrupted by a signal.
2803+
2804+ The caller does not need to hold an :term:`attached thread state`.
2805+
2806+
2807+ .. c:function:: int PyThread_release_lock(PyThread_type_lock lock)
2808+
2809+ Release *lock*. If *lock* is not held, then this function issues a
2810+ fatal error.
2811+
2812+ The caller does not need to hold an :term:`attached thread state`.
2813+
2814+
2815+ Operating System Thread APIs
2816+ ============================
2817+
2818+ .. c:macro:: PYTHREAD_INVALID_THREAD_ID
2819+
2820+ Sentinel value for an invalid thread ID.
2821+
2822+ This is currently equivalent to ``(unsigned long)-1``.
2823+
2824+
2825+ .. c:function:: unsigned long PyThread_start_new_thread(void (*func)(void *), void *arg)
2826+
2827+ Start function *func* in a new thread with argument *arg*.
2828+ The resulting thread is not intended to be joined.
2829+
2830+ *func* must not be ``NULL``, but *arg* may be ``NULL``.
2831+
2832+ On success, this function returns the identifier of the new thread; on failure,
2833+ this returns :c:macro:`PYTHREAD_INVALID_THREAD_ID`.
2834+
2835+ The caller does not need to hold an :term:`attached thread state`.
2836+
2837+
2838+ .. c:function:: unsigned long PyThread_get_thread_ident(void)
2839+
2840+ Return the identifier of the current thread, which will never be zero.
2841+
2842+ This function cannot fail, and the caller does not need to hold an
2843+ :term:`attached thread state`.
2844+
2845+ .. seealso::
2846+ :py:func:`threading.get_ident`
2847+
2848+
2849+ .. c:function:: PyObject *PyThread_GetInfo(void)
2850+
2851+ Get general information about the current thread in the form of a
2852+ :ref:`struct sequence <struct-sequence-objects>` object. This information is
2853+ accessible as :py:attr:`sys.thread_info` in Python.
2854+
2855+ On success, this returns a new :term:`strong reference` to the thread
2856+ information; on failure, this returns ``NULL`` with an exception set.
2857+
2858+ The caller must hold an :term:`attached thread state`.
2859+
2860+
2861+ .. c:macro:: PY_HAVE_THREAD_NATIVE_ID
2862+
2863+ This macro is defined when the system supports native thread IDs.
2864+
2865+
2866+ .. c:function:: unsigned long PyThread_get_thread_native_id(void)
2867+
2868+ Get the native identifier of the current thread as it was assigned by the operating
2869+ system's kernel, which will never be less than zero.
2870+
2871+ This function is only available when :c:macro:`PY_HAVE_THREAD_NATIVE_ID` is
2872+ defined.
2873+
2874+ This function cannot fail, and the caller does not need to hold an
2875+ :term:`attached thread state`.
2876+
2877+ .. seealso::
2878+ :py:func:`threading.get_native_id`
2879+
2880+
2881+ .. c:function:: void PyThread_exit_thread(void)
2882+
2883+ Terminate the current thread. This function is generally considered unsafe
2884+ and should be avoided. It is kept solely for backwards compatibility.
2885+
2886+ This function is only safe to call if all functions in the full call
2887+ stack are written to safely allow it.
2888+
2889+ .. warning::
2890+
2891+ If the current system uses POSIX threads (also known as" pthreads" ),
2892+ this calls :manpage:`pthread_exit(3)`, which attempts to unwind the stack
2893+ and call C++ destructors on some libc implementations. However, if a
2894+ ``noexcept`` function is reached, it may terminate the process.
2895+ Other systems, such as macOS, do unwinding.
2896+
2897+ On Windows, this function calls ``_endthreadex()``, which kills the thread
2898+ without calling C++ destructors.
2899+
2900+ In any case, there is a risk of corruption on the thread's stack.
2901+
2902+ .. deprecated:: 3.14
2903+
2904+
2905+ .. c:function:: void PyThread_init_thread(void)
2906+
2907+ Initialize ``PyThread*`` APIs. Python executes this function automatically,
2908+ so there's little need to call it from an extension module.
2909+
2910+
2911+ .. c:function:: int PyThread_set_stacksize(size_t size)
2912+
2913+ Set the stack size of the current thread to *size* bytes.
2914+
2915+ This function returns ``0`` on success, ``-1`` if *size* is invalid, or
2916+ ``-2`` if the system does not support changing the stack size. This function
2917+ does not set exceptions.
2918+
2919+ The caller does not need to hold an :term:`attached thread state`.
2920+
2921+
2922+ .. c:function:: size_t PyThread_get_stacksize(void)
2923+
2924+ Return the stack size of the current thread in bytes, or ``0`` if the system's
2925+ default stack size is in use.
2926+
2927+ The caller does not need to hold an :term:`attached thread state`.