Bound 'py lifetime by GILPool when it's possible
This commit is contained in:
parent
97fd658593
commit
2cd466dc46
|
@ -10,8 +10,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
|
|||
### Changed
|
||||
|
||||
* `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 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 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.)
|
||||
|
||||
### Added
|
||||
* `_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
|
||||
* `__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)
|
||||
* `&'static Py~` is not allowed as arguments. [#869](https://github.com/PyO3/pyo3/pull/869)
|
||||
|
||||
## [0.9.2]
|
||||
|
||||
|
|
|
@ -220,9 +220,9 @@ fn function_c_wrapper(name: &Ident, spec: &method::FnSpec<'_>) -> TokenStream {
|
|||
{
|
||||
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, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
|
||||
let _kwargs: Option<&pyo3::types::PyDict> = _py.from_borrowed_ptr_or_opt(_kwargs);
|
||||
|
||||
|
|
|
@ -105,9 +105,9 @@ fn impl_wrap_common(
|
|||
{
|
||||
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, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
#slf
|
||||
pyo3::callback::convert(_py, #body)
|
||||
})
|
||||
|
@ -124,9 +124,9 @@ fn impl_wrap_common(
|
|||
{
|
||||
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, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
#slf
|
||||
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
|
||||
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
|
||||
{
|
||||
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, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
|
||||
#borrow_self
|
||||
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;
|
||||
|
||||
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, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
|
||||
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
|
||||
{
|
||||
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, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
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 _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
|
||||
{
|
||||
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, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _args = _py.from_borrowed_ptr::<pyo3::types::PyTuple>(_args);
|
||||
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),"()");
|
||||
|
||||
let _py = pyo3::Python::assume_gil_acquired();
|
||||
let _pool = pyo3::GILPool::new();
|
||||
let _py = _pool.python();
|
||||
pyo3::run_callback(_py, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
|
||||
#borrow_self
|
||||
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
|
||||
{
|
||||
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, || {
|
||||
let _pool = pyo3::GILPool::new(_py);
|
||||
let _slf = _py.from_borrowed_ptr::<pyo3::PyCell<#cls>>(_slf);
|
||||
#borrow_self
|
||||
let _value = _py.from_borrowed_ptr::<pyo3::types::PyAny>(_value);
|
||||
|
|
|
@ -12,7 +12,7 @@ use crate::callback::HashCallbackOutput;
|
|||
use crate::class::methods::PyMethodDef;
|
||||
use crate::{
|
||||
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;
|
||||
|
||||
|
@ -218,10 +218,9 @@ where
|
|||
where
|
||||
T: for<'p> PyObjectGetAttrProtocol<'p>,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let pool = GILPool::new();
|
||||
let py = pool.python();
|
||||
run_callback(py, || {
|
||||
let _pool = GILPool::new(py);
|
||||
|
||||
// Behave like python's __getattr__ (as opposed to __getattribute__) and check
|
||||
// for existing fields and methods first
|
||||
let existing = ffi::PyObject_GenericGetAttr(slf, arg);
|
||||
|
@ -485,9 +484,9 @@ where
|
|||
where
|
||||
T: for<'p> PyObjectRichcmpProtocol<'p>,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let pool = GILPool::new();
|
||||
let py = pool.python();
|
||||
run_callback(py, || {
|
||||
let _pool = GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<PyAny>(arg);
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
//! c-api
|
||||
use crate::err::PyResult;
|
||||
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;
|
||||
|
||||
/// Buffer protocol interface
|
||||
|
@ -91,9 +91,9 @@ where
|
|||
where
|
||||
T: for<'p> PyBufferGetBufferProtocol<'p>,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let pool = GILPool::new();
|
||||
let py = pool.python();
|
||||
run_callback(py, || {
|
||||
let _pool = GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
let result = T::bf_getbuffer(slf.try_borrow_mut()?, arg1, arg2).into();
|
||||
callback::convert(py, result)
|
||||
|
@ -126,9 +126,9 @@ where
|
|||
where
|
||||
T: for<'p> PyBufferReleaseBufferProtocol<'p>,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let pool = GILPool::new();
|
||||
let py = pool.python();
|
||||
run_callback(py, || {
|
||||
let _pool = GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<crate::PyCell<T>>(slf);
|
||||
let result = T::bf_releasebuffer(slf.try_borrow_mut()?, arg1).into();
|
||||
crate::callback::convert(py, result)
|
||||
|
|
|
@ -89,8 +89,8 @@ where
|
|||
where
|
||||
T: for<'p> PyGCTraverseProtocol<'p>,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let _pool = crate::GILPool::new(py);
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
let visit = PyVisit {
|
||||
|
@ -98,8 +98,8 @@ where
|
|||
arg,
|
||||
_py: py,
|
||||
};
|
||||
|
||||
if let Ok(borrow) = slf.try_borrow() {
|
||||
let borrow = slf.try_borrow();
|
||||
if let Ok(borrow) = borrow {
|
||||
match borrow.__traverse__(visit) {
|
||||
Ok(()) => 0,
|
||||
Err(PyTraverseError(code)) => code,
|
||||
|
@ -136,8 +136,8 @@ where
|
|||
where
|
||||
T: for<'p> PyGCClearProtocol<'p>,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let _pool = crate::GILPool::new(py);
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
slf.borrow_mut().__clear__();
|
||||
|
|
|
@ -8,9 +8,9 @@ macro_rules! py_unary_func {
|
|||
where
|
||||
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, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
$crate::callback::convert(py, $call!(slf, $f)$(.map($conv))?)
|
||||
})
|
||||
|
@ -34,9 +34,9 @@ macro_rules! py_unary_refmut_func {
|
|||
where
|
||||
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, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let res = $class::$f(slf.borrow_mut()).into();
|
||||
$crate::callback::convert(py, res $(.map($conv))?)
|
||||
|
@ -69,9 +69,9 @@ macro_rules! py_binary_func {
|
|||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
use $crate::ObjectProtocol;
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg);
|
||||
$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>,
|
||||
{
|
||||
use $crate::ObjectProtocol;
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let lhs = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
|
||||
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>,
|
||||
{
|
||||
use $crate::ObjectProtocol;
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
// Swap lhs <-> rhs
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(rhs);
|
||||
let arg = py.from_borrowed_ptr::<$crate::PyAny>(lhs);
|
||||
|
@ -155,9 +155,9 @@ macro_rules! py_binary_self_func {
|
|||
{
|
||||
use $crate::ObjectProtocol;
|
||||
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf_ = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let arg = py.from_borrowed_ptr::<$crate::PyAny>(arg);
|
||||
call_mut!(slf_, $f, arg)?;
|
||||
|
@ -184,9 +184,9 @@ macro_rules! py_ssizearg_func {
|
|||
where
|
||||
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, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
$crate::callback::convert(py, $call!(slf, $f; arg.into()))
|
||||
})
|
||||
|
@ -209,9 +209,9 @@ macro_rules! py_ternary_func {
|
|||
{
|
||||
use $crate::ObjectProtocol;
|
||||
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let arg1 = py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>(arg1)
|
||||
|
@ -245,9 +245,9 @@ macro_rules! py_ternary_num_func {
|
|||
{
|
||||
use $crate::ObjectProtocol;
|
||||
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let arg1 = py
|
||||
.from_borrowed_ptr::<$crate::types::PyAny>(arg1)
|
||||
.extract()?;
|
||||
|
@ -280,9 +280,9 @@ macro_rules! py_ternary_reverse_num_func {
|
|||
T: for<'p> $trait<'p>,
|
||||
{
|
||||
use $crate::ObjectProtocol;
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
// Swap lhs <-> rhs
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<T>>(arg2);
|
||||
let slf = slf.try_borrow()?;
|
||||
|
@ -312,9 +312,9 @@ macro_rules! py_dummy_ternary_self_func {
|
|||
{
|
||||
use $crate::ObjectProtocol;
|
||||
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf_cell = py.from_borrowed_ptr::<$crate::PyCell<T>>(slf);
|
||||
let arg1 = py.from_borrowed_ptr::<$crate::PyAny>(arg1);
|
||||
call_mut!(slf_cell, $f, arg1)?;
|
||||
|
@ -338,9 +338,9 @@ macro_rules! py_func_set {
|
|||
{
|
||||
use $crate::ObjectProtocol;
|
||||
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
|
@ -374,10 +374,9 @@ macro_rules! py_func_del {
|
|||
{
|
||||
use $crate::ObjectProtocol;
|
||||
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
|
||||
if value.is_null() {
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<U>>(slf);
|
||||
let name = py
|
||||
|
@ -408,9 +407,9 @@ macro_rules! py_func_set_del {
|
|||
{
|
||||
use $crate::ObjectProtocol;
|
||||
|
||||
let py = $crate::Python::assume_gil_acquired();
|
||||
let pool = $crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
$crate::run_callback(py, || {
|
||||
let _pool = $crate::GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<$crate::PyCell<$generic>>(slf);
|
||||
let name = py.from_borrowed_ptr::<$crate::PyAny>(name);
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use crate::conversion::{FromPyObject, IntoPy};
|
|||
use crate::err::{PyErr, PyResult};
|
||||
use crate::gil::GILPool;
|
||||
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;
|
||||
|
||||
/// Sequence interface
|
||||
|
@ -256,9 +256,9 @@ mod sq_ass_item_impl {
|
|||
where
|
||||
T: for<'p> PySequenceSetItemProtocol<'p>,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let pool = GILPool::new();
|
||||
let py = pool.python();
|
||||
run_callback(py, || {
|
||||
let _pool = GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
if value.is_null() {
|
||||
|
@ -305,9 +305,9 @@ mod sq_ass_item_impl {
|
|||
where
|
||||
T: for<'p> PySequenceDelItemProtocol<'p>,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let pool = GILPool::new();
|
||||
let py = pool.python();
|
||||
run_callback(py, || {
|
||||
let _pool = GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
let result = if value.is_null() {
|
||||
|
@ -352,9 +352,9 @@ mod sq_ass_item_impl {
|
|||
where
|
||||
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, || {
|
||||
let _pool = GILPool::new(py);
|
||||
let slf = py.from_borrowed_ptr::<PyCell<T>>(slf);
|
||||
|
||||
let result = if value.is_null() {
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
use crate::err::PyResult;
|
||||
use crate::exceptions::TypeError;
|
||||
use crate::init_once;
|
||||
use crate::instance::PyNativeType;
|
||||
use crate::pyclass::PyClass;
|
||||
use crate::pyclass_init::PyClassInitializer;
|
||||
|
@ -138,8 +137,6 @@ impl ModuleDef {
|
|||
doc: &str,
|
||||
initializer: impl Fn(Python, &PyModule) -> PyResult<()>,
|
||||
) -> PyResult<*mut ffi::PyObject> {
|
||||
init_once();
|
||||
|
||||
#[cfg(py_sys_config = "WITH_THREAD")]
|
||||
// > Changed in version 3.7: This function is now called by Py_Initialize(), so you don’t have
|
||||
// > to call it yourself anymore.
|
||||
|
@ -147,11 +144,11 @@ impl ModuleDef {
|
|||
ffi::PyEval_InitThreads();
|
||||
|
||||
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() {
|
||||
return Err(crate::PyErr::fetch(py));
|
||||
}
|
||||
let _pool = GILPool::new(py);
|
||||
let module = py.from_owned_ptr_or_err::<PyModule>(module)?;
|
||||
module.add("__doc__", doc)?;
|
||||
initializer(py, module)?;
|
||||
|
|
179
src/gil.rs
179
src/gil.rs
|
@ -3,12 +3,10 @@
|
|||
//! Interaction with python's global interpreter lock
|
||||
|
||||
use crate::{ffi, internal_tricks::Unsendable, PyAny, Python};
|
||||
use std::cell::Cell;
|
||||
use std::ptr::NonNull;
|
||||
use std::{any, sync};
|
||||
use std::cell::{Cell, UnsafeCell};
|
||||
use std::{any, mem::ManuallyDrop, ptr::NonNull, sync};
|
||||
|
||||
static START: sync::Once = sync::Once::new();
|
||||
static START_PYO3: sync::Once = sync::Once::new();
|
||||
|
||||
thread_local! {
|
||||
/// 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,
|
||||
// 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]
|
||||
pub struct GILGuard {
|
||||
owned: usize,
|
||||
borrowed: usize,
|
||||
gstate: ffi::PyGILState_STATE,
|
||||
// Stable solution for impl !Send
|
||||
no_send: Unsendable,
|
||||
pool: ManuallyDrop<GILPool>,
|
||||
}
|
||||
|
||||
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.
|
||||
impl Drop for GILGuard {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let pool: &'static mut ReleasePool = &mut *POOL;
|
||||
pool.drain(self.python(), self.owned, self.borrowed);
|
||||
ManuallyDrop::drop(&mut self.pool);
|
||||
ffi::PyGILState_Release(self.gstate);
|
||||
}
|
||||
|
||||
decrement_gil_count();
|
||||
}
|
||||
}
|
||||
|
||||
/// Release pool
|
||||
struct ReleasePool {
|
||||
/// Implementation of release pool
|
||||
struct ReleasePoolImpl {
|
||||
owned: ArrayList<NonNull<ffi::PyObject>>,
|
||||
borrowed: ArrayList<NonNull<ffi::PyObject>>,
|
||||
pointers: *mut Vec<NonNull<ffi::PyObject>>,
|
||||
|
@ -145,9 +151,9 @@ struct ReleasePool {
|
|||
p: parking_lot::Mutex<*mut Vec<NonNull<ffi::PyObject>>>,
|
||||
}
|
||||
|
||||
impl ReleasePool {
|
||||
fn new() -> ReleasePool {
|
||||
ReleasePool {
|
||||
impl ReleasePoolImpl {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
owned: ArrayList::new(),
|
||||
borrowed: ArrayList::new(),
|
||||
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 {
|
||||
value: UnsafeCell<Option<ReleasePoolImpl>>,
|
||||
}
|
||||
|
||||
impl ReleasePool {
|
||||
const fn new() -> Self {
|
||||
Self {
|
||||
value: UnsafeCell::new(None),
|
||||
}
|
||||
}
|
||||
/// # 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)
|
||||
}
|
||||
}
|
||||
|
||||
static POOL: ReleasePool = ReleasePool::new();
|
||||
|
||||
unsafe impl Sync for ReleasePool {}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub struct GILPool<'p> {
|
||||
py: Python<'p>,
|
||||
pub struct GILPool {
|
||||
owned: usize,
|
||||
borrowed: usize,
|
||||
// Stable solution for impl !Send
|
||||
no_send: Unsendable,
|
||||
}
|
||||
|
||||
impl<'p> GILPool<'p> {
|
||||
impl GILPool {
|
||||
/// # Safety
|
||||
/// This function requires that GIL is already acquired.
|
||||
#[inline]
|
||||
pub fn new(py: Python) -> GILPool {
|
||||
pub unsafe fn new() -> GILPool {
|
||||
increment_gil_count();
|
||||
let p: &'static mut ReleasePool = unsafe { &mut *POOL };
|
||||
// Release objects that were dropped since last GIL acquisition
|
||||
let pool = POOL.get_or_init();
|
||||
pool.release_pointers();
|
||||
GILPool {
|
||||
py,
|
||||
owned: p.owned.len(),
|
||||
borrowed: p.borrowed.len(),
|
||||
owned: pool.owned.len(),
|
||||
borrowed: pool.borrowed.len(),
|
||||
no_send: Unsendable::default(),
|
||||
}
|
||||
}
|
||||
pub unsafe fn python(&self) -> Python {
|
||||
Python::assume_gil_acquired()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'p> Drop for GILPool<'p> {
|
||||
impl Drop for GILPool {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
let pool: &'static mut ReleasePool = &mut *POOL;
|
||||
pool.drain(self.py, self.owned, self.borrowed);
|
||||
let pool = POOL.get_or_init();
|
||||
pool.drain(self.python(), self.owned, self.borrowed);
|
||||
}
|
||||
decrement_gil_count();
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
@ -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>) {
|
||||
let pool = &mut *POOL;
|
||||
let pool = POOL.get_or_init();
|
||||
if gil_is_acquired() {
|
||||
ffi::Py_DECREF(obj.as_ptr())
|
||||
} 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 {
|
||||
let pool = &mut *POOL;
|
||||
let pool = POOL.get_or_init();
|
||||
&*(pool.owned.push_back(obj) as *const _ as *const 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)
|
||||
}
|
||||
|
||||
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.
|
||||
#[inline(always)]
|
||||
fn increment_gil_count() {
|
||||
|
@ -361,7 +362,7 @@ mod array_list {
|
|||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::{GILPool, NonNull, ReleasePool, GIL_COUNT, POOL};
|
||||
use super::{GILPool, NonNull, GIL_COUNT, POOL};
|
||||
use crate::object::PyObject;
|
||||
use crate::AsPyPointer;
|
||||
use crate::Python;
|
||||
|
@ -388,7 +389,7 @@ mod test {
|
|||
let _ref = obj.clone_ref(py);
|
||||
|
||||
unsafe {
|
||||
let p: &'static mut ReleasePool = &mut *POOL;
|
||||
let p = POOL.get_or_init();
|
||||
|
||||
{
|
||||
let gil = Python::acquire_gil();
|
||||
|
@ -416,10 +417,10 @@ mod test {
|
|||
let obj_ptr = obj.as_ptr();
|
||||
|
||||
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);
|
||||
|
||||
let _ = gil::register_owned(py, obj.into_nonnull());
|
||||
|
@ -427,7 +428,7 @@ mod test {
|
|||
assert_eq!(p.owned.len(), 1);
|
||||
assert_eq!(ffi::Py_REFCNT(obj_ptr), 2);
|
||||
{
|
||||
let _pool = GILPool::new(py);
|
||||
let _pool = GILPool::new();
|
||||
let obj = get_object();
|
||||
let _ = gil::register_owned(py, obj.into_nonnull());
|
||||
assert_eq!(p.owned.len(), 2);
|
||||
|
@ -443,9 +444,8 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_borrowed() {
|
||||
gil::init_once();
|
||||
unsafe {
|
||||
let p: &'static mut ReleasePool = &mut *POOL;
|
||||
let p = POOL.get_or_init();
|
||||
|
||||
let obj = get_object();
|
||||
let obj_ptr = obj.as_ptr();
|
||||
|
@ -469,9 +469,8 @@ mod test {
|
|||
|
||||
#[test]
|
||||
fn test_borrowed_nested() {
|
||||
gil::init_once();
|
||||
unsafe {
|
||||
let p: &'static mut ReleasePool = &mut *POOL;
|
||||
let p = POOL.get_or_init();
|
||||
|
||||
let obj = get_object();
|
||||
let obj_ptr = obj.as_ptr();
|
||||
|
@ -486,7 +485,7 @@ mod test {
|
|||
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
||||
|
||||
{
|
||||
let _pool = GILPool::new(py);
|
||||
let _pool = GILPool::new();
|
||||
assert_eq!(p.borrowed.len(), 1);
|
||||
gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap());
|
||||
assert_eq!(p.borrowed.len(), 2);
|
||||
|
@ -513,7 +512,7 @@ mod test {
|
|||
let obj_ptr = obj.as_ptr();
|
||||
|
||||
unsafe {
|
||||
let p: &'static mut ReleasePool = &mut *POOL;
|
||||
let p = POOL.get_or_init();
|
||||
|
||||
{
|
||||
assert_eq!(p.owned.len(), 0);
|
||||
|
@ -536,7 +535,7 @@ mod test {
|
|||
let obj_ptr = obj.as_ptr();
|
||||
|
||||
unsafe {
|
||||
let p: &'static mut ReleasePool = &mut *POOL;
|
||||
let p = POOL.get_or_init();
|
||||
|
||||
{
|
||||
assert_eq!(p.owned.len(), 0);
|
||||
|
@ -565,13 +564,11 @@ mod test {
|
|||
let gil = Python::acquire_gil();
|
||||
assert_eq!(get_gil_count(), 1);
|
||||
|
||||
let py = gil.python();
|
||||
|
||||
assert_eq!(get_gil_count(), 1);
|
||||
let pool = GILPool::new(py);
|
||||
let pool = unsafe { GILPool::new() };
|
||||
assert_eq!(get_gil_count(), 2);
|
||||
|
||||
let pool2 = GILPool::new(py);
|
||||
let pool2 = unsafe { GILPool::new() };
|
||||
assert_eq!(get_gil_count(), 3);
|
||||
|
||||
drop(pool);
|
||||
|
|
|
@ -140,7 +140,7 @@ pub use crate::conversion::{
|
|||
ToBorrowedObject, ToPyObject,
|
||||
};
|
||||
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::object::PyObject;
|
||||
pub use crate::objectprotocol::ObjectProtocol;
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
use crate::class::methods::{PyMethodDefType, PyMethodsProtocol};
|
||||
use crate::pyclass_slots::{PyClassDict, PyClassWeakRef};
|
||||
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::os::raw::c_void;
|
||||
use std::ptr;
|
||||
|
@ -111,8 +111,8 @@ where
|
|||
where
|
||||
T: PyClassAlloc,
|
||||
{
|
||||
let py = Python::assume_gil_acquired();
|
||||
let _pool = gil::GILPool::new(py);
|
||||
let pool = crate::GILPool::new();
|
||||
let py = pool.python();
|
||||
<T as PyClassAlloc>::dealloc(py, (obj as *mut T::Layout) as _)
|
||||
}
|
||||
type_object.tp_dealloc = Some(tp_dealloc_callback::<T>);
|
||||
|
|
|
@ -57,6 +57,10 @@ impl<'p> Python<'p> {
|
|||
/// 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`
|
||||
/// 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]
|
||||
pub unsafe fn assume_gil_acquired() -> Python<'p> {
|
||||
Python(PhantomData)
|
||||
|
|
|
@ -472,7 +472,7 @@ mod test {
|
|||
|
||||
let cnt;
|
||||
{
|
||||
let _pool = crate::GILPool::new(py);
|
||||
let _pool = unsafe { crate::GILPool::new() };
|
||||
let none = py.None();
|
||||
cnt = none.get_refcnt();
|
||||
let _dict = [(10, none)].into_py_dict(py);
|
||||
|
|
|
@ -137,7 +137,7 @@ mod tests {
|
|||
let none;
|
||||
let count;
|
||||
{
|
||||
let _pool = GILPool::new(py);
|
||||
let _pool = unsafe { GILPool::new() };
|
||||
let l = PyList::empty(py);
|
||||
none = py.None();
|
||||
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 mut it = inst.iter().unwrap();
|
||||
|
||||
|
|
|
@ -296,7 +296,7 @@ mod test {
|
|||
|
||||
let cnt;
|
||||
{
|
||||
let _pool = crate::GILPool::new(py);
|
||||
let _pool = unsafe { crate::GILPool::new() };
|
||||
let v = vec![2];
|
||||
let ob = v.to_object(py);
|
||||
let list = <PyList as PyTryFrom>::try_from(ob.as_ref(py)).unwrap();
|
||||
|
@ -331,7 +331,7 @@ mod test {
|
|||
|
||||
let cnt;
|
||||
{
|
||||
let _pool = crate::GILPool::new(py);
|
||||
let _pool = unsafe { crate::GILPool::new() };
|
||||
let list = PyList::empty(py);
|
||||
let none = py.None();
|
||||
cnt = none.get_refcnt();
|
||||
|
@ -360,7 +360,7 @@ mod test {
|
|||
|
||||
let cnt;
|
||||
{
|
||||
let _pool = crate::GILPool::new(py);
|
||||
let _pool = unsafe { crate::GILPool::new() };
|
||||
let list = PyList::empty(py);
|
||||
let none = py.None();
|
||||
cnt = none.get_refcnt();
|
||||
|
|
|
@ -7,4 +7,10 @@ fn test_compile_errors() {
|
|||
t.compile_fail("tests/ui/invalid_pymethod_names.rs");
|
||||
t.compile_fail("tests/ui/missing_clone.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
0
tests/test_datetime.rs
Executable file → Normal file
17
tests/ui/static_ref.rs
Normal file
17
tests/ui/static_ref.rs
Normal 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() {}
|
11
tests/ui/static_ref.stderr
Normal file
11
tests/ui/static_ref.stderr
Normal 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)
|
Loading…
Reference in a new issue