Skip to content

Commit

Permalink
remove safe static for datetime API from ffi module
Browse files Browse the repository at this point in the history
  • Loading branch information
pascalkuthe committed Jan 26, 2022
1 parent 39dbfdb commit dd423a2
Show file tree
Hide file tree
Showing 9 changed files with 354 additions and 391 deletions.
62 changes: 32 additions & 30 deletions pyo3-ffi/src/datetime.rs
Expand Up @@ -9,7 +9,7 @@
//! Support for `PyDateTime_CAPI` is limited as of PyPy 7.0.0.
//! `DateTime_FromTimestamp` and `Date_FromTimestamp` are currently not supported.

use crate::{PyObject, PyObject_TypeCheck, PyTypeObject, Py_TYPE};
use crate::{PyObject, PyObject_TypeCheck, PyTypeObject, Py_TYPE, UnsafeGILCell};
use std::os::raw::{c_char, c_int, c_uchar};
use std::ptr;
#[cfg(not(PyPy))]
Expand Down Expand Up @@ -431,31 +431,29 @@ pub struct PyDateTime_CAPI {
// Python already shares this object between threads, so it's no more evil for us to do it too!
unsafe impl Sync for PyDateTime_CAPI {}

pub static mut PyDateTimeAPI: *mut PyDateTime_CAPI = ptr::null_mut();
pub static PyDateTimeAPI: UnsafeGILCell<PyDateTime_CAPI> = UnsafeGILCell::new(ptr::null_mut());

#[cfg(not(all(PyPy, not(Py_3_8))))]
pub unsafe fn PyDateTime_TimeZone_UTC() -> *mut PyObject {
(*PyDateTimeAPI).TimeZone_UTC
(*PyDateTimeAPI.get()).TimeZone_UTC
}

/// Populates the `PyDateTimeAPI` object
pub unsafe fn PyDateTime_IMPORT() {
PyDateTimeAPI = {
// PyPy expects the C-API to be initialized via PyDateTime_Import, so trying to use
// `PyCapsule_Import` will behave unexpectedly in pypy.
#[cfg(PyPy)]
let py_datetime_c_api = PyDateTime_Import();
// PyPy expects the C-API to be initialized via PyDateTime_Import, so trying to use
// `PyCapsule_Import` will behave unexpectedly in pypy.
#[cfg(PyPy)]
let py_datetime_c_api = PyDateTime_Import();

#[cfg(not(PyPy))]
let py_datetime_c_api = {
// PyDateTime_CAPSULE_NAME is a macro in C
let PyDateTime_CAPSULE_NAME = CString::new("datetime.datetime_CAPI").unwrap();

PyCapsule_Import(PyDateTime_CAPSULE_NAME.as_ptr(), 1) as *mut PyDateTime_CAPI
};
#[cfg(not(PyPy))]
let py_datetime_c_api = {
// PyDateTime_CAPSULE_NAME is a macro in C
let PyDateTime_CAPSULE_NAME = CString::new("datetime.datetime_CAPI").unwrap();

py_datetime_c_api
PyCapsule_Import(PyDateTime_CAPSULE_NAME.as_ptr(), 1) as *mut PyDateTime_CAPI
};

PyDateTimeAPI.set(py_datetime_c_api)
}

// skipped non-limited PyDateTime_TimeZone_UTC
Expand All @@ -468,61 +466,61 @@ pub unsafe fn PyDateTime_IMPORT() {
#[inline]
/// Check if `op` is a `PyDateTimeAPI.DateType` or subtype.
pub unsafe fn PyDate_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, (*PyDateTimeAPI).DateType) as c_int
PyObject_TypeCheck(op, (*PyDateTimeAPI.get()).DateType) as c_int
}

#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.DateType`.
pub unsafe fn PyDate_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == (*PyDateTimeAPI).DateType) as c_int
(Py_TYPE(op) == (*PyDateTimeAPI.get()).DateType) as c_int
}

#[inline]
/// Check if `op` is a `PyDateTimeAPI.DateTimeType` or subtype.
pub unsafe fn PyDateTime_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, (*PyDateTimeAPI).DateTimeType) as c_int
PyObject_TypeCheck(op, (*PyDateTimeAPI.get()).DateTimeType) as c_int
}

#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.DateTimeType`.
pub unsafe fn PyDateTime_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == (*PyDateTimeAPI).DateTimeType) as c_int
(Py_TYPE(op) == (*PyDateTimeAPI.get()).DateTimeType) as c_int
}

#[inline]
/// Check if `op` is a `PyDateTimeAPI.TimeType` or subtype.
pub unsafe fn PyTime_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, (*PyDateTimeAPI).TimeType) as c_int
PyObject_TypeCheck(op, (*PyDateTimeAPI.get()).TimeType) as c_int
}

#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.TimeType`.
pub unsafe fn PyTime_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == (*PyDateTimeAPI).TimeType) as c_int
(Py_TYPE(op) == (*PyDateTimeAPI.get()).TimeType) as c_int
}

#[inline]
/// Check if `op` is a `PyDateTimeAPI.DetaType` or subtype.
pub unsafe fn PyDelta_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, (*PyDateTimeAPI).DeltaType) as c_int
PyObject_TypeCheck(op, (*PyDateTimeAPI.get()).DeltaType) as c_int
}

#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.DeltaType`.
pub unsafe fn PyDelta_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == (*PyDateTimeAPI).DeltaType) as c_int
(Py_TYPE(op) == (*PyDateTimeAPI.get()).DeltaType) as c_int
}

#[inline]
/// Check if `op` is a `PyDateTimeAPI.TZInfoType` or subtype.
pub unsafe fn PyTZInfo_Check(op: *mut PyObject) -> c_int {
PyObject_TypeCheck(op, (*PyDateTimeAPI).TZInfoType) as c_int
PyObject_TypeCheck(op, (*PyDateTimeAPI.get()).TZInfoType) as c_int
}

#[inline]
/// Check if `op`'s type is exactly `PyDateTimeAPI.TZInfoType`.
pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int {
(Py_TYPE(op) == (*PyDateTimeAPI).TZInfoType) as c_int
(Py_TYPE(op) == (*PyDateTimeAPI.get()).TZInfoType) as c_int
}

// skipped non-limited PyDate_FromDate
Expand All @@ -536,14 +534,18 @@ pub unsafe fn PyTZInfo_CheckExact(op: *mut PyObject) -> c_int {

#[cfg(not(PyPy))]
pub unsafe fn PyDateTime_FromTimestamp(args: *mut PyObject) -> *mut PyObject {
let f = (*PyDateTimeAPI).DateTime_FromTimestamp;
f((*PyDateTimeAPI).DateTimeType, args, std::ptr::null_mut())
let f = (*PyDateTimeAPI.get()).DateTime_FromTimestamp;
f(
(*PyDateTimeAPI.get()).DateTimeType,
args,
std::ptr::null_mut(),
)
}

#[cfg(not(PyPy))]
pub unsafe fn PyDate_FromTimestamp(args: *mut PyObject) -> *mut PyObject {
let f = (*PyDateTimeAPI).Date_FromTimestamp;
f((*PyDateTimeAPI).DateType, args)
let f = (*PyDateTimeAPI.get()).Date_FromTimestamp;
f((*PyDateTimeAPI.get()).DateType, args)
}

#[cfg(PyPy)]
Expand Down
35 changes: 35 additions & 0 deletions pyo3-ffi/src/lib.rs
Expand Up @@ -253,6 +253,8 @@ macro_rules! opaque_struct {
};
}

use std::cell::Cell;

pub use self::abstract_::*;
pub use self::bltinmodule::*;
pub use self::boolobject::*;
Expand Down Expand Up @@ -418,3 +420,36 @@ mod cpython;

#[cfg(not(Py_LIMITED_API))]
pub use self::cpython::*;

/// This cell type allows shared mutability for python types.
/// It is intended to hold raw pointers to the python heap and therefore only accepts copy types to
/// reduce the changes of accidental undefined behaviour.
/// Thread safety is ensured by the python GIL.
/// Therefore accessing the contents of this cell in any form while the GIL is not held is UB
#[repr(transparent)]
pub struct UnsafeGILCell<T>(Cell<*mut T>);

impl<T> UnsafeGILCell<T> {
pub const fn new(val: *mut T) -> UnsafeGILCell<T> {
UnsafeGILCell(Cell::new(val))
}

/// Sets the contained value.
///
/// # Safety
/// The caller must assure that the GIL is held
pub unsafe fn set(&self, val: *mut T) {
self.0.set(val)
}

/// Returns a copy of the contained value.
///
/// # Safety
/// The caller must assure that the GIL is held
pub unsafe fn get(&self) -> *mut T {
self.0.get()
}
}

unsafe impl<T: Sync> Sync for UnsafeGILCell<T> {}
unsafe impl<T: Sync> Send for UnsafeGILCell<T> {}
1 change: 0 additions & 1 deletion src/ffi/cpython/mod.rs

This file was deleted.

128 changes: 0 additions & 128 deletions src/ffi/cpython/unicodeobject.rs

This file was deleted.

0 comments on commit dd423a2

Please sign in to comment.