mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 05:31:20 +00:00 
			
		
		
		
	 fc5a0dc224
			
		
	
	
		fc5a0dc224
		
			
		
	
	
	
	
		
			
			* Replace uses of `PyCell_GET` and `PyCell_SET`. These macros are not safe to use in the free-threaded build. Use `PyCell_GetRef()` and `PyCell_SetTakeRef()` instead. * Since `PyCell_GetRef()` returns a strong rather than borrowed ref, some code restructuring was required, e.g. `frame_get_var()` returns a strong ref now. * Add critical sections to `PyCell_GET` and `PyCell_SET`. * Move critical_section.h earlier in the Python.h file. * Add `PyCell_GET` to the free-threading howto table of APIs that return borrowed refs. * Add additional unit tests for free-threading.
		
			
				
	
	
		
			282 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
			
		
		
	
	
			282 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			ReStructuredText
		
	
	
	
	
	
| .. highlight:: c
 | |
| 
 | |
| .. _freethreading-extensions-howto:
 | |
| 
 | |
| ******************************************
 | |
| C API Extension Support for Free Threading
 | |
| ******************************************
 | |
| 
 | |
| Starting with the 3.13 release, CPython has experimental support for running
 | |
| with the :term:`global interpreter lock` (GIL) disabled in a configuration
 | |
| called :term:`free threading`.  This document describes how to adapt C API
 | |
| extensions to support free threading.
 | |
| 
 | |
| 
 | |
| Identifying the Free-Threaded Build in C
 | |
| ========================================
 | |
| 
 | |
| The CPython C API exposes the ``Py_GIL_DISABLED`` macro: in the free-threaded
 | |
| build it's defined to ``1``, and in the regular build it's not defined.
 | |
| You can use it to enable code that only runs under the free-threaded build::
 | |
| 
 | |
|     #ifdef Py_GIL_DISABLED
 | |
|     /* code that only runs in the free-threaded build */
 | |
|     #endif
 | |
| 
 | |
| Module Initialization
 | |
| =====================
 | |
| 
 | |
| Extension modules need to explicitly indicate that they support running with
 | |
| the GIL disabled; otherwise importing the extension will raise a warning and
 | |
| enable the GIL at runtime.
 | |
| 
 | |
| There are two ways to indicate that an extension module supports running with
 | |
| the GIL disabled depending on whether the extension uses multi-phase or
 | |
| single-phase initialization.
 | |
| 
 | |
| Multi-Phase Initialization
 | |
| ..........................
 | |
| 
 | |
| Extensions that use multi-phase initialization (i.e.,
 | |
| :c:func:`PyModuleDef_Init`) should add a :c:data:`Py_mod_gil` slot in the
 | |
| module definition.  If your extension supports older versions of CPython,
 | |
| you should guard the slot with a :c:data:`PY_VERSION_HEX` check.
 | |
| 
 | |
| ::
 | |
| 
 | |
|     static struct PyModuleDef_Slot module_slots[] = {
 | |
|         ...
 | |
|     #if PY_VERSION_HEX >= 0x030D0000
 | |
|         {Py_mod_gil, Py_MOD_GIL_NOT_USED},
 | |
|     #endif
 | |
|         {0, NULL}
 | |
|     };
 | |
| 
 | |
|     static struct PyModuleDef moduledef = {
 | |
|         PyModuleDef_HEAD_INIT,
 | |
|         .m_slots = module_slots,
 | |
|         ...
 | |
|     };
 | |
| 
 | |
| 
 | |
| Single-Phase Initialization
 | |
| ...........................
 | |
| 
 | |
| Extensions that use single-phase initialization (i.e.,
 | |
| :c:func:`PyModule_Create`) should call :c:func:`PyUnstable_Module_SetGIL` to
 | |
| indicate that they support running with the GIL disabled.  The function is
 | |
| only defined in the free-threaded build, so you should guard the call with
 | |
| ``#ifdef Py_GIL_DISABLED`` to avoid compilation errors in the regular build.
 | |
| 
 | |
| ::
 | |
| 
 | |
|     static struct PyModuleDef moduledef = {
 | |
|         PyModuleDef_HEAD_INIT,
 | |
|         ...
 | |
|     };
 | |
| 
 | |
|     PyMODINIT_FUNC
 | |
|     PyInit_mymodule(void)
 | |
|     {
 | |
|         PyObject *m = PyModule_Create(&moduledef);
 | |
|         if (m == NULL) {
 | |
|             return NULL;
 | |
|         }
 | |
|     #ifdef Py_GIL_DISABLED
 | |
|         PyUnstable_Module_SetGIL(m, Py_MOD_GIL_NOT_USED);
 | |
|     #endif
 | |
|         return m;
 | |
|     }
 | |
| 
 | |
| 
 | |
| General API Guidelines
 | |
| ======================
 | |
| 
 | |
| Most of the C API is thread-safe, but there are some exceptions.
 | |
| 
 | |
| * **Struct Fields**: Accessing fields in Python C API objects or structs
 | |
|   directly is not thread-safe if the field may be concurrently modified.
 | |
| * **Macros**: Accessor macros like :c:macro:`PyList_GET_ITEM` and
 | |
|   :c:macro:`PyList_SET_ITEM` do not perform any error checking or locking.
 | |
|   These macros are not thread-safe if the container object may be modified
 | |
|   concurrently.
 | |
| * **Borrowed References**: C API functions that return
 | |
|   :term:`borrowed references <borrowed reference>` may not be thread-safe if
 | |
|   the containing object is modified concurrently.  See the section on
 | |
|   :ref:`borrowed references <borrowed-references>` for more information.
 | |
| 
 | |
| 
 | |
| Container Thread Safety
 | |
| .......................
 | |
| 
 | |
| Containers like :c:struct:`PyListObject`,
 | |
| :c:struct:`PyDictObject`, and :c:struct:`PySetObject` perform internal locking
 | |
| in the free-threaded build.  For example, the :c:func:`PyList_Append` will
 | |
| lock the list before appending an item.
 | |
| 
 | |
| .. _PyDict_Next:
 | |
| 
 | |
| ``PyDict_Next``
 | |
| '''''''''''''''
 | |
| 
 | |
| A notable exception is :c:func:`PyDict_Next`, which does not lock the
 | |
| dictionary.  You should use :c:macro:`Py_BEGIN_CRITICAL_SECTION` to protect
 | |
| the dictionary while iterating over it if the dictionary may be concurrently
 | |
| modified::
 | |
| 
 | |
|     Py_BEGIN_CRITICAL_SECTION(dict);
 | |
|     PyObject *key, *value;
 | |
|     Py_ssize_t pos = 0;
 | |
|     while (PyDict_Next(dict, &pos, &key, &value)) {
 | |
|         ...
 | |
|     }
 | |
|     Py_END_CRITICAL_SECTION();
 | |
| 
 | |
| 
 | |
| Borrowed References
 | |
| ===================
 | |
| 
 | |
| .. _borrowed-references:
 | |
| 
 | |
| Some C API functions return :term:`borrowed references <borrowed reference>`.
 | |
| These APIs are not thread-safe if the containing object is modified
 | |
| concurrently.  For example, it's not safe to use :c:func:`PyList_GetItem`
 | |
| if the list may be modified concurrently.
 | |
| 
 | |
| The following table lists some borrowed reference APIs and their replacements
 | |
| that return :term:`strong references <strong reference>`.
 | |
| 
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | Borrowed reference API            | Strong reference API              |
 | |
| +===================================+===================================+
 | |
| | :c:func:`PyList_GetItem`          | :c:func:`PyList_GetItemRef`       |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyDict_GetItem`          | :c:func:`PyDict_GetItemRef`       |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyDict_GetItemWithError` | :c:func:`PyDict_GetItemRef`       |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyDict_GetItemString`    | :c:func:`PyDict_GetItemStringRef` |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyDict_SetDefault`       | :c:func:`PyDict_SetDefaultRef`    |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyDict_Next`             | none (see :ref:`PyDict_Next`)     |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyWeakref_GetObject`     | :c:func:`PyWeakref_GetRef`        |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyWeakref_GET_OBJECT`    | :c:func:`PyWeakref_GetRef`        |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyImport_AddModule`      | :c:func:`PyImport_AddModuleRef`   |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| | :c:func:`PyCell_GET`              | :c:func:`PyCell_Get`              |
 | |
| +-----------------------------------+-----------------------------------+
 | |
| 
 | |
| Not all APIs that return borrowed references are problematic.  For
 | |
| example, :c:func:`PyTuple_GetItem` is safe because tuples are immutable.
 | |
| Similarly, not all uses of the above APIs are problematic.  For example,
 | |
| :c:func:`PyDict_GetItem` is often used for parsing keyword argument
 | |
| dictionaries in function calls; those keyword argument dictionaries are
 | |
| effectively private (not accessible by other threads), so using borrowed
 | |
| references in that context is safe.
 | |
| 
 | |
| Some of these functions were added in Python 3.13.  You can use the
 | |
| `pythoncapi-compat <https://github.com/python/pythoncapi-compat>`_ package
 | |
| to provide implementations of these functions for older Python versions.
 | |
| 
 | |
| 
 | |
| .. _free-threaded-memory-allocation:
 | |
| 
 | |
| Memory Allocation APIs
 | |
| ======================
 | |
| 
 | |
| Python's memory management C API provides functions in three different
 | |
| :ref:`allocation domains <allocator-domains>`: "raw", "mem", and "object".
 | |
| For thread-safety, the free-threaded build requires that only Python objects
 | |
| are allocated using the object domain, and that all Python object are
 | |
| allocated using that domain.  This differs from the prior Python versions,
 | |
| where this was only a best practice and not a hard requirement.
 | |
| 
 | |
| .. note::
 | |
| 
 | |
|    Search for uses of :c:func:`PyObject_Malloc` in your
 | |
|    extension and check that the allocated memory is used for Python objects.
 | |
|    Use :c:func:`PyMem_Malloc` to allocate buffers instead of
 | |
|    :c:func:`PyObject_Malloc`.
 | |
| 
 | |
| 
 | |
| Thread State and GIL APIs
 | |
| =========================
 | |
| 
 | |
| Python provides a set of functions and macros to manage thread state and the
 | |
| GIL, such as:
 | |
| 
 | |
| * :c:func:`PyGILState_Ensure` and :c:func:`PyGILState_Release`
 | |
| * :c:func:`PyEval_SaveThread` and :c:func:`PyEval_RestoreThread`
 | |
| * :c:macro:`Py_BEGIN_ALLOW_THREADS` and :c:macro:`Py_END_ALLOW_THREADS`
 | |
| 
 | |
| These functions should still be used in the free-threaded build to manage
 | |
| thread state even when the :term:`GIL` is disabled.  For example, if you
 | |
| create a thread outside of Python, you must call :c:func:`PyGILState_Ensure`
 | |
| before calling into the Python API to ensure that the thread has a valid
 | |
| Python thread state.
 | |
| 
 | |
| You should continue to call :c:func:`PyEval_SaveThread` or
 | |
| :c:macro:`Py_BEGIN_ALLOW_THREADS` around blocking operations, such as I/O or
 | |
| lock acquisitions, to allow other threads to run the
 | |
| :term:`cyclic garbage collector <garbage collection>`.
 | |
| 
 | |
| 
 | |
| Protecting Internal Extension State
 | |
| ===================================
 | |
| 
 | |
| Your extension may have internal state that was previously protected by the
 | |
| GIL.  You may need to add locking to protect this state.  The approach will
 | |
| depend on your extension, but some common patterns include:
 | |
| 
 | |
| * **Caches**: global caches are a common source of shared state.  Consider
 | |
|   using a lock to protect the cache or disabling it in the free-threaded build
 | |
|   if the cache is not critical for performance.
 | |
| * **Global State**: global state may need to be protected by a lock or moved
 | |
|   to thread local storage. C11 and C++11 provide the ``thread_local`` or
 | |
|   ``_Thread_local`` for
 | |
|   `thread-local storage <https://en.cppreference.com/w/c/language/storage_duration>`_.
 | |
| 
 | |
| 
 | |
| Building Extensions for the Free-Threaded Build
 | |
| ===============================================
 | |
| 
 | |
| C API extensions need to be built specifically for the free-threaded build.
 | |
| The wheels, shared libraries, and binaries are indicated by a ``t`` suffix.
 | |
| 
 | |
| * `pypa/manylinux <https://github.com/pypa/manylinux>`_ supports the
 | |
|   free-threaded build, with the ``t`` suffix, such as ``python3.13t``.
 | |
| * `pypa/cibuildwheel <https://github.com/pypa/cibuildwheel>`_ supports the
 | |
|   free-threaded build if you set
 | |
|   `CIBW_FREE_THREADED_SUPPORT <https://cibuildwheel.pypa.io/en/stable/options/#free-threaded-support>`_.
 | |
| 
 | |
| Limited C API and Stable ABI
 | |
| ............................
 | |
| 
 | |
| The free-threaded build does not currently support the
 | |
| :ref:`Limited C API <limited-c-api>` or the stable ABI.  If you use
 | |
| `setuptools <https://setuptools.pypa.io/en/latest/setuptools.html>`_ to build
 | |
| your extension and currently set ``py_limited_api=True`` you can use
 | |
| ``py_limited_api=not sysconfig.get_config_var("Py_GIL_DISABLED")`` to opt out
 | |
| of the limited API when building with the free-threaded build.
 | |
| 
 | |
| .. note::
 | |
|     You will need to build separate wheels specifically for the free-threaded
 | |
|     build.  If you currently use the stable ABI, you can continue to build a
 | |
|     single wheel for multiple non-free-threaded Python versions.
 | |
| 
 | |
| 
 | |
| Windows
 | |
| .......
 | |
| 
 | |
| Due to a limitation of the official Windows installer, you will need to
 | |
| manually define ``Py_GIL_DISABLED=1`` when building extensions from source.
 | |
| 
 | |
| .. seealso::
 | |
| 
 | |
|    `Porting Extension Modules to Support Free-Threading
 | |
|    <https://py-free-threading.github.io/porting/>`_:
 | |
|    A community-maintained porting guide for extension authors.
 |