From 268569133bf427c5389b6930d32daf1c8a91c6d7 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 6 Aug 2024 12:08:16 -0600 Subject: [PATCH 01/31] add support in pyo3-build-config for free-threaded python --- pyo3-build-config/src/impl_.rs | 42 ++++++++++++++++++++++++++++++++++ pyo3-build-config/src/lib.rs | 1 + 2 files changed, 43 insertions(+) diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index d38d41ed552..73b25cb7c7d 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -181,6 +181,10 @@ impl InterpreterConfig { out.push("cargo:rustc-cfg=Py_LIMITED_API".to_owned()); } + if self.build_flags.0.contains(&BuildFlag::Py_GIL_DISABLED) { + out.push("cargo:rustc-cfg=Py_GIL_DISABLED".to_owned()); + } + for flag in &self.build_flags.0 { out.push(format!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag)); } @@ -2733,6 +2737,44 @@ mod tests { ); } + #[test] + fn test_build_script_outputs_gil_disabled() { + let mut build_flags = BuildFlags::default(); + build_flags.0.insert(BuildFlag::Py_GIL_DISABLED); + let interpreter_config = InterpreterConfig { + implementation: PythonImplementation::CPython, + version: PythonVersion { + major: 3, + minor: 13, + }, + shared: true, + abi3: false, + lib_name: Some("python3".into()), + lib_dir: None, + executable: None, + pointer_width: None, + build_flags: build_flags, + suppress_build_script_link_lines: false, + extra_build_script_lines: vec![], + }; + + assert_eq!( + interpreter_config.build_script_outputs(), + [ + "cargo:rustc-cfg=Py_3_6".to_owned(), + "cargo:rustc-cfg=Py_3_7".to_owned(), + "cargo:rustc-cfg=Py_3_8".to_owned(), + "cargo:rustc-cfg=Py_3_9".to_owned(), + "cargo:rustc-cfg=Py_3_10".to_owned(), + "cargo:rustc-cfg=Py_3_11".to_owned(), + "cargo:rustc-cfg=Py_3_12".to_owned(), + "cargo:rustc-cfg=Py_3_13".to_owned(), + "cargo:rustc-cfg=Py_GIL_DISABLED".to_owned(), + "cargo:rustc-cfg=py_sys_config=\"Py_GIL_DISABLED\"".to_owned(), + ] + ); + } + #[test] fn test_build_script_outputs_debug() { let mut build_flags = BuildFlags::default(); diff --git a/pyo3-build-config/src/lib.rs b/pyo3-build-config/src/lib.rs index 0bc2274e0e5..033e7b46540 100644 --- a/pyo3-build-config/src/lib.rs +++ b/pyo3-build-config/src/lib.rs @@ -166,6 +166,7 @@ pub fn print_expected_cfgs() { } println!("cargo:rustc-check-cfg=cfg(Py_LIMITED_API)"); + println!("cargo:rustc-check-cfg=cfg(Py_GIL_DISABLED)"); println!("cargo:rustc-check-cfg=cfg(PyPy)"); println!("cargo:rustc-check-cfg=cfg(GraalPy)"); println!("cargo:rustc-check-cfg=cfg(py_sys_config, values(\"Py_DEBUG\", \"Py_REF_DEBUG\", \"Py_TRACE_REFS\", \"COUNT_ALLOCS\"))"); From e8613d56773dcc85a3a34291d198ed40db92e052 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 6 Aug 2024 12:09:12 -0600 Subject: [PATCH 02/31] update object.h bindings for free-threaded build --- pyo3-ffi/src/object.rs | 70 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 64 insertions(+), 6 deletions(-) diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 9181cb17dd2..688be68bb4c 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -2,6 +2,8 @@ use crate::pyport::{Py_hash_t, Py_ssize_t}; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; use std::ptr; +use std::sync::atomic::Ordering::Relaxed; +use std::sync::atomic::{AtomicIsize, AtomicU32}; #[cfg(Py_LIMITED_API)] opaque_struct!(PyTypeObject); @@ -22,12 +24,29 @@ pub const _Py_IMMORTAL_REFCNT: Py_ssize_t = { } }; +#[cfg(Py_GIL_DISABLED)] +pub const _Py_IMMORTAL_REFCNT_LOCAL: u32 = u32::MAX; +#[cfg(Py_GIL_DISABLED)] +pub const _Py_REF_SHARED_SHIFT: isize = 2; + pub const PyObject_HEAD_INIT: PyObject = PyObject { #[cfg(py_sys_config = "Py_TRACE_REFS")] _ob_next: std::ptr::null_mut(), #[cfg(py_sys_config = "Py_TRACE_REFS")] _ob_prev: std::ptr::null_mut(), - #[cfg(Py_3_12)] + #[cfg(Py_GIL_DISABLED)] + ob_tid: 0, + #[cfg(Py_GIL_DISABLED)] + _padding: 0, + #[cfg(Py_GIL_DISABLED)] + ob_mutex: 0, + #[cfg(Py_GIL_DISABLED)] + ob_gc_bits: 0, + #[cfg(Py_GIL_DISABLED)] + ob_ref_local: 0, + #[cfg(Py_GIL_DISABLED)] + ob_ref_shared: 0, + #[cfg(all(not(Py_GIL_DISABLED), Py_3_12))] ob_refcnt: PyObjectObRefcnt { ob_refcnt: 1 }, #[cfg(not(Py_3_12))] ob_refcnt: 1, @@ -67,6 +86,21 @@ pub struct PyObject { pub _ob_next: *mut PyObject, #[cfg(py_sys_config = "Py_TRACE_REFS")] pub _ob_prev: *mut PyObject, + #[cfg(Py_GIL_DISABLED)] + pub ob_tid: usize, + #[cfg(Py_GIL_DISABLED)] + pub _padding: u16, + #[cfg(Py_GIL_DISABLED)] + // TODO this should be a PyMutex not a u8 + // need to write PyMutex wrappers + pub ob_mutex: u8, // per-object lock + #[cfg(Py_GIL_DISABLED)] + pub ob_gc_bits: u8, // gc-related state + #[cfg(Py_GIL_DISABLED)] + pub ob_ref_local: u32, // local reference count + #[cfg(Py_GIL_DISABLED)] + pub ob_ref_shared: Py_ssize_t, // shared reference count + #[cfg(not(Py_GIL_DISABLED))] pub ob_refcnt: PyObjectObRefcnt, #[cfg(PyPy)] pub ob_pypy_link: Py_ssize_t, @@ -91,6 +125,18 @@ pub unsafe fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int { } #[inline] +#[cfg(Py_GIL_DISABLED)] +pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t { + let local = (AtomicU32::from((*ob).ob_ref_local)).load(Relaxed); + if local == _Py_IMMORTAL_REFCNT_LOCAL { + return _Py_IMMORTAL_REFCNT; + } + let shared = (AtomicIsize::from((*ob).ob_ref_shared)).load(Relaxed); + local as Py_ssize_t + Py_ssize_t::from(shared >> _Py_REF_SHARED_SHIFT) +} + +#[inline] +#[cfg(not(Py_GIL_DISABLED))] #[cfg(Py_3_12)] pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t { (*ob).ob_refcnt.ob_refcnt @@ -134,7 +180,7 @@ pub unsafe fn Py_IS_TYPE(ob: *mut PyObject, tp: *mut PyTypeObject) -> c_int { } #[inline(always)] -#[cfg(all(Py_3_12, target_pointer_width = "64"))] +#[cfg(all(not(Py_GIL_DISABLED), Py_3_12, target_pointer_width = "64"))] pub unsafe fn _Py_IsImmortal(op: *mut PyObject) -> c_int { (((*op).ob_refcnt.ob_refcnt as crate::PY_INT32_T) < 0) as c_int } @@ -507,8 +553,13 @@ extern "C" { #[inline(always)] pub unsafe fn Py_INCREF(op: *mut PyObject) { - // On limited API or with refcount debugging, let the interpreter do refcounting - #[cfg(any(Py_LIMITED_API, py_sys_config = "Py_REF_DEBUG", GraalPy))] + // On limited API, the free-threaded build, or with refcount debugging, let the interpreter do refcounting + #[cfg(any( + Py_GIL_DISABLED, + Py_LIMITED_API, + py_sys_config = "Py_REF_DEBUG", + GraalPy + ))] { // _Py_IncRef was added to the ABI in 3.10; skips null checks #[cfg(all(Py_3_10, not(PyPy)))] @@ -523,7 +574,12 @@ pub unsafe fn Py_INCREF(op: *mut PyObject) { } // version-specific builds are allowed to directly manipulate the reference count - #[cfg(not(any(any(Py_LIMITED_API, py_sys_config = "Py_REF_DEBUG", GraalPy))))] + #[cfg(not(any( + Py_GIL_DISABLED, + Py_LIMITED_API, + py_sys_config = "Py_REF_DEBUG", + GraalPy + )))] { #[cfg(all(Py_3_12, target_pointer_width = "64"))] { @@ -559,9 +615,10 @@ pub unsafe fn Py_INCREF(op: *mut PyObject) { track_caller )] pub unsafe fn Py_DECREF(op: *mut PyObject) { - // On limited API or with refcount debugging, let the interpreter do refcounting + // On limited API, the free-threaded build, or with refcount debugging, let the interpreter do refcounting // On 3.12+ we implement refcount debugging to get better assertion locations on negative refcounts #[cfg(any( + Py_GIL_DISABLED, Py_LIMITED_API, all(py_sys_config = "Py_REF_DEBUG", not(Py_3_12)), GraalPy @@ -580,6 +637,7 @@ pub unsafe fn Py_DECREF(op: *mut PyObject) { } #[cfg(not(any( + Py_GIL_DISABLED, Py_LIMITED_API, all(py_sys_config = "Py_REF_DEBUG", not(Py_3_12)), GraalPy From eeac20c3b82a305106092004b5b97f338d44a61f Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 6 Aug 2024 15:56:53 -0600 Subject: [PATCH 03/31] Add PyMutex bindings --- pyo3-ffi/src/cpython/lock.rs | 10 ++++++++++ pyo3-ffi/src/cpython/mod.rs | 3 +++ pyo3-ffi/src/object.rs | 6 ++++-- 3 files changed, 17 insertions(+), 2 deletions(-) create mode 100644 pyo3-ffi/src/cpython/lock.rs diff --git a/pyo3-ffi/src/cpython/lock.rs b/pyo3-ffi/src/cpython/lock.rs new file mode 100644 index 00000000000..3adb16a1ed3 --- /dev/null +++ b/pyo3-ffi/src/cpython/lock.rs @@ -0,0 +1,10 @@ +#[repr(C)] +#[derive(Debug, Copy, Clone)] +pub struct PyMutex { + pub _bits: u8, +} + +extern "C" { + pub fn PyMutex_Lock(m: *mut PyMutex); + pub fn PyMutex_UnLock(m: *mut PyMutex); +} diff --git a/pyo3-ffi/src/cpython/mod.rs b/pyo3-ffi/src/cpython/mod.rs index 1710dbc4122..c763439ca6b 100644 --- a/pyo3-ffi/src/cpython/mod.rs +++ b/pyo3-ffi/src/cpython/mod.rs @@ -18,6 +18,8 @@ pub(crate) mod import; pub(crate) mod initconfig; // skipped interpreteridobject.h pub(crate) mod listobject; +#[cfg(Py_3_13)] +pub(crate) mod lock; pub(crate) mod longobject; #[cfg(all(Py_3_9, not(PyPy)))] pub(crate) mod methodobject; @@ -54,6 +56,7 @@ pub use self::import::*; #[cfg(all(Py_3_8, not(PyPy)))] pub use self::initconfig::*; pub use self::listobject::*; +pub use self::lock::*; pub use self::longobject::*; #[cfg(all(Py_3_9, not(PyPy)))] pub use self::methodobject::*; diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 688be68bb4c..183438076ab 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -1,4 +1,6 @@ use crate::pyport::{Py_hash_t, Py_ssize_t}; +#[cfg(not(Py_LIMITED_API))] +use crate::PyMutex; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; use std::ptr; @@ -39,7 +41,7 @@ pub const PyObject_HEAD_INIT: PyObject = PyObject { #[cfg(Py_GIL_DISABLED)] _padding: 0, #[cfg(Py_GIL_DISABLED)] - ob_mutex: 0, + ob_mutex: PyMutex { _bits: 0 }, #[cfg(Py_GIL_DISABLED)] ob_gc_bits: 0, #[cfg(Py_GIL_DISABLED)] @@ -93,7 +95,7 @@ pub struct PyObject { #[cfg(Py_GIL_DISABLED)] // TODO this should be a PyMutex not a u8 // need to write PyMutex wrappers - pub ob_mutex: u8, // per-object lock + pub ob_mutex: PyMutex, // per-object lock #[cfg(Py_GIL_DISABLED)] pub ob_gc_bits: u8, // gc-related state #[cfg(Py_GIL_DISABLED)] From 8eebe436b846edc9081e5e9013edabef48e07494 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 6 Aug 2024 15:57:24 -0600 Subject: [PATCH 04/31] fix po3-ffi-check with free-threaded build --- pyo3-ffi/src/cpython/initconfig.rs | 2 ++ pyo3-ffi/src/cpython/weakrefobject.rs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/pyo3-ffi/src/cpython/initconfig.rs b/pyo3-ffi/src/cpython/initconfig.rs index 32931415888..ab03ca79d61 100644 --- a/pyo3-ffi/src/cpython/initconfig.rs +++ b/pyo3-ffi/src/cpython/initconfig.rs @@ -143,6 +143,8 @@ pub struct PyConfig { pub int_max_str_digits: c_int, #[cfg(Py_3_13)] pub cpu_count: c_int, + #[cfg(Py_GIL_DISABLED)] + pub enable_gil: c_int, pub pathconfig_warnings: c_int, #[cfg(Py_3_10)] pub program_name: *mut wchar_t, diff --git a/pyo3-ffi/src/cpython/weakrefobject.rs b/pyo3-ffi/src/cpython/weakrefobject.rs index 3a232c7ed38..9413b645091 100644 --- a/pyo3-ffi/src/cpython/weakrefobject.rs +++ b/pyo3-ffi/src/cpython/weakrefobject.rs @@ -8,6 +8,8 @@ pub struct _PyWeakReference { pub wr_next: *mut crate::PyWeakReference, #[cfg(Py_3_11)] pub vectorcall: Option, + #[cfg(Py_3_13)] + pub weakrefs_lock: *mut crate::PyMutex, } // skipped _PyWeakref_GetWeakrefCount From 9e9d77e980f599753beb5f5e692dec689340d426 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 6 Aug 2024 15:57:53 -0600 Subject: [PATCH 05/31] error when building with limited api and Py_GIL_DISABLED --- noxfile.py | 8 ++++++++ pyo3-build-config/src/impl_.rs | 18 +++++++++++++++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/noxfile.py b/noxfile.py index 7f012ce2fc5..1db0e187f08 100644 --- a/noxfile.py +++ b/noxfile.py @@ -5,6 +5,7 @@ import shutil import subprocess import sys +import sysconfig import tempfile from functools import lru_cache from glob import glob @@ -32,6 +33,7 @@ PYO3_DOCS_TARGET = PYO3_TARGET / "doc" PY_VERSIONS = ("3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13") PYPY_VERSIONS = ("3.7", "3.8", "3.9", "3.10") +IS_FREE_THREADED = bool(sysconfig.get_config_var("Py_GIL_DISABLED")) @nox.session(venv_backend="none") @@ -783,6 +785,12 @@ def _get_rust_default_target() -> str: def _get_feature_sets() -> Tuple[Tuple[str, ...], ...]: """Returns feature sets to use for clippy job""" cargo_target = os.getenv("CARGO_BUILD_TARGET", "") + if IS_FREE_THREADED: + # abi3 and free-threaded builds are incompatible + return ( + ("--no-default-features",), + ("--features=full multiple-pymethods",), + ) if "wasm32-wasi" not in cargo_target: # multiple-pymethods not supported on wasm return ( diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 73b25cb7c7d..b9ddbf8b082 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -325,6 +325,12 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) .parse() .context("failed to parse calcsize_pointer")?; + let build_flags: BuildFlags = BuildFlags::from_interpreter(interpreter)?; + + if build_flags.0.contains(&BuildFlag::Py_GIL_DISABLED) && abi3 { + bail!("Cannot set Py_LIMITED_API and Py_GIL_DISABLED at the same time") + } + Ok(InterpreterConfig { version, implementation, @@ -334,7 +340,7 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) lib_dir, executable: map.get("executable").cloned(), pointer_width: Some(calcsize_pointer * 8), - build_flags: BuildFlags::from_interpreter(interpreter)?, + build_flags, suppress_build_script_link_lines: false, extra_build_script_lines: vec![], }) @@ -488,6 +494,12 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) } }); + let build_flags: BuildFlags = build_flags.unwrap_or_default(); + + if build_flags.0.contains(&BuildFlag::Py_GIL_DISABLED) && abi3 { + bail!("Cannot set Py_LIMITED_API and Py_GIL_DISABLED at the same time") + } + Ok(InterpreterConfig { implementation, version, @@ -497,7 +509,7 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) lib_dir, executable, pointer_width, - build_flags: build_flags.unwrap_or_default(), + build_flags, suppress_build_script_link_lines: suppress_build_script_link_lines.unwrap_or(false), extra_build_script_lines, }) @@ -2753,7 +2765,7 @@ mod tests { lib_dir: None, executable: None, pointer_width: None, - build_flags: build_flags, + build_flags, suppress_build_script_link_lines: false, extra_build_script_lines: vec![], }; From 79dd1a749f663d02570c9d81aeeb48c62bbf6af3 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 31 Jul 2024 14:50:58 -0600 Subject: [PATCH 06/31] Add CI job for free-threaded build --- .github/workflows/ci.yml | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c8f4b5dcc67..68bf6e42ef0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -489,6 +489,34 @@ jobs: echo PYO3_CONFIG_FILE=$PYO3_CONFIG_FILE >> $GITHUB_ENV - run: python3 -m nox -s test + test-free-threaded: + if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }} + needs: [fmt] + runs-on: ubuntu-latest + env: + UNSAFE_PYO3_BUILD_FREE_THREADED: 1 + steps: + - uses: actions/checkout@v4 + - uses: Swatinem/rust-cache@v2 + with: + save-if: ${{ github.event_name != 'merge_group' }} + - uses: dtolnay/rust-toolchain@stable + with: + components: rust-src + # TODO: replace with setup-python when there is support + - uses: deadsnakes/action@v3.1.0 + with: + python-version: '3.13-dev' + nogil: true + - run: python3 -m sysconfig + - run: python3 -m pip install --upgrade pip && pip install nox + - name: Run nox sessions that should pass + run: nox -s ffi-check clippy docs rustfmt ruff + - name: Run PyO3 tests with free-threaded Python (can fail) + # TODO fix the test crashes so we can unset this + continue-on-error: true + run: nox -s test + test-version-limits: needs: [fmt] if: ${{ contains(github.event.pull_request.labels.*.name, 'CI-build-full') || github.event_name != 'pull_request' }} @@ -627,6 +655,7 @@ jobs: - coverage - emscripten - test-debug + - test-free-threaded - test-version-limits - check-feature-powerset - test-cross-compilation From 5aaa03ae0ebb41bf22bd9db6417aef761d0aad1c Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 6 Aug 2024 16:14:36 -0600 Subject: [PATCH 07/31] fix issues building on older pythons --- pyo3-ffi/src/cpython/mod.rs | 1 + pyo3-ffi/src/object.rs | 4 +++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/pyo3-ffi/src/cpython/mod.rs b/pyo3-ffi/src/cpython/mod.rs index c763439ca6b..8f850104def 100644 --- a/pyo3-ffi/src/cpython/mod.rs +++ b/pyo3-ffi/src/cpython/mod.rs @@ -56,6 +56,7 @@ pub use self::import::*; #[cfg(all(Py_3_8, not(PyPy)))] pub use self::initconfig::*; pub use self::listobject::*; +#[cfg(Py_3_13)] pub use self::lock::*; pub use self::longobject::*; #[cfg(all(Py_3_9, not(PyPy)))] diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 183438076ab..f9fc185f222 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -1,10 +1,12 @@ use crate::pyport::{Py_hash_t, Py_ssize_t}; -#[cfg(not(Py_LIMITED_API))] +#[cfg(all(Py_3_13, not(Py_LIMITED_API)))] use crate::PyMutex; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; use std::ptr; +#[cfg(Py_GIL_DISABLED)] use std::sync::atomic::Ordering::Relaxed; +#[cfg(Py_GIL_DISABLED)] use std::sync::atomic::{AtomicIsize, AtomicU32}; #[cfg(Py_LIMITED_API)] From f4219b319155cdb1409c747c5a37af6f45ad5a2e Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 6 Aug 2024 16:33:34 -0600 Subject: [PATCH 08/31] ci config fixup --- .github/workflows/ci.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 68bf6e42ef0..2f2e093937d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -510,8 +510,9 @@ jobs: nogil: true - run: python3 -m sysconfig - run: python3 -m pip install --upgrade pip && pip install nox - - name: Run nox sessions that should pass - run: nox -s ffi-check clippy docs rustfmt ruff + - run: nox -s ffi-check + - name: Run default nox sessions that should pass + run: nox -s clippy docs rustfmt ruff - name: Run PyO3 tests with free-threaded Python (can fail) # TODO fix the test crashes so we can unset this continue-on-error: true From 4ff9a6275080a0ce11e6213f43ef68481898b1ee Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 6 Aug 2024 16:33:47 -0600 Subject: [PATCH 09/31] fix clippy on gil-enabled 3.13 build --- pyo3-ffi/src/object.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index f9fc185f222..0eb4ec2bcdf 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -1,5 +1,5 @@ use crate::pyport::{Py_hash_t, Py_ssize_t}; -#[cfg(all(Py_3_13, not(Py_LIMITED_API)))] +#[cfg(all(Py_GIL_DISABLED, not(Py_LIMITED_API)))] use crate::PyMutex; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; From 57e7e3d07019f06e60902afdac00f92f339ed16e Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 13 Aug 2024 14:49:18 -0600 Subject: [PATCH 10/31] Apply suggestions from code review Co-authored-by: David Hewitt --- pyo3-ffi/src/cpython/weakrefobject.rs | 2 +- pyo3-ffi/src/object.rs | 6 +----- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/pyo3-ffi/src/cpython/weakrefobject.rs b/pyo3-ffi/src/cpython/weakrefobject.rs index 9413b645091..88bb501bcc5 100644 --- a/pyo3-ffi/src/cpython/weakrefobject.rs +++ b/pyo3-ffi/src/cpython/weakrefobject.rs @@ -8,7 +8,7 @@ pub struct _PyWeakReference { pub wr_next: *mut crate::PyWeakReference, #[cfg(Py_3_11)] pub vectorcall: Option, - #[cfg(Py_3_13)] + #[cfg(all(Py_3_13, Py_GIL_DISABLED))] pub weakrefs_lock: *mut crate::PyMutex, } diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 0eb4ec2bcdf..25329bc11a0 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -5,9 +5,7 @@ use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; use std::ptr; #[cfg(Py_GIL_DISABLED)] -use std::sync::atomic::Ordering::Relaxed; -#[cfg(Py_GIL_DISABLED)] -use std::sync::atomic::{AtomicIsize, AtomicU32}; +use std::sync::atomic::{AtomicIsize, AtomicU32, Ordering::Relaxed}; #[cfg(Py_LIMITED_API)] opaque_struct!(PyTypeObject); @@ -95,8 +93,6 @@ pub struct PyObject { #[cfg(Py_GIL_DISABLED)] pub _padding: u16, #[cfg(Py_GIL_DISABLED)] - // TODO this should be a PyMutex not a u8 - // need to write PyMutex wrappers pub ob_mutex: PyMutex, // per-object lock #[cfg(Py_GIL_DISABLED)] pub ob_gc_bits: u8, // gc-related state From a042e56de4daa7f08870c658961db9ea8144f3e0 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 13 Aug 2024 14:55:43 -0600 Subject: [PATCH 11/31] make PyMutex and PyObject refcounting fields atomics --- pyo3-ffi/src/cpython/lock.rs | 12 ++++++++++-- pyo3-ffi/src/object.rs | 14 +++++++------- 2 files changed, 17 insertions(+), 9 deletions(-) diff --git a/pyo3-ffi/src/cpython/lock.rs b/pyo3-ffi/src/cpython/lock.rs index 3adb16a1ed3..56059919400 100644 --- a/pyo3-ffi/src/cpython/lock.rs +++ b/pyo3-ffi/src/cpython/lock.rs @@ -1,7 +1,15 @@ +use std::fmt; +use std::sync::atomic::AtomicU8; + #[repr(C)] -#[derive(Debug, Copy, Clone)] pub struct PyMutex { - pub _bits: u8, + _bits: AtomicU8, +} + +impl fmt::Debug for PyMutex { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("PyMutex").finish() + } } extern "C" { diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 25329bc11a0..d245f65ab03 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -41,13 +41,13 @@ pub const PyObject_HEAD_INIT: PyObject = PyObject { #[cfg(Py_GIL_DISABLED)] _padding: 0, #[cfg(Py_GIL_DISABLED)] - ob_mutex: PyMutex { _bits: 0 }, + ob_mutex: unsafe { mem::zeroed::() }, #[cfg(Py_GIL_DISABLED)] ob_gc_bits: 0, #[cfg(Py_GIL_DISABLED)] - ob_ref_local: 0, + ob_ref_local: AtomicU32::new(0), #[cfg(Py_GIL_DISABLED)] - ob_ref_shared: 0, + ob_ref_shared: AtomicIsize::new(0), #[cfg(all(not(Py_GIL_DISABLED), Py_3_12))] ob_refcnt: PyObjectObRefcnt { ob_refcnt: 1 }, #[cfg(not(Py_3_12))] @@ -97,9 +97,9 @@ pub struct PyObject { #[cfg(Py_GIL_DISABLED)] pub ob_gc_bits: u8, // gc-related state #[cfg(Py_GIL_DISABLED)] - pub ob_ref_local: u32, // local reference count + pub ob_ref_local: AtomicU32, // local reference count #[cfg(Py_GIL_DISABLED)] - pub ob_ref_shared: Py_ssize_t, // shared reference count + pub ob_ref_shared: AtomicIsize, // shared reference count #[cfg(not(Py_GIL_DISABLED))] pub ob_refcnt: PyObjectObRefcnt, #[cfg(PyPy)] @@ -127,11 +127,11 @@ pub unsafe fn Py_Is(x: *mut PyObject, y: *mut PyObject) -> c_int { #[inline] #[cfg(Py_GIL_DISABLED)] pub unsafe fn Py_REFCNT(ob: *mut PyObject) -> Py_ssize_t { - let local = (AtomicU32::from((*ob).ob_ref_local)).load(Relaxed); + let local = (*ob).ob_ref_local.load(Relaxed); if local == _Py_IMMORTAL_REFCNT_LOCAL { return _Py_IMMORTAL_REFCNT; } - let shared = (AtomicIsize::from((*ob).ob_ref_shared)).load(Relaxed); + let shared = (*ob).ob_ref_shared.load(Relaxed); local as Py_ssize_t + Py_ssize_t::from(shared >> _Py_REF_SHARED_SHIFT) } From 7c493eb297ca776e52981b6e2f311917fe492038 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 13 Aug 2024 15:07:56 -0600 Subject: [PATCH 12/31] add new field on PyConfig in 3.13 debug ABI --- pyo3-ffi/src/cpython/initconfig.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyo3-ffi/src/cpython/initconfig.rs b/pyo3-ffi/src/cpython/initconfig.rs index ab03ca79d61..321d200e141 100644 --- a/pyo3-ffi/src/cpython/initconfig.rs +++ b/pyo3-ffi/src/cpython/initconfig.rs @@ -179,6 +179,8 @@ pub struct PyConfig { pub _is_python_build: c_int, #[cfg(all(Py_3_9, not(Py_3_10)))] pub _orig_argv: PyWideStringList, + #[cfg(all(Py_3_13, py_sys_config = "Py_DEBUG"))] + pub run_presite: *mut wchar_t, } extern "C" { From da3e50cac4bf6778bda2239407aa1e6fe08f5ae5 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 13 Aug 2024 16:46:11 -0600 Subject: [PATCH 13/31] warn and disable abi3 on gil-disabled build --- noxfile.py | 8 -------- pyo3-build-config/src/impl_.rs | 11 ++--------- pyo3-ffi/build.rs | 5 +++++ 3 files changed, 7 insertions(+), 17 deletions(-) diff --git a/noxfile.py b/noxfile.py index 1db0e187f08..7f012ce2fc5 100644 --- a/noxfile.py +++ b/noxfile.py @@ -5,7 +5,6 @@ import shutil import subprocess import sys -import sysconfig import tempfile from functools import lru_cache from glob import glob @@ -33,7 +32,6 @@ PYO3_DOCS_TARGET = PYO3_TARGET / "doc" PY_VERSIONS = ("3.7", "3.8", "3.9", "3.10", "3.11", "3.12", "3.13") PYPY_VERSIONS = ("3.7", "3.8", "3.9", "3.10") -IS_FREE_THREADED = bool(sysconfig.get_config_var("Py_GIL_DISABLED")) @nox.session(venv_backend="none") @@ -785,12 +783,6 @@ def _get_rust_default_target() -> str: def _get_feature_sets() -> Tuple[Tuple[str, ...], ...]: """Returns feature sets to use for clippy job""" cargo_target = os.getenv("CARGO_BUILD_TARGET", "") - if IS_FREE_THREADED: - # abi3 and free-threaded builds are incompatible - return ( - ("--no-default-features",), - ("--features=full multiple-pymethods",), - ) if "wasm32-wasi" not in cargo_target: # multiple-pymethods not supported on wasm return ( diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index b9ddbf8b082..ff08635e7f1 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -177,7 +177,8 @@ impl InterpreterConfig { PythonImplementation::GraalPy => out.push("cargo:rustc-cfg=GraalPy".to_owned()), } - if self.abi3 { + // If Py_GIL_DISABLED is set, do not build with limited API support + if self.abi3 && !self.build_flags.0.contains(&BuildFlag::Py_GIL_DISABLED) { out.push("cargo:rustc-cfg=Py_LIMITED_API".to_owned()); } @@ -327,10 +328,6 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) let build_flags: BuildFlags = BuildFlags::from_interpreter(interpreter)?; - if build_flags.0.contains(&BuildFlag::Py_GIL_DISABLED) && abi3 { - bail!("Cannot set Py_LIMITED_API and Py_GIL_DISABLED at the same time") - } - Ok(InterpreterConfig { version, implementation, @@ -496,10 +493,6 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) let build_flags: BuildFlags = build_flags.unwrap_or_default(); - if build_flags.0.contains(&BuildFlag::Py_GIL_DISABLED) && abi3 { - bail!("Cannot set Py_LIMITED_API and Py_GIL_DISABLED at the same time") - } - Ok(InterpreterConfig { implementation, version, diff --git a/pyo3-ffi/build.rs b/pyo3-ffi/build.rs index 83408b31222..8b3a98bf9f7 100644 --- a/pyo3-ffi/build.rs +++ b/pyo3-ffi/build.rs @@ -135,6 +135,11 @@ fn ensure_gil_enabled(interpreter_config: &InterpreterConfig) -> Result<()> { = help: set UNSAFE_PYO3_BUILD_FREE_THREADED=1 to suppress this check and build anyway for free-threaded Python", std::env::var("CARGO_PKG_VERSION").unwrap() ); + if interpreter_config.abi3 { + warn!( + "The free-threaded build of CPython does not yet support abi3 so the build artifacts will be version-specific." + ) + } Ok(()) } From 77b4d96db9cb678fbfe5c4bc0ce1a4104813c862 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 13 Aug 2024 16:47:27 -0600 Subject: [PATCH 14/31] fix conditional compilation for PyMutex usage --- pyo3-ffi/src/object.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index d245f65ab03..64d16760669 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -1,5 +1,5 @@ use crate::pyport::{Py_hash_t, Py_ssize_t}; -#[cfg(all(Py_GIL_DISABLED, not(Py_LIMITED_API)))] +#[cfg(not(Py_LIMITED_API))] use crate::PyMutex; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; From 96dd13eba1bf3f07201c75c08730f4daa37b4c1c Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 13 Aug 2024 16:48:18 -0600 Subject: [PATCH 15/31] temporarily skip test that deadlocks --- tests/test_dict_iter.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/test_dict_iter.rs b/tests/test_dict_iter.rs index dc32eb61fd7..5b3573d10ad 100644 --- a/tests/test_dict_iter.rs +++ b/tests/test_dict_iter.rs @@ -3,6 +3,7 @@ use pyo3::types::IntoPyDict; #[test] #[cfg_attr(target_arch = "wasm32", ignore)] // Not sure why this fails. +#[cfg_attr(Py_GIL_DISABLED, ignore)] // test deadlocks in GIL-disabled build, TODO: fix deadlock fn iter_dict_nosegv() { Python::with_gil(|py| { const LEN: usize = 10_000_000; From dbcb9d29d22d071f435f267995b3a12ae72f4648 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 13 Aug 2024 16:54:54 -0600 Subject: [PATCH 16/31] remove Py_GIL_DISABLED from py_sys_config cfg options --- pyo3-build-config/src/impl_.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index ff08635e7f1..1eaec754da4 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -187,7 +187,9 @@ impl InterpreterConfig { } for flag in &self.build_flags.0 { - out.push(format!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag)); + if flag != &BuildFlag::Py_GIL_DISABLED { + out.push(format!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag)); + } } out @@ -2775,7 +2777,6 @@ mod tests { "cargo:rustc-cfg=Py_3_12".to_owned(), "cargo:rustc-cfg=Py_3_13".to_owned(), "cargo:rustc-cfg=Py_GIL_DISABLED".to_owned(), - "cargo:rustc-cfg=py_sys_config=\"Py_GIL_DISABLED\"".to_owned(), ] ); } From d9dac3c243e4ec286f46e116844c1d9d72dbe8fc Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Tue, 13 Aug 2024 16:57:55 -0600 Subject: [PATCH 17/31] only expose PyMutex in 3.13 --- pyo3-ffi/src/object.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 64d16760669..dd2b3832068 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -1,5 +1,5 @@ use crate::pyport::{Py_hash_t, Py_ssize_t}; -#[cfg(not(Py_LIMITED_API))] +#[cfg(all(Py_3_13, not(Py_LIMITED_API)))] use crate::PyMutex; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; From 9b70b077f3fa3b6c2dd2ea9023d9ffd7da2cc33b Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 13:34:04 -0600 Subject: [PATCH 18/31] make PyObject_HEAD_INIT a function --- examples/sequential/src/module.rs | 2 +- examples/string-sum/src/lib.rs | 2 +- pyo3-ffi/README.md | 2 +- pyo3-ffi/src/lib.rs | 2 +- pyo3-ffi/src/moduleobject.rs | 14 ++++---- pyo3-ffi/src/object.rs | 54 ++++++++++++++++--------------- src/impl_/pymodule.rs | 2 +- 7 files changed, 41 insertions(+), 37 deletions(-) diff --git a/examples/sequential/src/module.rs b/examples/sequential/src/module.rs index 5e71f07a865..604bfe393c5 100644 --- a/examples/sequential/src/module.rs +++ b/examples/sequential/src/module.rs @@ -3,7 +3,7 @@ use pyo3_ffi::*; use std::os::raw::{c_int, c_void}; pub static mut MODULE_DEF: PyModuleDef = PyModuleDef { - m_base: PyModuleDef_HEAD_INIT, + m_base: PyModuleDef_HEAD_INIT(), m_name: c_str!("sequential").as_ptr(), m_doc: c_str!("A library for generating sequential ids, written in Rust.").as_ptr(), m_size: mem::size_of::() as Py_ssize_t, diff --git a/examples/string-sum/src/lib.rs b/examples/string-sum/src/lib.rs index ce71ab38f87..8929d788caf 100644 --- a/examples/string-sum/src/lib.rs +++ b/examples/string-sum/src/lib.rs @@ -4,7 +4,7 @@ use std::ptr; use pyo3_ffi::*; static mut MODULE_DEF: PyModuleDef = PyModuleDef { - m_base: PyModuleDef_HEAD_INIT, + m_base: PyModuleDef_HEAD_INIT(), m_name: c_str!("string_sum").as_ptr(), m_doc: c_str!("A Python module written in Rust.").as_ptr(), m_size: 0, diff --git a/pyo3-ffi/README.md b/pyo3-ffi/README.md index 200c78cec14..2f433c62435 100644 --- a/pyo3-ffi/README.md +++ b/pyo3-ffi/README.md @@ -50,7 +50,7 @@ use std::ptr; use pyo3_ffi::*; static mut MODULE_DEF: PyModuleDef = PyModuleDef { - m_base: PyModuleDef_HEAD_INIT, + m_base: PyModuleDef_HEAD_INIT(), m_name: c_str!("string_sum").as_ptr(), m_doc: c_str!("A Python module written in Rust.").as_ptr(), m_size: 0, diff --git a/pyo3-ffi/src/lib.rs b/pyo3-ffi/src/lib.rs index 55c7f31404f..fbc17878211 100644 --- a/pyo3-ffi/src/lib.rs +++ b/pyo3-ffi/src/lib.rs @@ -88,7 +88,7 @@ //! use pyo3_ffi::*; //! //! static mut MODULE_DEF: PyModuleDef = PyModuleDef { -//! m_base: PyModuleDef_HEAD_INIT, +//! m_base: PyModuleDef_HEAD_INIT(), //! m_name: c_str!("string_sum").as_ptr(), //! m_doc: c_str!("A Python module written in Rust.").as_ptr(), //! m_size: 0, diff --git a/pyo3-ffi/src/moduleobject.rs b/pyo3-ffi/src/moduleobject.rs index b9026997d2e..bf04da660cf 100644 --- a/pyo3-ffi/src/moduleobject.rs +++ b/pyo3-ffi/src/moduleobject.rs @@ -59,12 +59,14 @@ pub struct PyModuleDef_Base { pub m_copy: *mut PyObject, } -pub const PyModuleDef_HEAD_INIT: PyModuleDef_Base = PyModuleDef_Base { - ob_base: PyObject_HEAD_INIT, - m_init: None, - m_index: 0, - m_copy: std::ptr::null_mut(), -}; +pub const fn PyModuleDef_HEAD_INIT() -> PyModuleDef_Base { + PyModuleDef_Base { + ob_base: PyObject_HEAD_INIT(), + m_init: None, + m_index: 0, + m_copy: std::ptr::null_mut(), + } +} #[repr(C)] #[derive(Copy, Clone, Eq, PartialEq)] diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index dd2b3832068..f193274664c 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -1,5 +1,5 @@ use crate::pyport::{Py_hash_t, Py_ssize_t}; -#[cfg(all(Py_3_13, not(Py_LIMITED_API)))] +#[cfg(Py_GIL_DISABLED)] use crate::PyMutex; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; @@ -31,31 +31,33 @@ pub const _Py_IMMORTAL_REFCNT_LOCAL: u32 = u32::MAX; #[cfg(Py_GIL_DISABLED)] pub const _Py_REF_SHARED_SHIFT: isize = 2; -pub const PyObject_HEAD_INIT: PyObject = PyObject { - #[cfg(py_sys_config = "Py_TRACE_REFS")] - _ob_next: std::ptr::null_mut(), - #[cfg(py_sys_config = "Py_TRACE_REFS")] - _ob_prev: std::ptr::null_mut(), - #[cfg(Py_GIL_DISABLED)] - ob_tid: 0, - #[cfg(Py_GIL_DISABLED)] - _padding: 0, - #[cfg(Py_GIL_DISABLED)] - ob_mutex: unsafe { mem::zeroed::() }, - #[cfg(Py_GIL_DISABLED)] - ob_gc_bits: 0, - #[cfg(Py_GIL_DISABLED)] - ob_ref_local: AtomicU32::new(0), - #[cfg(Py_GIL_DISABLED)] - ob_ref_shared: AtomicIsize::new(0), - #[cfg(all(not(Py_GIL_DISABLED), Py_3_12))] - ob_refcnt: PyObjectObRefcnt { ob_refcnt: 1 }, - #[cfg(not(Py_3_12))] - ob_refcnt: 1, - #[cfg(PyPy)] - ob_pypy_link: 0, - ob_type: std::ptr::null_mut(), -}; +pub const fn PyObject_HEAD_INIT() -> PyObject { + PyObject { + #[cfg(py_sys_config = "Py_TRACE_REFS")] + _ob_next: std::ptr::null_mut(), + #[cfg(py_sys_config = "Py_TRACE_REFS")] + _ob_prev: std::ptr::null_mut(), + #[cfg(Py_GIL_DISABLED)] + ob_tid: 0, + #[cfg(Py_GIL_DISABLED)] + _padding: 0, + #[cfg(Py_GIL_DISABLED)] + ob_mutex: unsafe { mem::zeroed::() }, + #[cfg(Py_GIL_DISABLED)] + ob_gc_bits: 0, + #[cfg(Py_GIL_DISABLED)] + ob_ref_local: AtomicU32::new(0), + #[cfg(Py_GIL_DISABLED)] + ob_ref_shared: AtomicIsize::new(0), + #[cfg(all(not(Py_GIL_DISABLED), Py_3_12))] + ob_refcnt: PyObjectObRefcnt { ob_refcnt: 1 }, + #[cfg(not(Py_3_12))] + ob_refcnt: 1, + #[cfg(PyPy)] + ob_pypy_link: 0, + ob_type: std::ptr::null_mut(), + } +} // skipped PyObject_VAR_HEAD // skipped Py_INVALID_SIZE diff --git a/src/impl_/pymodule.rs b/src/impl_/pymodule.rs index 08d55bfa5e8..52bef0f0497 100644 --- a/src/impl_/pymodule.rs +++ b/src/impl_/pymodule.rs @@ -55,7 +55,7 @@ impl ModuleDef { initializer: ModuleInitializer, ) -> Self { const INIT: ffi::PyModuleDef = ffi::PyModuleDef { - m_base: ffi::PyModuleDef_HEAD_INIT, + m_base: ffi::PyModuleDef_HEAD_INIT(), m_name: std::ptr::null(), m_doc: std::ptr::null(), m_size: 0, From 3e03dd169131b48383e3f32b98073f5caf3ecb4c Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 13:46:26 -0600 Subject: [PATCH 19/31] intialize ob_ref_local to _Py_IMMORTAL_REFCNT_LOCAL in HEAD_INIT --- pyo3-ffi/src/object.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index f193274664c..f7be0d7139b 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -46,7 +46,7 @@ pub const fn PyObject_HEAD_INIT() -> PyObject { #[cfg(Py_GIL_DISABLED)] ob_gc_bits: 0, #[cfg(Py_GIL_DISABLED)] - ob_ref_local: AtomicU32::new(0), + ob_ref_local: AtomicU32::new(_Py_IMMORTAL_REFCNT_LOCAL), #[cfg(Py_GIL_DISABLED)] ob_ref_shared: AtomicIsize::new(0), #[cfg(all(not(Py_GIL_DISABLED), Py_3_12))] From f6952033f8ee1da1cab6cb935fdf9a4dae728eb3 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 13:46:43 -0600 Subject: [PATCH 20/31] Fix clippy lint about static with interior mutability --- src/impl_/pymodule.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/impl_/pymodule.rs b/src/impl_/pymodule.rs index 52bef0f0497..a2325dc07fb 100644 --- a/src/impl_/pymodule.rs +++ b/src/impl_/pymodule.rs @@ -54,7 +54,7 @@ impl ModuleDef { doc: &'static CStr, initializer: ModuleInitializer, ) -> Self { - const INIT: ffi::PyModuleDef = ffi::PyModuleDef { + let init = ffi::PyModuleDef { m_base: ffi::PyModuleDef_HEAD_INIT(), m_name: std::ptr::null(), m_doc: std::ptr::null(), @@ -69,7 +69,7 @@ impl ModuleDef { let ffi_def = UnsafeCell::new(ffi::PyModuleDef { m_name: name.as_ptr(), m_doc: doc.as_ptr(), - ..INIT + ..init }); ModuleDef { From 848c7934f4a455891f9803787553c948130e5475 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 13:53:49 -0600 Subject: [PATCH 21/31] add TODO comments about INCREF and DECREF in free-threaded build --- pyo3-ffi/src/object.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index f7be0d7139b..9baebb8a51f 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -556,6 +556,7 @@ extern "C" { #[inline(always)] pub unsafe fn Py_INCREF(op: *mut PyObject) { // On limited API, the free-threaded build, or with refcount debugging, let the interpreter do refcounting + // TODO: reimplement the logic in the header in the free-threaded build, for a little bit of performance. #[cfg(any( Py_GIL_DISABLED, Py_LIMITED_API, @@ -619,6 +620,7 @@ pub unsafe fn Py_INCREF(op: *mut PyObject) { pub unsafe fn Py_DECREF(op: *mut PyObject) { // On limited API, the free-threaded build, or with refcount debugging, let the interpreter do refcounting // On 3.12+ we implement refcount debugging to get better assertion locations on negative refcounts + // TODO: reimplement the logic in the header in the free-threaded build, for a little bit of performance. #[cfg(any( Py_GIL_DISABLED, Py_LIMITED_API, From 6e66cb0e5297fbc1327abc03df2384780f9d2974 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 14:11:27 -0600 Subject: [PATCH 22/31] make the _bits field of PyMutex pub(crate) --- pyo3-ffi/src/cpython/lock.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyo3-ffi/src/cpython/lock.rs b/pyo3-ffi/src/cpython/lock.rs index 56059919400..58ffdb34223 100644 --- a/pyo3-ffi/src/cpython/lock.rs +++ b/pyo3-ffi/src/cpython/lock.rs @@ -3,7 +3,7 @@ use std::sync::atomic::AtomicU8; #[repr(C)] pub struct PyMutex { - _bits: AtomicU8, + pub(crate) _bits: AtomicU8, } impl fmt::Debug for PyMutex { From 126c97ba002f44609c83503265a698bcbf710d91 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 14:11:46 -0600 Subject: [PATCH 23/31] refactor so HEAD_INIT remains a constant --- examples/sequential/src/module.rs | 2 +- examples/string-sum/src/lib.rs | 2 +- pyo3-ffi/README.md | 2 +- pyo3-ffi/src/lib.rs | 2 +- pyo3-ffi/src/moduleobject.rs | 14 ++++---- pyo3-ffi/src/object.rs | 56 +++++++++++++++---------------- src/impl_/pymodule.rs | 6 ++-- 7 files changed, 41 insertions(+), 43 deletions(-) diff --git a/examples/sequential/src/module.rs b/examples/sequential/src/module.rs index 604bfe393c5..5e71f07a865 100644 --- a/examples/sequential/src/module.rs +++ b/examples/sequential/src/module.rs @@ -3,7 +3,7 @@ use pyo3_ffi::*; use std::os::raw::{c_int, c_void}; pub static mut MODULE_DEF: PyModuleDef = PyModuleDef { - m_base: PyModuleDef_HEAD_INIT(), + m_base: PyModuleDef_HEAD_INIT, m_name: c_str!("sequential").as_ptr(), m_doc: c_str!("A library for generating sequential ids, written in Rust.").as_ptr(), m_size: mem::size_of::() as Py_ssize_t, diff --git a/examples/string-sum/src/lib.rs b/examples/string-sum/src/lib.rs index 8929d788caf..ce71ab38f87 100644 --- a/examples/string-sum/src/lib.rs +++ b/examples/string-sum/src/lib.rs @@ -4,7 +4,7 @@ use std::ptr; use pyo3_ffi::*; static mut MODULE_DEF: PyModuleDef = PyModuleDef { - m_base: PyModuleDef_HEAD_INIT(), + m_base: PyModuleDef_HEAD_INIT, m_name: c_str!("string_sum").as_ptr(), m_doc: c_str!("A Python module written in Rust.").as_ptr(), m_size: 0, diff --git a/pyo3-ffi/README.md b/pyo3-ffi/README.md index 2f433c62435..200c78cec14 100644 --- a/pyo3-ffi/README.md +++ b/pyo3-ffi/README.md @@ -50,7 +50,7 @@ use std::ptr; use pyo3_ffi::*; static mut MODULE_DEF: PyModuleDef = PyModuleDef { - m_base: PyModuleDef_HEAD_INIT(), + m_base: PyModuleDef_HEAD_INIT, m_name: c_str!("string_sum").as_ptr(), m_doc: c_str!("A Python module written in Rust.").as_ptr(), m_size: 0, diff --git a/pyo3-ffi/src/lib.rs b/pyo3-ffi/src/lib.rs index fbc17878211..55c7f31404f 100644 --- a/pyo3-ffi/src/lib.rs +++ b/pyo3-ffi/src/lib.rs @@ -88,7 +88,7 @@ //! use pyo3_ffi::*; //! //! static mut MODULE_DEF: PyModuleDef = PyModuleDef { -//! m_base: PyModuleDef_HEAD_INIT(), +//! m_base: PyModuleDef_HEAD_INIT, //! m_name: c_str!("string_sum").as_ptr(), //! m_doc: c_str!("A Python module written in Rust.").as_ptr(), //! m_size: 0, diff --git a/pyo3-ffi/src/moduleobject.rs b/pyo3-ffi/src/moduleobject.rs index bf04da660cf..b9026997d2e 100644 --- a/pyo3-ffi/src/moduleobject.rs +++ b/pyo3-ffi/src/moduleobject.rs @@ -59,14 +59,12 @@ pub struct PyModuleDef_Base { pub m_copy: *mut PyObject, } -pub const fn PyModuleDef_HEAD_INIT() -> PyModuleDef_Base { - PyModuleDef_Base { - ob_base: PyObject_HEAD_INIT(), - m_init: None, - m_index: 0, - m_copy: std::ptr::null_mut(), - } -} +pub const PyModuleDef_HEAD_INIT: PyModuleDef_Base = PyModuleDef_Base { + ob_base: PyObject_HEAD_INIT, + m_init: None, + m_index: 0, + m_copy: std::ptr::null_mut(), +}; #[repr(C)] #[derive(Copy, Clone, Eq, PartialEq)] diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 9baebb8a51f..48aa1f31861 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -5,7 +5,7 @@ use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; use std::ptr; #[cfg(Py_GIL_DISABLED)] -use std::sync::atomic::{AtomicIsize, AtomicU32, Ordering::Relaxed}; +use std::sync::atomic::{AtomicIsize, AtomicU32, AtomicU8, Ordering::Relaxed}; #[cfg(Py_LIMITED_API)] opaque_struct!(PyTypeObject); @@ -31,33 +31,33 @@ pub const _Py_IMMORTAL_REFCNT_LOCAL: u32 = u32::MAX; #[cfg(Py_GIL_DISABLED)] pub const _Py_REF_SHARED_SHIFT: isize = 2; -pub const fn PyObject_HEAD_INIT() -> PyObject { - PyObject { - #[cfg(py_sys_config = "Py_TRACE_REFS")] - _ob_next: std::ptr::null_mut(), - #[cfg(py_sys_config = "Py_TRACE_REFS")] - _ob_prev: std::ptr::null_mut(), - #[cfg(Py_GIL_DISABLED)] - ob_tid: 0, - #[cfg(Py_GIL_DISABLED)] - _padding: 0, - #[cfg(Py_GIL_DISABLED)] - ob_mutex: unsafe { mem::zeroed::() }, - #[cfg(Py_GIL_DISABLED)] - ob_gc_bits: 0, - #[cfg(Py_GIL_DISABLED)] - ob_ref_local: AtomicU32::new(_Py_IMMORTAL_REFCNT_LOCAL), - #[cfg(Py_GIL_DISABLED)] - ob_ref_shared: AtomicIsize::new(0), - #[cfg(all(not(Py_GIL_DISABLED), Py_3_12))] - ob_refcnt: PyObjectObRefcnt { ob_refcnt: 1 }, - #[cfg(not(Py_3_12))] - ob_refcnt: 1, - #[cfg(PyPy)] - ob_pypy_link: 0, - ob_type: std::ptr::null_mut(), - } -} +pub const PyObject_HEAD_INIT: PyObject = PyObject { + #[cfg(py_sys_config = "Py_TRACE_REFS")] + _ob_next: std::ptr::null_mut(), + #[cfg(py_sys_config = "Py_TRACE_REFS")] + _ob_prev: std::ptr::null_mut(), + #[cfg(Py_GIL_DISABLED)] + ob_tid: 0, + #[cfg(Py_GIL_DISABLED)] + _padding: 0, + #[cfg(Py_GIL_DISABLED)] + ob_mutex: PyMutex { + _bits: AtomicU8::new(0), + }, + #[cfg(Py_GIL_DISABLED)] + ob_gc_bits: 0, + #[cfg(Py_GIL_DISABLED)] + ob_ref_local: AtomicU32::new(_Py_IMMORTAL_REFCNT_LOCAL), + #[cfg(Py_GIL_DISABLED)] + ob_ref_shared: AtomicIsize::new(0), + #[cfg(all(not(Py_GIL_DISABLED), Py_3_12))] + ob_refcnt: PyObjectObRefcnt { ob_refcnt: 1 }, + #[cfg(not(Py_3_12))] + ob_refcnt: 1, + #[cfg(PyPy)] + ob_pypy_link: 0, + ob_type: std::ptr::null_mut(), +}; // skipped PyObject_VAR_HEAD // skipped Py_INVALID_SIZE diff --git a/src/impl_/pymodule.rs b/src/impl_/pymodule.rs index a2325dc07fb..08d55bfa5e8 100644 --- a/src/impl_/pymodule.rs +++ b/src/impl_/pymodule.rs @@ -54,8 +54,8 @@ impl ModuleDef { doc: &'static CStr, initializer: ModuleInitializer, ) -> Self { - let init = ffi::PyModuleDef { - m_base: ffi::PyModuleDef_HEAD_INIT(), + const INIT: ffi::PyModuleDef = ffi::PyModuleDef { + m_base: ffi::PyModuleDef_HEAD_INIT, m_name: std::ptr::null(), m_doc: std::ptr::null(), m_size: 0, @@ -69,7 +69,7 @@ impl ModuleDef { let ffi_def = UnsafeCell::new(ffi::PyModuleDef { m_name: name.as_ptr(), m_doc: doc.as_ptr(), - ..init + ..INIT }); ModuleDef { From 162a65ece84275afc4de7510211d9f321115eb2c Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 15:06:33 -0600 Subject: [PATCH 24/31] ignore clippy lint about interior mutability --- pyo3-ffi/src/moduleobject.rs | 1 + pyo3-ffi/src/object.rs | 1 + src/impl_/pymodule.rs | 1 + 3 files changed, 3 insertions(+) diff --git a/pyo3-ffi/src/moduleobject.rs b/pyo3-ffi/src/moduleobject.rs index b9026997d2e..64b3a37d038 100644 --- a/pyo3-ffi/src/moduleobject.rs +++ b/pyo3-ffi/src/moduleobject.rs @@ -59,6 +59,7 @@ pub struct PyModuleDef_Base { pub m_copy: *mut PyObject, } +#[allow(clippy::declare_interior_mutable_const)] pub const PyModuleDef_HEAD_INIT: PyModuleDef_Base = PyModuleDef_Base { ob_base: PyObject_HEAD_INIT, m_init: None, diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 48aa1f31861..3f71c5f324f 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -31,6 +31,7 @@ pub const _Py_IMMORTAL_REFCNT_LOCAL: u32 = u32::MAX; #[cfg(Py_GIL_DISABLED)] pub const _Py_REF_SHARED_SHIFT: isize = 2; +#[allow(clippy::declare_interior_mutable_const)] pub const PyObject_HEAD_INIT: PyObject = PyObject { #[cfg(py_sys_config = "Py_TRACE_REFS")] _ob_next: std::ptr::null_mut(), diff --git a/src/impl_/pymodule.rs b/src/impl_/pymodule.rs index 08d55bfa5e8..9cca48f5594 100644 --- a/src/impl_/pymodule.rs +++ b/src/impl_/pymodule.rs @@ -54,6 +54,7 @@ impl ModuleDef { doc: &'static CStr, initializer: ModuleInitializer, ) -> Self { + #[allow(clippy::declare_interior_mutable_const)] const INIT: ffi::PyModuleDef = ffi::PyModuleDef { m_base: ffi::PyModuleDef_HEAD_INIT, m_name: std::ptr::null(), From 6103d2628175bdc2d5a8a433e7ed0f316615967a Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 16:37:27 -0600 Subject: [PATCH 25/31] revert unnecessary changes to pyo3-build-config --- pyo3-build-config/src/impl_.rs | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 1eaec754da4..10ed63ea495 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -328,8 +328,6 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) .parse() .context("failed to parse calcsize_pointer")?; - let build_flags: BuildFlags = BuildFlags::from_interpreter(interpreter)?; - Ok(InterpreterConfig { version, implementation, @@ -339,7 +337,7 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) lib_dir, executable: map.get("executable").cloned(), pointer_width: Some(calcsize_pointer * 8), - build_flags, + build_flags: BuildFlags::from_interpreter(interpreter)?, suppress_build_script_link_lines: false, extra_build_script_lines: vec![], }) @@ -493,8 +491,6 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) } }); - let build_flags: BuildFlags = build_flags.unwrap_or_default(); - Ok(InterpreterConfig { implementation, version, @@ -504,7 +500,7 @@ print("ext_suffix", get_config_var("EXT_SUFFIX")) lib_dir, executable, pointer_width, - build_flags, + build_flags: build_flags.unwrap_or_default(), suppress_build_script_link_lines: suppress_build_script_link_lines.unwrap_or(false), extra_build_script_lines, }) From 8a9ef2d3cc92bfc2b699a07690abbb00944858a8 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Wed, 14 Aug 2024 16:39:04 -0600 Subject: [PATCH 26/31] add changelog entries --- newsfragments/4421.added.md | 1 + newsfragments/4421.fixed.md | 1 + 2 files changed, 2 insertions(+) create mode 100644 newsfragments/4421.added.md create mode 100644 newsfragments/4421.fixed.md diff --git a/newsfragments/4421.added.md b/newsfragments/4421.added.md new file mode 100644 index 00000000000..b0a85bea3ca --- /dev/null +++ b/newsfragments/4421.added.md @@ -0,0 +1 @@ +* Added bindings for PyMutex. diff --git a/newsfragments/4421.fixed.md b/newsfragments/4421.fixed.md new file mode 100644 index 00000000000..075b1fa7b5a --- /dev/null +++ b/newsfragments/4421.fixed.md @@ -0,0 +1 @@ +* Updated FFI bindings for free-threaded CPython 3.13 ABI From e1ddd017ffaf57158d34d71e3ba514929a57ccfa Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Thu, 15 Aug 2024 11:27:24 -0600 Subject: [PATCH 27/31] use derive(Debug) for PyMutex --- pyo3-ffi/src/cpython/lock.rs | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/pyo3-ffi/src/cpython/lock.rs b/pyo3-ffi/src/cpython/lock.rs index 58ffdb34223..ba210ef4a89 100644 --- a/pyo3-ffi/src/cpython/lock.rs +++ b/pyo3-ffi/src/cpython/lock.rs @@ -1,17 +1,11 @@ -use std::fmt; use std::sync::atomic::AtomicU8; #[repr(C)] +#[derive(Debug)] pub struct PyMutex { pub(crate) _bits: AtomicU8, } -impl fmt::Debug for PyMutex { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("PyMutex").finish() - } -} - extern "C" { pub fn PyMutex_Lock(m: *mut PyMutex); pub fn PyMutex_UnLock(m: *mut PyMutex); From 1a088eabdd95e967afd1fca50ff6644901c7b93b Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Thu, 15 Aug 2024 11:31:57 -0600 Subject: [PATCH 28/31] Add PhantomPinned field to PyMutex bindings --- pyo3-ffi/src/cpython/lock.rs | 4 +++- pyo3-ffi/src/object.rs | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/pyo3-ffi/src/cpython/lock.rs b/pyo3-ffi/src/cpython/lock.rs index ba210ef4a89..05778dfe573 100644 --- a/pyo3-ffi/src/cpython/lock.rs +++ b/pyo3-ffi/src/cpython/lock.rs @@ -1,9 +1,11 @@ +use std::marker::PhantomPinned; use std::sync::atomic::AtomicU8; -#[repr(C)] +#[repr(transparent)] #[derive(Debug)] pub struct PyMutex { pub(crate) _bits: AtomicU8, + pub(crate) _pin: PhantomPinned, } extern "C" { diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index 3f71c5f324f..a37655c867f 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -1,6 +1,8 @@ use crate::pyport::{Py_hash_t, Py_ssize_t}; #[cfg(Py_GIL_DISABLED)] use crate::PyMutex; +#[cfg(Py_GIL_DISABLED)] +use std::marker::PhantomPinned; use std::mem; use std::os::raw::{c_char, c_int, c_uint, c_ulong, c_void}; use std::ptr; @@ -44,6 +46,7 @@ pub const PyObject_HEAD_INIT: PyObject = PyObject { #[cfg(Py_GIL_DISABLED)] ob_mutex: PyMutex { _bits: AtomicU8::new(0), + _pin: PhantomPinned, }, #[cfg(Py_GIL_DISABLED)] ob_gc_bits: 0, From 38bc4927d5325167dcf725220e94a29729ee3d97 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Thu, 15 Aug 2024 15:20:57 -0600 Subject: [PATCH 29/31] Update pyo3-build-config/src/impl_.rs Co-authored-by: David Hewitt --- pyo3-build-config/src/impl_.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index 10ed63ea495..c354c7e6a7c 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -187,8 +187,9 @@ impl InterpreterConfig { } for flag in &self.build_flags.0 { - if flag != &BuildFlag::Py_GIL_DISABLED { - out.push(format!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag)); + match flag { + BuildFlag::Py_GIL_DISABLED => out.push("cargo:rustc-cfg=Py_GIL_DISABLED".to_owned()); + flag => out.push(format!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag)); } } From a85fa4c28263a31edc40b1f002a20e41cdadce10 Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Thu, 15 Aug 2024 15:21:09 -0600 Subject: [PATCH 30/31] Update pyo3-ffi/src/object.rs Co-authored-by: David Hewitt --- pyo3-ffi/src/object.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyo3-ffi/src/object.rs b/pyo3-ffi/src/object.rs index a37655c867f..27436c208a9 100644 --- a/pyo3-ffi/src/object.rs +++ b/pyo3-ffi/src/object.rs @@ -95,7 +95,7 @@ pub struct PyObject { #[cfg(py_sys_config = "Py_TRACE_REFS")] pub _ob_prev: *mut PyObject, #[cfg(Py_GIL_DISABLED)] - pub ob_tid: usize, + pub ob_tid: libc::uintptr_t, #[cfg(Py_GIL_DISABLED)] pub _padding: u16, #[cfg(Py_GIL_DISABLED)] From 60c26c4716a10e38dde4491987e4d7a7d1bc704d Mon Sep 17 00:00:00 2001 From: Nathan Goldbaum Date: Thu, 15 Aug 2024 15:26:14 -0600 Subject: [PATCH 31/31] fix build config again --- pyo3-build-config/src/impl_.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pyo3-build-config/src/impl_.rs b/pyo3-build-config/src/impl_.rs index c354c7e6a7c..c8f68864727 100644 --- a/pyo3-build-config/src/impl_.rs +++ b/pyo3-build-config/src/impl_.rs @@ -182,14 +182,12 @@ impl InterpreterConfig { out.push("cargo:rustc-cfg=Py_LIMITED_API".to_owned()); } - if self.build_flags.0.contains(&BuildFlag::Py_GIL_DISABLED) { - out.push("cargo:rustc-cfg=Py_GIL_DISABLED".to_owned()); - } - for flag in &self.build_flags.0 { match flag { - BuildFlag::Py_GIL_DISABLED => out.push("cargo:rustc-cfg=Py_GIL_DISABLED".to_owned()); - flag => out.push(format!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag)); + BuildFlag::Py_GIL_DISABLED => { + out.push("cargo:rustc-cfg=Py_GIL_DISABLED".to_owned()) + } + flag => out.push(format!("cargo:rustc-cfg=py_sys_config=\"{}\"", flag)), } }