diff --git a/newsfragments/4872.added.md b/newsfragments/4872.added.md new file mode 100644 index 00000000000..71f37f8a207 --- /dev/null +++ b/newsfragments/4872.added.md @@ -0,0 +1 @@ +Add FFI definitions from `pythread.h`. diff --git a/pyo3-ffi/src/cpython/mod.rs b/pyo3-ffi/src/cpython/mod.rs index fe909f0ceeb..33a67fcd41d 100644 --- a/pyo3-ffi/src/cpython/mod.rs +++ b/pyo3-ffi/src/cpython/mod.rs @@ -13,6 +13,7 @@ pub(crate) mod descrobject; pub(crate) mod dictobject; // skipped fileobject.h // skipped fileutils.h +pub(crate) mod floatobject; pub(crate) mod frameobject; pub(crate) mod funcobject; pub(crate) mod genobject; @@ -30,14 +31,14 @@ pub(crate) mod object; pub(crate) mod objimpl; pub(crate) mod pydebug; pub(crate) mod pyerrors; +pub(crate) mod pyframe; #[cfg(all(Py_3_8, not(PyPy)))] pub(crate) mod pylifecycle; pub(crate) mod pymem; pub(crate) mod pystate; pub(crate) mod pythonrun; +pub(crate) mod pythread; // skipped sysmodule.h -pub(crate) mod floatobject; -pub(crate) mod pyframe; pub(crate) mod tupleobject; pub(crate) mod unicodeobject; pub(crate) mod weakrefobject; @@ -78,6 +79,7 @@ pub use self::pylifecycle::*; pub use self::pymem::*; pub use self::pystate::*; pub use self::pythonrun::*; +pub use self::pythread::*; pub use self::tupleobject::*; pub use self::unicodeobject::*; #[cfg(not(any(PyPy, GraalPy)))] diff --git a/pyo3-ffi/src/cpython/pythread.rs b/pyo3-ffi/src/cpython/pythread.rs new file mode 100644 index 00000000000..1e40e669c91 --- /dev/null +++ b/pyo3-ffi/src/cpython/pythread.rs @@ -0,0 +1,42 @@ +use std::mem; +use std::os::raw::{c_int, c_longlong, c_ulong}; + +#[cfg(all(not(PyPy), not(Py_3_13), not(windows)))] +pub const PY_TIMEOUT_MAX: c_longlong = c_longlong::MAX / 1000; +#[cfg(all(not(PyPy), not(Py_3_11), windows))] +pub const PY_TIMEOUT_MAX: c_longlong = (0xFFFFFFFF as c_longlong).saturating_mul(1000); +#[cfg(all(not(PyPy), Py_3_11, not(Py_3_13), windows))] +pub const PY_TIMEOUT_MAX: c_longlong = (0xFFFFFFFE as c_longlong).saturating_mul(1000); +#[cfg(all(not(any(PyPy, GraalPy)), Py_3_13))] +#[cfg_attr(windows, link(name = "pythonXY"))] +extern "C" { + pub static PY_TIMEOUT_MAX: c_longlong; +} + +#[cfg(not(PyPy))] +pub const PYTHREAD_INVALID_THREAD_ID: c_ulong = c_ulong::MAX; + +// skipped _PyThread_at_fork_reinit (removed 3.13) + +#[cfg(not(windows))] +type NATIVE_TSS_KEY_T = libc::pthread_key_t; +#[cfg(windows)] +type NATIVE_TSS_KEY_T = c_ulong; + +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub struct Py_tss_t { + _is_initialized: c_int, + _key: NATIVE_TSS_KEY_T, +} + +impl Default for Py_tss_t { + fn default() -> Self { + Py_tss_NEEDS_INIT + } +} + +pub const Py_tss_NEEDS_INIT: Py_tss_t = Py_tss_t { + _is_initialized: 0, + _key: 0, +}; diff --git a/pyo3-ffi/src/lib.rs b/pyo3-ffi/src/lib.rs index 7bdba1173d6..8c0750c467d 100644 --- a/pyo3-ffi/src/lib.rs +++ b/pyo3-ffi/src/lib.rs @@ -438,6 +438,7 @@ pub use self::pyport::*; pub use self::pystate::*; pub use self::pystrtod::*; pub use self::pythonrun::*; +pub use self::pythread::*; pub use self::rangeobject::*; pub use self::setobject::*; pub use self::sliceobject::*; @@ -528,7 +529,7 @@ mod pythonrun; // skipped pystrhex.h // skipped pystrcmp.h mod pystrtod; -// skipped pythread.h +mod pythread; // skipped pytime.h mod rangeobject; mod setobject; diff --git a/pyo3-ffi/src/pythread.rs b/pyo3-ffi/src/pythread.rs new file mode 100644 index 00000000000..4b91d114b6d --- /dev/null +++ b/pyo3-ffi/src/pythread.rs @@ -0,0 +1,98 @@ +use crate::object::PyObject; +use std::os::raw::{c_int, c_longlong, c_ulong, c_void}; + +pub type PyThread_type_lock = *mut c_void; +// skipped PyThread_type_sema (removed 3.9) + +#[cfg(not(PyPy))] +#[repr(C)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum PyLockStatus { + PY_LOCK_FAILURE = 0, + PY_LOCK_ACQUIRED = 1, + PY_LOCK_INTR, +} + +extern "C" { + pub fn PyThread_init_thread(); + pub fn PyThread_start_new_thread( + arg1: Option, + arg2: *mut c_void, + ) -> c_ulong; + + #[cfg(not(PyPy))] + pub fn PyThread_exit_thread() -> !; + + pub fn PyThread_get_thread_ident() -> c_ulong; + + #[cfg(all( + not(PyPy), + any( + target_os = "ios", + target_os = "macos", + target_os = "tvos", + target_os = "watchos", + target_os = "android", + target_os = "linux", + target_os = "windows", + target_os = "freebsd", + target_os = "openbsd", + target_os = "netbsd", + all(not(GraalPy), Py_3_12, target_os = "dragonfly"), + target_os = "aix" + ) + ))] + pub fn PyThread_get_thread_native_id() -> c_ulong; + + pub fn PyThread_allocate_lock() -> PyThread_type_lock; + pub fn PyThread_free_lock(arg1: PyThread_type_lock); + pub fn PyThread_acquire_lock(arg1: PyThread_type_lock, arg2: c_int) -> c_int; +} + +pub const WAIT_LOCK: c_int = 1; +pub const NOWAIT_LOCK: c_int = 0; + +#[cfg(not(PyPy))] +pub type PY_TIMEOUT_T = c_longlong; + +extern "C" { + #[cfg(not(PyPy))] + pub fn PyThread_acquire_lock_timed( + arg1: PyThread_type_lock, + microseconds: PY_TIMEOUT_T, + intr_flag: c_int, + ) -> PyLockStatus; + + pub fn PyThread_release_lock(arg1: PyThread_type_lock); + + #[cfg(not(PyPy))] + pub fn PyThread_get_stacksize() -> usize; + + #[cfg(not(PyPy))] + pub fn PyThread_set_stacksize(arg1: usize) -> c_int; + + #[cfg(not(PyPy))] + pub fn PyThread_GetInfo() -> *mut PyObject; + + // skipped PyThread_create_key (deprecated 3.7) + // skipped PyThread_delete_key (deprecated 3.7) + // skipped PyThread_set_key_value (deprecated 3.7) + // skipped PyThread_get_key_value (deprecated 3.7) + // skipped PyThread_delete_key_value (deprecated 3.7) + // skipped PyThread_ReInitTLS (deprecated 3.7) +} + +#[cfg(Py_LIMITED_API)] +opaque_struct!(Py_tss_t); +#[cfg(not(Py_LIMITED_API))] +use crate::cpython::pythread::Py_tss_t; + +extern "C" { + pub fn PyThread_tss_alloc() -> *mut Py_tss_t; + pub fn PyThread_tss_free(key: *mut Py_tss_t); + pub fn PyThread_tss_is_created(key: *mut Py_tss_t) -> c_int; + pub fn PyThread_tss_create(key: *mut Py_tss_t) -> c_int; + pub fn PyThread_tss_delete(key: *mut Py_tss_t); + pub fn PyThread_tss_set(key: *mut Py_tss_t, value: *mut c_void) -> c_int; + pub fn PyThread_tss_get(key: *mut Py_tss_t) -> *mut c_void; +}