Bound 'py lifetime by GILPool when it's possible

This commit is contained in:
kngwyu 2020-04-12 16:31:35 +09:00
parent 97fd658593
commit 2cd466dc46
20 changed files with 219 additions and 188 deletions

View file

@ -10,8 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Changed ### Changed
* `PyObject` and `Py<T>` reference counts are now decremented sooner after `drop()`. [#851](https://github.com/PyO3/pyo3/pull/851) * `PyObject` and `Py<T>` reference counts are now decremented sooner after `drop()`. [#851](https://github.com/PyO3/pyo3/pull/851)
* When the GIL is held, the refcount is now decreased immediately on drop. (Previously would wait until just before releasing the GIL.) * When the GIL is held, the refcount is now decreased immediately on drop. (Previously would wait until just before releasing the GIL.)
* When the GIL is not held, the refcount is now decreased when the GIL is next acquired. (Previously would wait until next time the GIL was released.) * When the GIL is not held, the refcount is now decreased when the GIL is next acquired. (Previously would wait until next time the GIL was released.)
### Added ### Added
* `_PyDict_NewPresized`. [#849](https://github.com/PyO3/pyo3/pull/849) * `_PyDict_NewPresized`. [#849](https://github.com/PyO3/pyo3/pull/849)
@ -20,6 +20,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Fixed ### Fixed
* `__radd__` and other `__r*__` methods now correctly work with operators. [#839](https://github.com/PyO3/pyo3/pull/839) * `__radd__` and other `__r*__` methods now correctly work with operators. [#839](https://github.com/PyO3/pyo3/pull/839)
* Garbage Collector causing random panics when traversing objects that were mutably borrowed. [#855](https://github.com/PyO3/pyo3/pull/855) * Garbage Collector causing random panics when traversing objects that were mutably borrowed. [#855](https://github.com/PyO3/pyo3/pull/855)
* `&'static Py~` is not allowed as arguments. [#869](https://github.com/PyO3/pyo3/pull/869)
## [0.9.2] ## [0.9.2]

View file

@ -220,9 +220,9 @@ fn function_c_wrapper(name: &Ident, spec: &method::FnSpec<'_>) -> TokenStream {
{ {
const _LOCATION: &'static str = concat!(stringify!(#name), "()"); const _LOCATION: &'static str = concat!(stringify!(#name), "()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args); let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);

View file

@ -105,9 +105,9 @@ fn impl_wrap_common(
{ {
const _LOCATION: &'static str = concat!( const _LOCATION: &'static str = concat!(
stringify!(#cls), ".", stringify!(#python_name), "()"); stringify!(#cls), ".", stringify!(#python_name), "()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
#slf #slf
pyo3::callback::convert(_py, #body) pyo3::callback::convert(_py, #body)
}) })
@ -124,9 +124,9 @@ fn impl_wrap_common(
{ {
const _LOCATION: &'static str = concat!( const _LOCATION: &'static str = concat!(
stringify!(#cls), ".", stringify!(#python_name), "()"); stringify!(#cls), ".", stringify!(#python_name), "()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
#slf #slf
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args); let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
@ -155,9 +155,9 @@ pub fn impl_proto_wrap(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject _kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject
{ {
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf); let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
#borrow_self #borrow_self
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args); let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
@ -193,9 +193,9 @@ pub fn impl_wrap_new(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
use pyo3::type_object::PyTypeInfo; use pyo3::type_object::PyTypeInfo;
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args); let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
@ -225,9 +225,9 @@ pub fn impl_wrap_class(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject _kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject
{ {
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
let _cls = pyo3::types::PyType::from_type_ptr(_py, _cls as *mut pyo3::ffi::PyTypeObject); let _cls = pyo3::types::PyType::from_type_ptr(_py, _cls as *mut pyo3::ffi::PyTypeObject);
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args); let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
@ -257,9 +257,9 @@ pub fn impl_wrap_static(cls: &syn::Type, spec: &FnSpec<'_>) -> TokenStream {
_kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject _kwargs: *mut pyo3::ffi::PyObject) -> *mut pyo3::ffi::PyObject
{ {
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args); let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs); let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
@ -315,9 +315,9 @@ pub(crate) fn impl_wrap_getter(
{ {
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf); let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
#borrow_self #borrow_self
pyo3::callback::convert(_py, #getter_impl) pyo3::callback::convert(_py, #getter_impl)
@ -372,9 +372,9 @@ pub(crate) fn impl_wrap_setter(
_value: *mut pyo3::ffi::PyObject, _: *mut ::std::os::raw::c_void) -> pyo3::libc::c_int _value: *mut pyo3::ffi::PyObject, _: *mut ::std::os::raw::c_void) -> pyo3::libc::c_int
{ {
const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()"); const _LOCATION: &'static str = concat!(stringify!(#cls),".",stringify!(#python_name),"()");
let _py = pyo3::Python::assume_gil_acquired(); let _pool = pyo3::GILPool::new();
let _py = _pool.python();
pyo3::run_callback(_py, || { pyo3::run_callback(_py, || {
let _pool = pyo3::GILPool::new(_py);
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf); let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
#borrow_self #borrow_self
let _value = _py.from_borrowed_ptr::<pyo3::types::PyAny>(_value); let _value = _py.from_borrowed_ptr::<pyo3::types::PyAny>(_value);

View file

@ -12,7 +12,7 @@ use crate::callback::HashCallbackOutput;
use crate::class::methods::PyMethodDef; use crate::class::methods::PyMethodDef;
use crate::{ use crate::{
callback, exceptions, ffi, run_callback, FromPyObject, GILPool, IntoPy, ObjectProtocol, PyAny, callback, exceptions, ffi, run_callback, FromPyObject, GILPool, IntoPy, ObjectProtocol, PyAny,
PyCell, PyClass, PyErr, PyObject, PyResult, Python, PyCell, PyClass, PyErr, PyObject, PyResult,
}; };
use std::os::raw::c_int; use std::os::raw::c_int;
@ -218,10 +218,9 @@ where
where where
T: for<'p> PyObjectGetAttrProtocol<'p>, T: for<'p> PyObjectGetAttrProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = GILPool::new();
let py = pool.python();
run_callback(py, || { run_callback(py, || {
let _pool = GILPool::new(py);
// Behave like python's __getattr__ (as opposed to __getattribute__) and check // Behave like python's __getattr__ (as opposed to __getattribute__) and check
// for existing fields and methods first // for existing fields and methods first
let existing = ffi::PyObject_GenericGetAttr(slf, arg); let existing = ffi::PyObject_GenericGetAttr(slf, arg);
@ -485,9 +484,9 @@ where
where where
T: for<'p> PyObjectRichcmpProtocol<'p>, T: for<'p> PyObjectRichcmpProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = GILPool::new();
let py = pool.python();
run_callback(py, || { run_callback(py, || {
let _pool = GILPool::new(py);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<PyAny>(arg); let arg = py.from_borrowed_ptr::<PyAny>(arg);

View file

@ -6,7 +6,7 @@
//! c-api //! c-api
use crate::err::PyResult; use crate::err::PyResult;
use crate::gil::GILPool; use crate::gil::GILPool;
use crate::{callback, ffi, run_callback, PyCell, PyClass, PyRefMut, Python}; use crate::{callback, ffi, run_callback, PyCell, PyClass, PyRefMut};
use std::os::raw::c_int; use std::os::raw::c_int;
/// Buffer protocol interface /// Buffer protocol interface
@ -91,9 +91,9 @@ where
where where
T: for<'p> PyBufferGetBufferProtocol<'p>, T: for<'p> PyBufferGetBufferProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = GILPool::new();
let py = pool.python();
run_callback(py, || { run_callback(py, || {
let _pool = GILPool::new(py);
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let result = T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into(); let result = T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into();
callback::convert(py, result) callback::convert(py, result)
@ -126,9 +126,9 @@ where
where where
T: for<'p> PyBufferReleaseBufferProtocol<'p>, T: for<'p> PyBufferReleaseBufferProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = GILPool::new();
let py = pool.python();
run_callback(py, || { run_callback(py, || {
let _pool = GILPool::new(py);
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
let result = T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into(); let result = T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into();
crate::callback::convert(py, result) crate::callback::convert(py, result)

View file

@ -89,8 +89,8 @@ where
where where
T: for<'p> PyGCTraverseProtocol<'p>, T: for<'p> PyGCTraverseProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = crate::GILPool::new();
let _pool = crate::GILPool::new(py); let py = pool.python();
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let visit = PyVisit { let visit = PyVisit {
@ -98,8 +98,8 @@ where
arg, arg,
_py: py, _py: py,
}; };
let borrow = slf.try_borrow();
if let Ok(borrow) = slf.try_borrow() { if let Ok(borrow) = borrow {
match borrow.__traverse__(visit) { match borrow.__traverse__(visit) {
Ok(()) => 0, Ok(()) => 0,
Err(PyTraverseError(code)) => code, Err(PyTraverseError(code)) => code,
@ -136,8 +136,8 @@ where
where where
T: for<'p> PyGCClearProtocol<'p>, T: for<'p> PyGCClearProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = crate::GILPool::new();
let _pool = crate::GILPool::new(py); let py = pool.python();
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
slf.borrow_mut().__clear__(); slf.borrow_mut().__clear__();

View file

@ -8,9 +8,9 @@ macro_rules! py_unary_func {
where where
T: for<'p> $trait<'p>, T: for<'p> $trait<'p>,
{ {
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
$crate::callback::convert(py, $call!(slf, $f)$(.map($conv))?) $crate::callback::convert(py, $call!(slf, $f)$(.map($conv))?)
}) })
@ -34,9 +34,9 @@ macro_rules! py_unary_refmut_func {
where where
T: for<'p> $trait<'p>, T: for<'p> $trait<'p>,
{ {
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let res = $class::$f(slf.borrow_mut()).into(); let res = $class::$f(slf.borrow_mut()).into();
$crate::callback::convert(py, res $(.map($conv))?) $crate::callback::convert(py, res $(.map($conv))?)
@ -69,9 +69,9 @@ macro_rules! py_binary_func {
T: for<'p> $trait<'p>, T: for<'p> $trait<'p>,
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg); let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg);
$crate::callback::convert(py, $call!(slf, $f, arg)$(.map($conv))?) $crate::callback::convert(py, $call!(slf, $f, arg)$(.map($conv))?)
@ -99,9 +99,9 @@ macro_rules! py_binary_num_func {
T: for<'p> $trait<'p>, T: for<'p> $trait<'p>,
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs); let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
let rhs = py.from_borrowed_ptr::<$crate::PyAny>(rhs); let rhs = py.from_borrowed_ptr::<$crate::PyAny>(rhs);
@ -125,9 +125,9 @@ macro_rules! py_binary_reverse_num_func {
T: for<'p> $trait<'p>, T: for<'p> $trait<'p>,
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
// Swap lhs <-> rhs // Swap lhs <-> rhs
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(rhs); let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(rhs);
let arg = py.from_borrowed_ptr::<$crate::PyAny>(lhs); let arg = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
@ -155,9 +155,9 @@ macro_rules! py_binary_self_func {
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf_ = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf); let slf_ = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg); let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg);
call_mut!(slf_, $f, arg)?; call_mut!(slf_, $f, arg)?;
@ -184,9 +184,9 @@ macro_rules! py_ssizearg_func {
where where
T: for<'p> $trait<'p>, T: for<'p> $trait<'p>,
{ {
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
$crate::callback::convert(py, $call!(slf, $f; arg.into())) $crate::callback::convert(py, $call!(slf, $f; arg.into()))
}) })
@ -209,9 +209,9 @@ macro_rules! py_ternary_func {
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg1 = py let arg1 = py
.from_borrowed_ptr::<$crate::types::PyAny>(arg1) .from_borrowed_ptr::<$crate::types::PyAny>(arg1)
@ -245,9 +245,9 @@ macro_rules! py_ternary_num_func {
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let arg1 = py let arg1 = py
.from_borrowed_ptr::<$crate::types::PyAny>(arg1) .from_borrowed_ptr::<$crate::types::PyAny>(arg1)
.extract()?; .extract()?;
@ -280,9 +280,9 @@ macro_rules! py_ternary_reverse_num_func {
T: for<'p> $trait<'p>, T: for<'p> $trait<'p>,
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
// Swap lhs <-> rhs // Swap lhs <-> rhs
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(arg2); let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(arg2);
let slf = slf.try_borrow()?; let slf = slf.try_borrow()?;
@ -312,9 +312,9 @@ macro_rules! py_dummy_ternary_self_func {
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf_cell = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf); let slf_cell = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1); let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1);
call_mut!(slf_cell, $f, arg1)?; call_mut!(slf_cell, $f, arg1)?;
@ -338,9 +338,9 @@ macro_rules! py_func_set {
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf); let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
if value.is_null() { if value.is_null() {
@ -374,10 +374,9 @@ macro_rules! py_func_del {
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
if value.is_null() { if value.is_null() {
let slf = py.from_borrowed_ptr::<$crate::PyCell<U>>(slf); let slf = py.from_borrowed_ptr::<$crate::PyCell<U>>(slf);
let name = py let name = py
@ -408,9 +407,9 @@ macro_rules! py_func_set_del {
{ {
use $crate::ObjectProtocol; use $crate::ObjectProtocol;
let py = $crate::Python::assume_gil_acquired(); let pool = $crate::GILPool::new();
let py = pool.python();
$crate::run_callback(py, || { $crate::run_callback(py, || {
let _pool = $crate::GILPool::new(py);
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf); let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
let name = py.from_borrowed_ptr::<$crate::PyAny>(name); let name = py.from_borrowed_ptr::<$crate::PyAny>(name);

View file

@ -7,7 +7,7 @@ use crate::conversion::{FromPyObject, IntoPy};
use crate::err::{PyErr, PyResult}; use crate::err::{PyErr, PyResult};
use crate::gil::GILPool; use crate::gil::GILPool;
use crate::objectprotocol::ObjectProtocol; use crate::objectprotocol::ObjectProtocol;
use crate::{callback, exceptions, ffi, run_callback, PyAny, PyCell, PyClass, PyObject, Python}; use crate::{callback, exceptions, ffi, run_callback, PyAny, PyCell, PyClass, PyObject};
use std::os::raw::c_int; use std::os::raw::c_int;
/// Sequence interface /// Sequence interface
@ -256,9 +256,9 @@ mod sq_ass_item_impl {
where where
T: for<'p> PySequenceSetItemProtocol<'p>, T: for<'p> PySequenceSetItemProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = GILPool::new();
let py = pool.python();
run_callback(py, || { run_callback(py, || {
let _pool = GILPool::new(py);
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
if value.is_null() { if value.is_null() {
@ -305,9 +305,9 @@ mod sq_ass_item_impl {
where where
T: for<'p> PySequenceDelItemProtocol<'p>, T: for<'p> PySequenceDelItemProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = GILPool::new();
let py = pool.python();
run_callback(py, || { run_callback(py, || {
let _pool = GILPool::new(py);
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let result = if value.is_null() { let result = if value.is_null() {
@ -352,9 +352,9 @@ mod sq_ass_item_impl {
where where
T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>, T: for<'p> PySequenceSetItemProtocol<'p> + for<'p> PySequenceDelItemProtocol<'p>,
{ {
let py = Python::assume_gil_acquired(); let pool = GILPool::new();
let py = pool.python();
run_callback(py, || { run_callback(py, || {
let _pool = GILPool::new(py);
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf); let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
let result = if value.is_null() { let result = if value.is_null() {

View file

@ -6,7 +6,6 @@
use crate::err::PyResult; use crate::err::PyResult;
use crate::exceptions::TypeError; use crate::exceptions::TypeError;
use crate::init_once;
use crate::instance::PyNativeType; use crate::instance::PyNativeType;
use crate::pyclass::PyClass; use crate::pyclass::PyClass;
use crate::pyclass_init::PyClassInitializer; use crate::pyclass_init::PyClassInitializer;
@ -138,8 +137,6 @@ impl ModuleDef {
doc: &str, doc: &str,
initializer: impl Fn(Python, &PyModule) -> PyResult<()>, initializer: impl Fn(Python, &PyModule) -> PyResult<()>,
) -> PyResult<*mut ffi::PyObject> { ) -> PyResult<*mut ffi::PyObject> {
init_once();
#[cfg(py_sys_config = "WITH_THREAD")] #[cfg(py_sys_config = "WITH_THREAD")]
// > Changed in version 3.7: This function is now called by Py_Initialize(), so you dont have // > Changed in version 3.7: This function is now called by Py_Initialize(), so you dont have
// > to call it yourself anymore. // > to call it yourself anymore.
@ -147,11 +144,11 @@ impl ModuleDef {
ffi::PyEval_InitThreads(); ffi::PyEval_InitThreads();
let module = ffi::PyModule_Create(self.0.get()); let module = ffi::PyModule_Create(self.0.get());
let py = Python::assume_gil_acquired(); let pool = GILPool::new();
let py = pool.python();
if module.is_null() { if module.is_null() {
return Err(crate::PyErr::fetch(py)); return Err(crate::PyErr::fetch(py));
} }
let _pool = GILPool::new(py);
let module = py.from_owned_ptr_or_err::<PyModule>(module)?; let module = py.from_owned_ptr_or_err::<PyModule>(module)?;
module.add("__doc__", doc)?; module.add("__doc__", doc)?;
initializer(py, module)?; initializer(py, module)?;

View file

@ -3,12 +3,10 @@
//! Interaction with python's global interpreter lock //! Interaction with python's global interpreter lock
use crate::{ffi, internal_tricks::Unsendable, PyAny, Python}; use crate::{ffi, internal_tricks::Unsendable, PyAny, Python};
use std::cell::Cell; use std::cell::{Cell, UnsafeCell};
use std::ptr::NonNull; use std::{any, mem::ManuallyDrop, ptr::NonNull, sync};
use std::{any, sync};
static START: sync::Once = sync::Once::new(); static START: sync::Once = sync::Once::new();
static START_PYO3: sync::Once = sync::Once::new();
thread_local! { thread_local! {
/// This is a internal counter in pyo3 monitoring whether this thread has the GIL. /// This is a internal counter in pyo3 monitoring whether this thread has the GIL.
@ -90,16 +88,6 @@ pub fn prepare_freethreaded_python() {
// Note that the PyThreadState returned by PyEval_SaveThread is also held in TLS by the Python runtime, // Note that the PyThreadState returned by PyEval_SaveThread is also held in TLS by the Python runtime,
// and will be restored by PyGILState_Ensure. // and will be restored by PyGILState_Ensure.
} }
init_once();
});
}
#[doc(hidden)]
pub fn init_once() {
START_PYO3.call_once(|| unsafe {
// initialize release pool
POOL = Box::into_raw(Box::new(ReleasePool::new()));
}); });
} }
@ -116,28 +104,46 @@ pub fn init_once() {
/// ``` /// ```
#[must_use] #[must_use]
pub struct GILGuard { pub struct GILGuard {
owned: usize,
borrowed: usize,
gstate: ffi::PyGILState_STATE, gstate: ffi::PyGILState_STATE,
// Stable solution for impl !Send pool: ManuallyDrop<GILPool>,
no_send: Unsendable, }
impl GILGuard {
/// Acquires the global interpreter lock, which allows access to the Python runtime.
///
/// If the Python runtime is not already initialized, this function will initialize it.
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
pub fn acquire() -> GILGuard {
prepare_freethreaded_python();
unsafe {
let gstate = ffi::PyGILState_Ensure(); // acquire GIL
GILGuard {
gstate,
pool: ManuallyDrop::new(GILPool::new()),
}
}
}
/// Retrieves the marker type that proves that the GIL was acquired.
#[inline]
pub fn python(&self) -> Python {
unsafe { Python::assume_gil_acquired() }
}
} }
/// The Drop implementation for `GILGuard` will release the GIL. /// The Drop implementation for `GILGuard` will release the GIL.
impl Drop for GILGuard { impl Drop for GILGuard {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
let pool: &'static mut ReleasePool = &mut *POOL; ManuallyDrop::drop(&mut self.pool);
pool.drain(self.python(), self.owned, self.borrowed);
ffi::PyGILState_Release(self.gstate); ffi::PyGILState_Release(self.gstate);
} }
decrement_gil_count();
} }
} }
/// Release pool /// Implementation of release pool
struct ReleasePool { struct ReleasePoolImpl {
owned: ArrayList<NonNull<ffi::PyObject>>, owned: ArrayList<NonNull<ffi::PyObject>>,
borrowed: ArrayList<NonNull<ffi::PyObject>>, borrowed: ArrayList<NonNull<ffi::PyObject>>,
pointers: *mut Vec<NonNull<ffi::PyObject>>, pointers: *mut Vec<NonNull<ffi::PyObject>>,
@ -145,9 +151,9 @@ struct ReleasePool {
p: parking_lot::Mutex<*mut Vec<NonNull<ffi::PyObject>>>, p: parking_lot::Mutex<*mut Vec<NonNull<ffi::PyObject>>>,
} }
impl ReleasePool { impl ReleasePoolImpl {
fn new() -> ReleasePool { fn new() -> Self {
ReleasePool { Self {
owned: ArrayList::new(), owned: ArrayList::new(),
borrowed: ArrayList::new(), borrowed: ArrayList::new(),
pointers: Box::into_raw(Box::new(Vec::with_capacity(256))), pointers: Box::into_raw(Box::new(Vec::with_capacity(256))),
@ -187,42 +193,69 @@ impl ReleasePool {
} }
} }
static mut POOL: *mut ReleasePool = ::std::ptr::null_mut(); /// Sync wrapper of ReleasePoolImpl
struct ReleasePool {
#[doc(hidden)] value: UnsafeCell<Option<ReleasePoolImpl>>,
pub struct GILPool<'p> {
py: Python<'p>,
owned: usize,
borrowed: usize,
no_send: Unsendable,
} }
impl<'p> GILPool<'p> { impl ReleasePool {
#[inline] const fn new() -> Self {
pub fn new(py: Python) -> GILPool { Self {
increment_gil_count(); value: UnsafeCell::new(None),
let p: &'static mut ReleasePool = unsafe { &mut *POOL };
GILPool {
py,
owned: p.owned.len(),
borrowed: p.borrowed.len(),
no_send: Unsendable::default(),
} }
} }
/// # Safety
/// This function is not thread safe. Thus, the caller has to have GIL.
#[allow(clippy::mut_from_ref)]
unsafe fn get_or_init(&self) -> &mut ReleasePoolImpl {
(*self.value.get()).get_or_insert_with(ReleasePoolImpl::new)
}
} }
impl<'p> Drop for GILPool<'p> { static POOL: ReleasePool = ReleasePool::new();
unsafe impl Sync for ReleasePool {}
#[doc(hidden)]
pub struct GILPool {
owned: usize,
borrowed: usize,
// Stable solution for impl !Send
no_send: Unsendable,
}
impl GILPool {
/// # Safety
/// This function requires that GIL is already acquired.
#[inline]
pub unsafe fn new() -> GILPool {
increment_gil_count();
// Release objects that were dropped since last GIL acquisition
let pool = POOL.get_or_init();
pool.release_pointers();
GILPool {
owned: pool.owned.len(),
borrowed: pool.borrowed.len(),
no_send: Unsendable::default(),
}
}
pub unsafe fn python(&self) -> Python {
Python::assume_gil_acquired()
}
}
impl Drop for GILPool {
fn drop(&mut self) { fn drop(&mut self) {
unsafe { unsafe {
let pool: &'static mut ReleasePool = &mut *POOL; let pool = POOL.get_or_init();
pool.drain(self.py, self.owned, self.borrowed); pool.drain(self.python(), self.owned, self.borrowed);
} }
decrement_gil_count(); decrement_gil_count();
} }
} }
pub unsafe fn register_any<'p, T: 'static>(obj: T) -> &'p T { pub unsafe fn register_any<'p, T: 'static>(obj: T) -> &'p T {
let pool: &'static mut ReleasePool = &mut *POOL; let pool = POOL.get_or_init();
pool.obj.push(Box::new(obj)); pool.obj.push(Box::new(obj));
pool.obj pool.obj
@ -234,7 +267,7 @@ pub unsafe fn register_any<'p, T: 'static>(obj: T) -> &'p T {
} }
pub unsafe fn register_pointer(obj: NonNull<ffi::PyObject>) { pub unsafe fn register_pointer(obj: NonNull<ffi::PyObject>) {
let pool = &mut *POOL; let pool = POOL.get_or_init();
if gil_is_acquired() { if gil_is_acquired() {
ffi::Py_DECREF(obj.as_ptr()) ffi::Py_DECREF(obj.as_ptr())
} else { } else {
@ -243,47 +276,15 @@ pub unsafe fn register_pointer(obj: NonNull<ffi::PyObject>) {
} }
pub unsafe fn register_owned(_py: Python, obj: NonNull<ffi::PyObject>) -> &PyAny { pub unsafe fn register_owned(_py: Python, obj: NonNull<ffi::PyObject>) -> &PyAny {
let pool = &mut *POOL; let pool = POOL.get_or_init();
&*(pool.owned.push_back(obj) as *const _ as *const PyAny) &*(pool.owned.push_back(obj) as *const _ as *const PyAny)
} }
pub unsafe fn register_borrowed(_py: Python, obj: NonNull<ffi::PyObject>) -> &PyAny { pub unsafe fn register_borrowed(_py: Python, obj: NonNull<ffi::PyObject>) -> &PyAny {
let pool = &mut *POOL; let pool = POOL.get_or_init();
&*(pool.borrowed.push_back(obj) as *const _ as *const PyAny) &*(pool.borrowed.push_back(obj) as *const _ as *const PyAny)
} }
impl GILGuard {
/// Acquires the global interpreter lock, which allows access to the Python runtime.
///
/// If the Python runtime is not already initialized, this function will initialize it.
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
pub fn acquire() -> GILGuard {
prepare_freethreaded_python();
unsafe {
let gstate = ffi::PyGILState_Ensure(); // acquire GIL
increment_gil_count();
// Release objects that were dropped since last GIL acquisition
let pool: &'static mut ReleasePool = &mut *POOL;
pool.release_pointers();
GILGuard {
owned: pool.owned.len(),
borrowed: pool.borrowed.len(),
gstate,
no_send: Unsendable::default(),
}
}
}
/// Retrieves the marker type that proves that the GIL was acquired.
#[inline]
pub fn python(&self) -> Python {
unsafe { Python::assume_gil_acquired() }
}
}
/// Increment pyo3's internal GIL count - to be called whenever GILPool or GILGuard is created. /// Increment pyo3's internal GIL count - to be called whenever GILPool or GILGuard is created.
#[inline(always)] #[inline(always)]
fn increment_gil_count() { fn increment_gil_count() {
@ -361,7 +362,7 @@ mod array_list {
#[cfg(test)] #[cfg(test)]
mod test { mod test {
use super::{GILPool, NonNull, ReleasePool, GIL_COUNT, POOL}; use super::{GILPool, NonNull, GIL_COUNT, POOL};
use crate::object::PyObject; use crate::object::PyObject;
use crate::AsPyPointer; use crate::AsPyPointer;
use crate::Python; use crate::Python;
@ -388,7 +389,7 @@ mod test {
let _ref = obj.clone_ref(py); let _ref = obj.clone_ref(py);
unsafe { unsafe {
let p: &'static mut ReleasePool = &mut *POOL; let p = POOL.get_or_init();
{ {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
@ -416,10 +417,10 @@ mod test {
let obj_ptr = obj.as_ptr(); let obj_ptr = obj.as_ptr();
unsafe { unsafe {
let p: &'static mut ReleasePool = &mut *POOL; let p = POOL.get_or_init();
{ {
let _pool = GILPool::new(py); let _pool = GILPool::new();
assert_eq!(p.owned.len(), 0); assert_eq!(p.owned.len(), 0);
let _ = gil::register_owned(py, obj.into_nonnull()); let _ = gil::register_owned(py, obj.into_nonnull());
@ -427,7 +428,7 @@ mod test {
assert_eq!(p.owned.len(), 1); assert_eq!(p.owned.len(), 1);
assert_eq!(ffi::Py_REFCNT(obj_ptr), 2); assert_eq!(ffi::Py_REFCNT(obj_ptr), 2);
{ {
let _pool = GILPool::new(py); let _pool = GILPool::new();
let obj = get_object(); let obj = get_object();
let _ = gil::register_owned(py, obj.into_nonnull()); let _ = gil::register_owned(py, obj.into_nonnull());
assert_eq!(p.owned.len(), 2); assert_eq!(p.owned.len(), 2);
@ -443,9 +444,8 @@ mod test {
#[test] #[test]
fn test_borrowed() { fn test_borrowed() {
gil::init_once();
unsafe { unsafe {
let p: &'static mut ReleasePool = &mut *POOL; let p = POOL.get_or_init();
let obj = get_object(); let obj = get_object();
let obj_ptr = obj.as_ptr(); let obj_ptr = obj.as_ptr();
@ -469,9 +469,8 @@ mod test {
#[test] #[test]
fn test_borrowed_nested() { fn test_borrowed_nested() {
gil::init_once();
unsafe { unsafe {
let p: &'static mut ReleasePool = &mut *POOL; let p = POOL.get_or_init();
let obj = get_object(); let obj = get_object();
let obj_ptr = obj.as_ptr(); let obj_ptr = obj.as_ptr();
@ -486,7 +485,7 @@ mod test {
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1); assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
{ {
let _pool = GILPool::new(py); let _pool = GILPool::new();
assert_eq!(p.borrowed.len(), 1); assert_eq!(p.borrowed.len(), 1);
gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap()); gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap());
assert_eq!(p.borrowed.len(), 2); assert_eq!(p.borrowed.len(), 2);
@ -513,7 +512,7 @@ mod test {
let obj_ptr = obj.as_ptr(); let obj_ptr = obj.as_ptr();
unsafe { unsafe {
let p: &'static mut ReleasePool = &mut *POOL; let p = POOL.get_or_init();
{ {
assert_eq!(p.owned.len(), 0); assert_eq!(p.owned.len(), 0);
@ -536,7 +535,7 @@ mod test {
let obj_ptr = obj.as_ptr(); let obj_ptr = obj.as_ptr();
unsafe { unsafe {
let p: &'static mut ReleasePool = &mut *POOL; let p = POOL.get_or_init();
{ {
assert_eq!(p.owned.len(), 0); assert_eq!(p.owned.len(), 0);
@ -565,13 +564,11 @@ mod test {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
assert_eq!(get_gil_count(), 1); assert_eq!(get_gil_count(), 1);
let py = gil.python();
assert_eq!(get_gil_count(), 1); assert_eq!(get_gil_count(), 1);
let pool = GILPool::new(py); let pool = unsafe { GILPool::new() };
assert_eq!(get_gil_count(), 2); assert_eq!(get_gil_count(), 2);
let pool2 = GILPool::new(py); let pool2 = unsafe { GILPool::new() };
assert_eq!(get_gil_count(), 3); assert_eq!(get_gil_count(), 3);
drop(pool); drop(pool);

View file

@ -140,7 +140,7 @@ pub use crate::conversion::{
ToBorrowedObject, ToPyObject, ToBorrowedObject, ToPyObject,
}; };
pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult}; pub use crate::err::{PyDowncastError, PyErr, PyErrArguments, PyErrValue, PyResult};
pub use crate::gil::{init_once, GILGuard, GILPool}; pub use crate::gil::{GILGuard, GILPool};
pub use crate::instance::{AsPyRef, ManagedPyRef, Py, PyNativeType}; pub use crate::instance::{AsPyRef, ManagedPyRef, Py, PyNativeType};
pub use crate::object::PyObject; pub use crate::object::PyObject;
pub use crate::objectprotocol::ObjectProtocol; pub use crate::objectprotocol::ObjectProtocol;

View file

@ -2,7 +2,7 @@
use crate::class::methods::{PyMethodDefType, PyMethodsProtocol}; use crate::class::methods::{PyMethodDefType, PyMethodsProtocol};
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef}; use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
use crate::type_object::{type_flags, PyLayout}; use crate::type_object::{type_flags, PyLayout};
use crate::{class, ffi, gil, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python}; use crate::{class, ffi, PyCell, PyErr, PyNativeType, PyResult, PyTypeInfo, Python};
use std::ffi::CString; use std::ffi::CString;
use std::os::raw::c_void; use std::os::raw::c_void;
use std::ptr; use std::ptr;
@ -111,8 +111,8 @@ where
where where
T: PyClassAlloc, T: PyClassAlloc,
{ {
let py = Python::assume_gil_acquired(); let pool = crate::GILPool::new();
let _pool = gil::GILPool::new(py); let py = pool.python();
<T as PyClassAlloc>::dealloc(py, (obj as *mut T::Layout) as _) <T as PyClassAlloc>::dealloc(py, (obj as *mut T::Layout) as _)
} }
type_object.tp_dealloc = Some(tp_dealloc_callback::<T>); type_object.tp_dealloc = Some(tp_dealloc_callback::<T>);

View file

@ -57,6 +57,10 @@ impl<'p> Python<'p> {
/// Because the output lifetime `'p` is not connected to any input parameter, /// Because the output lifetime `'p` is not connected to any input parameter,
/// care must be taken that the compiler infers an appropriate lifetime for `'p` /// care must be taken that the compiler infers an appropriate lifetime for `'p`
/// when calling this function. /// when calling this function.
///
/// # Safety
/// The lifetime `'p` must be shorter than the period you *assume* that you have GIL.
/// I.e., `Python<'static>` is always *really* unsafe.
#[inline] #[inline]
pub unsafe fn assume_gil_acquired() -> Python<'p> { pub unsafe fn assume_gil_acquired() -> Python<'p> {
Python(PhantomData) Python(PhantomData)

View file

@ -472,7 +472,7 @@ mod test {
let cnt; let cnt;
{ {
let _pool = crate::GILPool::new(py); let _pool = unsafe { crate::GILPool::new() };
let none = py.None(); let none = py.None();
cnt = none.get_refcnt(); cnt = none.get_refcnt();
let _dict = [(10, none)].into_py_dict(py); let _dict = [(10, none)].into_py_dict(py);

View file

@ -137,7 +137,7 @@ mod tests {
let none; let none;
let count; let count;
{ {
let _pool = GILPool::new(py); let _pool = unsafe { GILPool::new() };
let l = PyList::empty(py); let l = PyList::empty(py);
none = py.None(); none = py.None();
l.append(10).unwrap(); l.append(10).unwrap();
@ -147,7 +147,7 @@ mod tests {
} }
{ {
let _pool = GILPool::new(py); let _pool = unsafe { GILPool::new() };
let inst = obj.as_ref(py); let inst = obj.as_ref(py);
let mut it = inst.iter().unwrap(); let mut it = inst.iter().unwrap();

View file

@ -296,7 +296,7 @@ mod test {
let cnt; let cnt;
{ {
let _pool = crate::GILPool::new(py); let _pool = unsafe { crate::GILPool::new() };
let v = vec![2]; let v = vec![2];
let ob = v.to_object(py); let ob = v.to_object(py);
let list = <PyList as PyTryFrom>::try_from(ob.as_ref(py)).unwrap(); let list = <PyList as PyTryFrom>::try_from(ob.as_ref(py)).unwrap();
@ -331,7 +331,7 @@ mod test {
let cnt; let cnt;
{ {
let _pool = crate::GILPool::new(py); let _pool = unsafe { crate::GILPool::new() };
let list = PyList::empty(py); let list = PyList::empty(py);
let none = py.None(); let none = py.None();
cnt = none.get_refcnt(); cnt = none.get_refcnt();
@ -360,7 +360,7 @@ mod test {
let cnt; let cnt;
{ {
let _pool = crate::GILPool::new(py); let _pool = unsafe { crate::GILPool::new() };
let list = PyList::empty(py); let list = PyList::empty(py);
let none = py.None(); let none = py.None();
cnt = none.get_refcnt(); cnt = none.get_refcnt();

View file

@ -7,4 +7,10 @@ fn test_compile_errors() {
t.compile_fail("tests/ui/invalid_pymethod_names.rs"); t.compile_fail("tests/ui/invalid_pymethod_names.rs");
t.compile_fail("tests/ui/missing_clone.rs"); t.compile_fail("tests/ui/missing_clone.rs");
t.compile_fail("tests/ui/reject_generics.rs"); t.compile_fail("tests/ui/reject_generics.rs");
// Since the current minimum nightly(2020-01-20) has a different error message,
// we skip a test.
// TODO(kngwyu): Remove this when we update minimum nightly.
if option_env!("TRAVIS_JOB_NAME") != Some("Minimum nightly") {
t.compile_fail("tests/ui/static_ref.rs");
}
} }

0
tests/test_datetime.rs Executable file → Normal file
View file

17
tests/ui/static_ref.rs Normal file
View file

@ -0,0 +1,17 @@
use pyo3::prelude::*;
use pyo3::types::PyList;
#[pyclass]
struct MyClass {
list: &'static PyList,
}
#[pymethods]
impl MyClass {
#[new]
fn new(list: &'static PyList) -> Self {
Self { list }
}
}
fn main() {}

View file

@ -0,0 +1,11 @@
error[E0597]: `_pool` does not live long enough
--> $DIR/static_ref.rs:9:1
|
9 | #[pymethods]
| ^^^^^^^^^^^-
| | |
| | `_pool` dropped here while still borrowed
| borrowed value does not live long enough
| cast requires that `_pool` is borrowed for `'static`
|
= note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info)