### CI Setup with setup-uv Action Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/ci.md This example shows an alternative CI setup using the `setup-uv` GitHub Action for free-threaded Python builds. Similar to `setup-python`, it allows specifying the Python version, with 't' indicating the free-threaded variant. Replace ellipses with actual action versions. ```yaml jobs: free-threaded: runs-on: ubuntu-latest steps: - uses: actions/checkout@... - uses: astral-sh/setup-uv@... with: python-version: 3.14t ``` -------------------------------- ### Build Free-Threaded Python from source Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Builds a free-threaded version of CPython from source code. This involves cloning the official CPython repository, configuring the build with the GIL disabled, compiling the code using multiple processors for speed, and then installing the built interpreter. The installation is verified by checking the Python version. ```bash # Clone CPython repository git clone https://github.com/python/cpython cd cpython # Configure with GIL disabled ./configure --with-pydebug --disable-gil # Build and install make -j$(nproc) sudo make install # Verify build python3.14t -VV ``` -------------------------------- ### Install Free-Threaded Python on macOS using python.org installers Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Installs a free-threaded Python 3.14.0 build on macOS using the official installer. It requires downloading the package, creating a customization file to enable the free-threaded framework, and then applying the customization during installation. Finally, it verifies the installation by checking the Python version. ```bash # Download installer curl -O https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg # Create customization file to enable free-threaded framework cat > ./choicechanges.plist < attributeSetting 1 choiceAttribute selected choiceIdentifier org.python.Python.PythonTFramework-3.14 EOF # Install with customization sudo installer -pkg ./python-3.14.0-macos11.pkg \ -applyChoiceChangesXML ./choicechanges.plist \ -target / # Verify installation python3.14t -VV # Output: Python 3.14.0 experimental free-threading build ... ``` -------------------------------- ### Example Issue for Free-Threading Support Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/contributing.md This markdown snippet provides a template for opening an issue to propose adding free-threading support to a Python package. It includes sections for describing the intent, noting package-specific considerations, and listing standard tasks for implementation, referencing relevant guides and tools. ```markdown Title: *Support for free-threaded CPython* I am interested in adding support for free-threading to PROJECT-NAME. I had a look at what it would take to implement that. The standard TODOs for adding free-threading support are: - [ ] Audit Python bindings and declare them free-threading compatible (xref https://py-free-threading.github.io/porting/#updating-extension-modules). - [ ] Run the test suite with `pytest-run-parallel` to find potential issues, and fix them. - [ ] Run the test suite under [Thread Sanitizer](thread_sanitizer.md). _If possible, depends on how many dependencies there are and if they run under TSan._ - [ ] Add `cp314t-*` (and `cp313t-*`) to CI to build free-threading wheels. For more details, please see the [suggested plan of attack in the py-free-threading guide](https://py-free-threading.github.io/porting/#suggested-plan-of-attack). Note that this is the first time I've looked at this repo, so I might be missing known issues or code that needs closer inspection. Any suggestions here will be very useful. I will be happy to help and work on this. Please do let me know if you'd prefer me to hold off for any reason. ``` -------------------------------- ### GitHub Actions CI for Free-Threading Tests Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt A GitHub Actions workflow to automate testing of Python projects in a free-threaded environment. It checks out code, sets up a specific Python version (e.g., 3.14t), installs project dependencies, and runs pytest with `PYTHON_GIL=0`. ```yaml name: Free-Threading Tests on: [push, pull_request] jobs: test-freethreading: runs-on: ubuntu-latest timeout-minutes: 10 steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: 3.14t - name: Install dependencies run: | python -m pip install --upgrade pip pip install -e .[test] - name: Run tests env: PYTHON_GIL: 0 run: | python -c "import sys; print(f'GIL: {sys._is_gil_enabled()}')" pytest -v tests/ ``` -------------------------------- ### Install Python on macOS using Installer Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Installs a specific Python version on macOS using a package installer and a choice changes XML file. Requires superuser privileges. Ensure the installer package and choicechanges.plist are available. ```bash sudo installer -pkg ./python-3.14.0-macos11.pkg \ -applyChoiceChangesXML ./choicechanges.plist \ -target / ``` ```bash rm -f python-3.14.0-macos11.pkg ``` -------------------------------- ### Windows CI Python Install via PowerShell Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/ci.md This PowerShell script installs a free-threaded Python build on a Windows CI runner (`runs-on: windows-latest`). It downloads the free-threaded Python installer from a NuGet source, installs it, and updates the system's PATH environment variable to include Python's directories. This is for manual installation when Actions are not sufficient. ```powershell jobs: free-threaded: runs-on: windows-latest steps: - uses: actions/checkout@... - name: custom python install script shell: pwsh run: | $pythonInstallerUrl = 'https://www.nuget.org/api/v2/package/python-freethreaded/3.13.1' Invoke-WebRequest $pythonInstallerUrl -OutFile 'python-freethreaded.3.13.1.nupkg' Install-Package python-freethreaded -Scope CurrentUser -Source $pwd $python_dir = (Get-Item((Get-Package -Name python-freethreaded).Source)).DirectoryName $env:path = $python_dir + "\tools;" + $python_dir + "\tools\Scripts;" + $env:Path ``` -------------------------------- ### Install Free-Threaded Python on Windows using NuGet Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Installs a free-threaded Python package (version 3.14.0) on Windows using the NuGet package manager. It involves downloading the package, installing it, and then updating the system's PATH environment variable to include the Python executables. The installation is verified by checking the Python version. ```powershell # Download and install free-threaded Python package $url = 'https://www.nuget.org/api/v2/package/python-freethreaded/3.14.0' Invoke-WebRequest -Uri $url -OutFile 'python-freethreaded.3.14.0.nupkg' Install-Package python-freethreaded -Scope CurrentUser -Source $pwd # Add to PATH $python_dir = (Get-Item((Get-Package -Name python-freethreaded).Source)).DirectoryName $env:path = $python_dir + "\tools;" + $python_dir + "\tools\Scripts;" + $env:Path # Verify installation python3.14t.exe -VV ``` -------------------------------- ### Configure Free-Threaded Python Install (macOS) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Creates a `choicechanges.plist` file to customize the macOS Python installer. This file enables the 'Free-threaded Python' package and accepts other default settings for an automated installation via the command line. ```bash cat > ./choicechanges.plist < attributeSetting 1 choiceAttribute selected ``` -------------------------------- ### Install Dependencies for Web Scraping Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/examples/asyncio.md Installs necessary Python packages, `aiohttp` for asynchronous HTTP requests and `beautifulsoup4` for HTML parsing, required for the web scraping script. This command should be run in your terminal. ```bash pip install aiohttp beautifulsoup4 ``` -------------------------------- ### Create Virtual Environment with uv Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Creates a virtual environment using the uv tool, specifying the free-threaded Python version '3.14t'. ```bash uv venv --python 3.14t ``` -------------------------------- ### Download Free-Threaded Python Installer (macOS) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Downloads the macOS installer package for a specific version of Python from python.org using curl. This is a preparatory step for command-line or GUI installations. ```bash curl -O https://www.python.org/ftp/python/3.14.0/python-3.14.0-macos11.pkg ``` -------------------------------- ### C Thread-Local Storage Example Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt This C code snippet shows how to implement thread-local storage using platform-specific macros (`NPY_TLS`). It defines thread-local variables for tracking error occurrences and messages, allowing each thread to manage its state independently. ```c #include // Thread-local storage macro (platform-dependent) #if defined(_MSC_VER) #define NPY_TLS __declspec(thread) #elif defined(__GNUC__) || defined(__clang__) #define NPY_TLS __thread #else #define NPY_TLS #endif // Thread-local error state NPY_TLS int error_occurred = 0; NPY_TLS char error_message[256] = {0}; static PyObject* some_function(PyObject *self, PyObject *args) { // Each thread has its own error_occurred variable if (error_occurred) { PyErr_SetString(PyExc_RuntimeError, error_message); error_occurred = 0; return NULL; } Py_RETURN_NONE; } ``` -------------------------------- ### Install Python on Nixpkgs (NixOS) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Installs the free-threaded Python 3.14 package from Nixpkgs. Supports installation with flakes for ephemeral shells or standard channel updates for persistent environments. ```bash nix shell nixpkgs#python314FreeThreading ``` ```bash sudo nix-channel --update nix-shell -p python314FreeThreading ``` -------------------------------- ### Install Free-Threaded Python via Official Installer (Windows) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Installs the free-threaded version of Python using the official Python.org installer on Windows. This method is a fallback if nuget is not preferred, but may lead to issues with shared site-packages if both gil-enabled and free-threaded builds are installed. It supports quiet installation with specific flags. ```powershell $url = 'https://www.python.org/ftp/python/3.14.0/python-3.14.0-amd64.exe' Invoke-WebRequest -Uri $url -OutFile 'python-3.14.0-amd64.exe' .\python-3.14.0-amd64.exe /quiet Include_freethreaded=1 ``` -------------------------------- ### Install Python on Ubuntu using PPA Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Installs the free-threaded Python 3.14 package on Ubuntu by adding the deadsnakes PPA to the system's software repositories. Requires updating package lists after adding the PPA. ```bash sudo add-apt-repository ppa:deadsnakes sudo apt-get update sudo apt-get install python3.14-nogil ``` -------------------------------- ### CI Setup with setup-python Action Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/ci.md This snippet demonstrates how to set up a free-threaded Python build on a CI runner using the `setup-python` GitHub Action. It specifies the desired Python version, ensuring a free-threaded build is used. The `python-version` needs to be configured with 't' to indicate a free-threaded build. ```yaml jobs: free-threaded: runs-on: ubuntu-latest steps: - uses: actions/checkout@... - uses: actions/setup-python@... with: python-version: 3.14t ``` -------------------------------- ### Install Free-Threaded Jupyter Kernel (Bash) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md This command installs the free-threaded Jupyter kernel. It requires a specific Python executable (`python3.14t`) and registers the kernel for user-level access, making it available for both standard and free-threaded Python installations. ```bash python3.14t -m ipykernel install --name python3.14t --user ``` -------------------------------- ### GitHub Actions for Building Wheels with cibuildwheel Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt A GitHub Actions workflow designed to build Python wheels for various platforms using `cibuildwheel`. It leverages matrix strategy for different operating systems and specifies the Python build environment (e.g., `cp314t-*`) for free-threaded compatibility. ```yaml name: Build Wheels on: [push, pull_request] jobs: build_wheels: runs-on: ${{ matrix.os }} strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] steps: - uses: actions/checkout@v4 - name: Build wheels uses: pypa/cibuildwheel@v2.21 env: CIBW_BUILD: cp314t-* - uses: actions/upload-artifact@v4 with: name: wheels-${{ matrix.os }} path: ./wheelhouse/*.whl ``` -------------------------------- ### Install Python on Fedora Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Installs the free-threaded Python 3.14 package on Fedora using the DNF package manager. This command installs the interpreter to /usr/bin/python3.14t. ```bash sudo dnf install python3.14-freethreading ``` -------------------------------- ### Configure CPython Build with Free-threading Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Configures the CPython build process to include free-threading support by passing the '--disable-gil' flag to the configure script. Also includes debug builds. ```bash ./configure --with-pydebug --disable-gil ``` -------------------------------- ### Install NumPy Build Requirements Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/thread_sanitizer.md This command installs the necessary build dependencies for NumPy from its `build_requirements.txt` file. This is a prerequisite before attempting to build NumPy. ```bash cd numpy python -m pip install -r requirements/build_requirements.txt ``` -------------------------------- ### Install Python 3.14 with Pyenv Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Installs Python version 3.14 with debug enabled using pyenv, which is useful for building free-threaded versions or when switching Python versions frequently. ```bash pyenv install --debug --keep 3.14 ``` -------------------------------- ### Install Free-Threaded Python via Nuget (Windows) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Automates the download and installation of the free-threaded Python package using nuget on Windows. This method avoids issues with shared site-packages by installing 'python-freethreaded' separately. It modifies the PATH environment variable for the current session. ```powershell $url = 'https://www.nuget.org/api/v2/package/python-freethreaded/3.14.0' Invoke-WebRequest -Uri $url -OutFile 'python-freethreaded.3.14.0.nupkg' Install-Package python-freethreaded -Scope CurrentUser -Source $pwd $python_dir = (Get-Item((Get-Package -Name python-freethreaded).Source)).DirectoryName $env:path = $python_dir + "\tools;" + $python_dir + "\tools\Scripts;" + $env:Path ``` -------------------------------- ### Bash Commands for GDB Debugging Python Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Shell commands to run Python tests under the GNU Debugger (GDB) for debugging concurrent issues. It includes commands to start GDB, run the test, and inspect Python backtraces for all threads when a crash occurs. ```bash # Run pytest under GDB PYTHON_GIL=0 gdb --args python -m pytest -x -v "tests/test_concurrent.py::test_race" # GDB commands (gdb) run (gdb) py-bt # Python backtrace when crash occurs (gdb) thread apply all py-bt # Show all thread backtraces (gdb) info threads # List all threads ``` -------------------------------- ### Install Free-threaded Python using Homebrew Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Installs the free-threaded Python package on macOS and Linux systems using the Homebrew package manager. The interpreter will be located at $(brew --prefix)/bin/python3.14t. ```bash brew install python-freethreading ``` -------------------------------- ### Create Anaconda Testing Environment with Free-threaded Python Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Creates a Conda environment named 'nogil' using Anaconda's test channel for Python 3.14 free-threading ABI builds. It specifies multiple channels including the main Anaconda channel. ```bash conda create -n nogil --override-channels -c ad-testing/label/py314 -c https://repo.anaconda.com/pkgs/main python-freethreading ``` -------------------------------- ### Bash Commands for Pytest Parallel Execution Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Shell commands to install and use `pytest-run-parallel` and `pytest-repeat` for running Python tests in parallel threads and repeating them to catch flaky failures. Requires setting `PYTHON_GIL=0` for free-threaded execution. ```bash # Install plugin pip install pytest-run-parallel # Run tests in parallel threads PYTHON_GIL=0 pytest --parallel-threads 8 tests/ # Repeat tests to catch flaky failures pip install pytest-repeat PYTHON_GIL=0 pytest -x -v --count=100 tests/test_concurrent.py ``` -------------------------------- ### Create Conda Environment with Free-threaded Python Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/installing-cpython.md Creates a Conda environment named 'nogil' with the free-threaded Python package. Supports both mamba and conda package managers. ```bash mamba create -n nogil -c conda-forge python-freethreading ``` ```bash conda create -n nogil --override-channels -c conda-forge python-freethreading ``` -------------------------------- ### Enable Free-Threading in Cython Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt This snippet shows how to enable free-threading compatibility in Cython modules. It demonstrates using the `freethreading_compatible=True` compiler directive and conditionally applying it based on the Cython version for compatibility with setuptools integration. ```python # cython: freethreading_compatible=True def my_function(): """Function in free-threading compatible Cython module""" return 42 # Or via setuptools from Cython.Compiler.Version import version as cython_version from packaging.version import Version compiler_directives = {} if Version(cython_version) >= Version("3.1.0"): compiler_directives["freethreading_compatible"] = True setup( ext_modules=cythonize( extensions, compiler_directives=compiler_directives, ) ) ``` -------------------------------- ### Install TSan-enabled CPython using Pyenv Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/thread_sanitizer.md This command shows how to install a specific version of CPython with Thread Sanitizer support using `pyenv`. It utilizes environment variables to specify the compiler and configure options. ```bash CC=/path/to/clang CXX=/path/to/clang++ CONFIGURE_OPTS="--with-thread-sanitizer" pyenv install 3.14t-dev ``` -------------------------------- ### Install CFFI with Version Constraint (Bash) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/dependencies.md Ensures that CFFI version 2.0.0 or higher is installed, which is required for free-threaded Python builds. ```bash python -m pip install cffi>=2.0.0 ``` -------------------------------- ### Configure and Build CPython with Thread Sanitizer Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/thread_sanitizer.md These commands configure and build the CPython interpreter with Thread Sanitizer enabled and a specified installation prefix. It requires Clang as the C/C++ compiler and the `--disable-gil` and `--with-thread-sanitizer` flags. ```bash cd cpython CC=/path/to/clang CXX=/path/to/clang++ ./configure --disable-gil --with-thread-sanitizer --prefix $PWD/cpython-tsan make -j 8 make install ``` -------------------------------- ### Install debug CPython with pyenv Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/debugging.md This shell command shows how to install a debug version of CPython using `pyenv`. The `--debug` flag enables debugging symbols, and `--keep` ensures the source files are retained. This is essential for `gdb`/`lldb` to load source files during debugging sessions, providing a more comprehensive debugging experience. ```bash pyenv install --debug --keep 3.13.1 ``` -------------------------------- ### CI Timeout Configuration Example Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/ci.md This YAML snippet illustrates how to configure a timeout for a CI job when using free-threaded Python. Due to the potential for deadlocks with free-threading, setting a `timeout-minutes` is recommended to prevent CI jobs from hanging indefinitely. The value should be adjusted based on expected build times. ```yaml jobs: test_freethreading: timeout-minutes: 10 steps: - uses: actions/checkout@... ... ``` -------------------------------- ### Python Thread-Local Storage for Caching Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt This Python code demonstrates using `threading.local()` to create thread-local storage for a cache. Each thread maintains its own independent cache, eliminating the need for locks and improving performance for thread-specific data. ```python import threading from internals import _do_expensive_calculation # Each thread gets its own cache local = threading.local() def do_calculation(arg): # Initialize cache for this thread if needed if not hasattr(local, 'cache'): local.cache = {} if arg not in local.cache: local.cache[arg] = _do_expensive_calculation(arg) return local.cache[arg] # Usage from concurrent.futures import ThreadPoolExecutor def worker(items): return [do_calculation(item) for item in items] with ThreadPoolExecutor(max_workers=4) as executor: chunks = [range(25*i, 25*(i+1)) for i in range(4)] results = list(executor.map(worker, chunks)) ``` -------------------------------- ### Example Multithreaded Test with Shared List Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/testing.md This example demonstrates how to use the `run_threaded` helper to perform a multithreaded test involving appending to a shared list. It defines a closure that waits for a barrier and then appends an index to the list. The test asserts that the sum of the appended elements matches the expected sum, verifying thread safety. ```python def test_parallel_append(): shared_list = [] def closure(i, b): b.wait() shared_list.append(i) run_threaded(closure, num_threads=8, pass_barrier=True, pass_count=True) assert sum(shared_list) == sum(range(8)) ``` -------------------------------- ### Python Thread Pool Testing Helper Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt A Python helper function to run a given function multiple times in parallel using `ThreadPoolExecutor`. It supports passing arguments, barriers for synchronization, and iteration counts. Useful for testing thread-safe code. ```python from concurrent.futures import ThreadPoolExecutor import threading def run_threaded( func, num_threads=8, pass_count=False, pass_barrier=False, outer_iterations=1, prepare_args=None, ): """Run function many times in parallel""" for _ in range(outer_iterations): with ThreadPoolExecutor(max_workers=num_threads) as tpe: if prepare_args is None: args = [] else: args = prepare_args() if pass_barrier: barrier = threading.Barrier(num_threads) args.append(barrier) if pass_count: all_args = [(func, i, *args) for i in range(num_threads)] else: all_args = [(func, *args) for i in range(num_threads)] try: futures = [] for arg in all_args: futures.append(tpe.submit(*arg)) finally: if len(futures) < num_threads and pass_barrier: barrier.abort() for f in futures: f.result() # Example test def test_parallel_append(): shared_list = [] def closure(i, b): b.wait() # Synchronize threads shared_list.append(i) run_threaded(closure, num_threads=8, pass_barrier=True, pass_count=True) assert sum(shared_list) == sum(range(8)) assert len(shared_list) == 8 ``` -------------------------------- ### C Code for Wrapping Thread-Unsafe Libraries Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt A C code snippet demonstrating how to wrap a thread-unsafe native library function to make it safe for concurrent use in Python. It uses `PyMutex` for locking around calls to the underlying library function, ensuring exclusive access. ```c #include typedef struct { low_level_library_state *state; PyMutex lock; } lib_state_struct; static PyObject* call_library_function(PyObject *self, PyObject *args) { lib_state_struct *lib_state; int result; if (!PyArg_ParseTuple(args, "O", &lib_state)) { return NULL; } PyMutex_Lock(&lib_state->lock); result = library_function(lib_state->state); PyMutex_Unlock(&lib_state->lock); return PyLong_FromLong(result); } ``` -------------------------------- ### Wrap Non-reentrant Libraries with PyMutex Lock (C) Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt This C code demonstrates how to wrap calls to a non-reentrant library using a global `PyMutex` lock to ensure thread safety. It acquires the lock before calling the library function and releases it afterward, preventing race conditions when multiple threads access the same library. Dependencies include the Python C API. ```c #include // Global lock for non-reentrant library static PyMutex global_library_lock = {0}; static PyObject* call_nonreentrant_function(PyObject *self, PyObject *args) { int arg; int result; if (!PyArg_ParseTuple(args, "i", &arg)) { return NULL; } // All library calls must acquire global lock PyMutex_Lock(&global_library_lock); result = nonreentrant_library_function(arg); PyMutex_Unlock(&global_library_lock); return PyLong_FromLong(result); } ``` -------------------------------- ### Convert Global Cache to Thread-Local Cache in Python Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/porting.md This snippet demonstrates how to convert a shared global cache into a thread-local cache using Python's `threading.local`. Each thread gets its own private copy of the cache, preventing race conditions. This is suitable when the overhead of multiple cache copies is acceptable. ```python import threading from internals import _do_expensive_calculation local = threading.local() local.cache = {} def do_calculation(arg): if arg not in local.cache: local.cache[arg] = _do_expensive_calculation(arg) return local.cache[arg] ``` -------------------------------- ### Get CPU Core Count - Python Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/examples/mandelbrot-threads.ipynb Retrieves the number of logical CPU cores available on the system using the `os` module. It also includes a placeholder for manually setting hyperthreads per core. ```python import os ncpus = os.cpu_count() # Adjust this to fit your host. Not easy to detect it manually. # Set to 1 if hyperthreading is disabled. hyperthreads_per_core = 2 ``` -------------------------------- ### Bash Commands for Building CPython with Address Sanitizer Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Shell commands to build CPython with Address Sanitizer (ASan) enabled for detecting memory errors like buffer overflows and use-after-free. The process involves configuring CPython, compiling, and running tests, with an option to disable leak detection. ```bash # Build CPython with ASan ./configure --with-pydebug --disable-gil --with-address-sanitizer make -j$(nproc) # Build extension with ASan pip install --no-build-isolation -e . -Csetup-args=-Db_sanitize=address # Run with leak detection disabled ASAN_OPTIONS="detect_leaks=0" python -m pytest tests/ ``` -------------------------------- ### Declare Free-Threading Support in C Extension Modules (Single-phase Init) Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Illustrates how to declare free-threading support for C extension modules using the single-phase initialization API. It utilizes `PyUnstable_Module_SetGIL` to explicitly mark the module as not requiring the GIL if `Py_GIL_DISABLED` is defined during compilation. ```c #include PyMODINIT_FUNC PyInit__module(void) { PyObject *mod = PyModule_Create(&module); if (mod == NULL) { return NULL; } #ifdef Py_GIL_DISABLED PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED); #endif return mod; } ``` -------------------------------- ### Declare Free-Threading Support in C Extension Modules (Multi-phase Init) Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Shows how to declare that a C extension module supports running with the Global Interpreter Lock (GIL) disabled using the multi-phase initialization API. It involves defining module slots and conditionally including `Py_MOD_GIL_NOT_USED` if the `Py_GIL_DISABLED` macro is defined during compilation. ```c #include // Define module slots with GIL disabled declaration static PyModuleDef_Slot module_slots[] = { #ifdef Py_GIL_DISABLED {Py_mod_gil, Py_MOD_GIL_NOT_USED}, #endif {0, NULL} }; static struct PyModuleDef module_def = { PyModuleDef_HEAD_INIT, .m_name = "my_module", .m_slots = module_slots, }; PyMODINIT_FUNC PyInit_my_module(void) { return PyModuleDef_Init(&module_def); } ``` -------------------------------- ### Thread-Safe Cache with PyMutex (C Extension) Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt This C code snippet illustrates how to implement a thread-safe cache within a Python C extension using `PyMutex`. It conditionally applies locking based on whether the GIL is disabled, ensuring thread safety in free-threaded environments. ```c #include #ifdef Py_GIL_DISABLED static PyMutex cache_lock = {0}; #define LOCK() PyMutex_Lock(&cache_lock) #define UNLOCK() PyMutex_Unlock(&cache_lock) #else #define LOCK() #define UNLOCK() #endif static PyObject *global_cache = NULL; static PyObject* get_from_cache(PyObject *self, PyObject *key) { PyObject *value; LOCK(); value = PyDict_GetItem(global_cache, key); if (value == NULL) { value = compute_expensive_value(key); PyDict_SetItem(global_cache, key, value); } Py_INCREF(value); UNLOCK(); return value; } ``` -------------------------------- ### Example TSan Suppression File Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/thread_sanitizer.md This code snippet demonstrates the format of a ThreadSanitizer (TSan) suppression file. Each line specifies a 'race' followed by the function name where the race is detected. TSan will ignore races occurring in these specified functions. ```plaintext race:llvm::RuntimeDyldELF::registerEHFrames race:partial_vectorcall_fallback race:dnnl_sgemm ``` -------------------------------- ### PyO3 Module with GIL Disabled (Rust) Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt This Rust code snippet demonstrates how to create a PyO3 module in Rust that does not rely on the Python Global Interpreter Lock (GIL). This is essential for true multi-threading in Python extensions. ```rust use pyo3::prelude::*; #[pymodule(gil_used = false)] fn my_module(py: Python, m: &Bound<'_, PyModule>) -> PyResult<()> { // Module implementation Ok(()) } ``` -------------------------------- ### Thread-Safe Cache with Mutex (Python) Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt This Python code implements a thread-safe cache using `threading.Lock`. It employs a double-check locking pattern to minimize lock contention, first checking the cache without a lock and acquiring it only if the item is not found. ```python import threading from internals import _do_expensive_calculation cache_lock = threading.Lock() global_cache = {} def do_calculation(arg): # Fast path without lock if arg in global_cache: return global_cache[arg] # Slow path with lock with cache_lock: # Double-check pattern if arg not in global_cache: global_cache[arg] = _do_expensive_calculation(arg) return global_cache[arg] # Usage from concurrent.futures import ThreadPoolExecutor with ThreadPoolExecutor(max_workers=8) as executor: results = list(executor.map(do_calculation, range(100))) ``` -------------------------------- ### Bash Commands for Building CPython with Thread Sanitizer Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt Shell commands to build CPython with Thread Sanitizer (TSan) enabled, which helps detect data races and deadlocks. It involves configuring CPython with specific flags (`--disable-gil`, `--with-thread-sanitizer`), compiling, and then running tests with TSan options and a suppression file. ```bash # Build CPython with TSan ./configure --with-pydebug --disable-gil --with-thread-sanitizer make -j$(nproc) # Build extension with TSan CFLAGS="-fsanitize=thread" pip install --no-build-isolation -e . # Run tests TSAN_OPTIONS="suppressions=tsan.supp" python -m pytest tests/ # Create suppression file for known false positives cat > tsan.supp < typedef struct { PyObject_HEAD PyObject *data; long counter; } MyObject; static PyObject* MyObject_increment(MyObject *self) { int res; Py_BEGIN_CRITICAL_SECTION(self); self->counter++; res = self->counter; Py_END_CRITICAL_SECTION(); return PyLong_FromLong(res); } static PyObject* MyObject_update_data(MyObject *self, PyObject *new_data) { Py_BEGIN_CRITICAL_SECTION(self); Py_SETREF(self->data, Py_NewRef(new_data)); Py_END_CRITICAL_SECTION(); Py_RETURN_NONE; } ``` -------------------------------- ### Declare Cython Free-threaded Support (Setuptools) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/porting-extensions.md Using setuptools, you can enable `freethreading_compatible=True` by passing the `compiler_directives` keyword argument to `cythonize`, provided Cython version is 3.1.0 or later. ```python from Cython.Compiler.Version import version as cython_version from packaging.version import Version compiler_directives = {} if Version(cython_version) >= Version("3.1.0"): compiler_directives["freethreading_compatible"] = True setup( ext_modules=cythonize( extensions, compiler_directives=compiler_directives, ) ) ``` -------------------------------- ### Building Free-Threaded Wheels with cibuildwheel Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/ci.md This configuration snippet shows how to enable building free-threaded wheels using `cibuildwheel` version 3.1+. It sets the `CIBW_BUILD` environment variable to target the free-threaded Python interpreter (e.g., `cp314t`) for a specific build platform. This is crucial for distributing free-threaded Python packages. ```yaml - name: Build wheels uses: pypa/cibuildwheel@... env: # enable cpython-freethreading necessary only for 3.13t # CIBW_ENABLE: cpython-freethreading CIBW_BUILD: cp314t-${{ matrix.buildplat }} ``` -------------------------------- ### Set up TSan-enabled CPython Virtual Environment Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/thread_sanitizer.md This demonstrates how to create and activate a Python virtual environment using a CPython interpreter that was previously built with Thread Sanitizer. This isolates the TSan-enabled Python for testing. ```bash # Create a virtual environment: $PWD/cpython-tsan/bin/python3.14t -m venv ~/tsanvenv # Then activate it: source ~/tsanvenv/bin/activate # Exit the `cpython` folder (preparation for the next step below) cd .. ``` -------------------------------- ### Running Michi with Default Python Threads Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/examples/monte-carlo.md This command executes the Michi program using the default Python build with threads enabled. It forces the use of threads for benchmarking the 'tsbenchmark' task. This configuration is expected to be slow due to the GIL. ```bash uv run --python=3.14 python michi.py --force-threads tsbenchmark ``` -------------------------------- ### Declare C API Free-threaded Support (Single-phase init) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/porting-extensions.md Extensions using single-phase initialization should call `PyUnstable_Module_SetGIL()` within the module's initialization function to declare free-threaded support. This ensures compatibility when the GIL is disabled. ```c PyMODINIT_FUNC PyInit__module(void) { PyObject *mod = PyModule_Create(&module); if (mod == NULL) { return NULL; } #ifdef Py_GIL_DISABLED PyUnstable_Module_SetGIL(mod, Py_MOD_GIL_NOT_USED); #endif return mod; } ``` -------------------------------- ### Initialize Read-Only Global Cache at Module Initialization (C) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/porting-extensions.md This C code shows how to initialize a global cache during module initialization in CPython. The cache is set up once in the `PyInit` function and is read-only thereafter. This is safe in free-threaded builds because module initialization happens only once per interpreter, avoiding concurrent access issues for read-only data. ```c static int *cache = NULL; PyMODINIT_FUNC PyInit__module(void) { PyObject *mod = PyModule_Create(&module); if (mod == NULL) { return NULL; } // don't need to lock or do anything special cache = setup_cache(); // do rest of initialization } ``` -------------------------------- ### Running Michi with Free-Threaded Python Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/examples/monte-carlo.md This command executes the Michi program using a free-threaded Python build. The 't' suffix in the Python version indicates the use of the free-threaded interpreter, allowing for true multi-threading performance on CPU-bound tasks. ```bash uv run --python=3.14t python michi.py --force-threads tsbenchmark ``` -------------------------------- ### Locking Two Objects Simultaneously in C API Source: https://context7.com/quansight-labs/free-threaded-compatibility/llms.txt This C code snippet shows how to safely lock two objects simultaneously using `Py_BEGIN_CRITICAL_SECTION2` and `Py_END_CRITICAL_SECTION2`. It emphasizes locking objects in a consistent order (by address) to prevent deadlocks when transferring data between them. ```c static PyObject* transfer_data(MyObject *source, MyObject *dest) { PyObject *data; // Lock both objects (sorted by address to prevent deadlock) Py_BEGIN_CRITICAL_SECTION2(source, dest); data = source->data; Py_INCREF(data); source->data = Py_None; Py_INCREF(Py_None); Py_SETREF(dest->data, data); Py_END_CRITICAL_SECTION2(); Py_RETURN_NONE; } ``` -------------------------------- ### Mandelbrot Image Array Initialization and Population (Python) Source: https://github.com/quansight-labs/free-threaded-compatibility/blob/main/docs/examples/mandelbrot.md This snippet initializes a 2D NumPy array to represent the Mandelbrot image and then iterates through defined x and y domains to populate the array by calling the mandelbrot function for each pixel coordinate. It requires NumPy and assumes x_domain and y_domain are pre-defined. ```python import numpy as np iteration_array = np.zeros((800, 800)) for i, x in enumerate(x_domain): for j, y in enumerate(y_domain): iteration_array[j, i] = mandelbrot(x, y) ```