2017-06-20 21:10:12 +00:00
|
|
|
|
// Copyright (c) 2017-present PyO3 Project and Contributors
|
2019-02-23 17:01:22 +00:00
|
|
|
|
|
|
|
|
|
//! Interaction with python's global interpreter lock
|
|
|
|
|
|
2018-10-31 10:43:21 +00:00
|
|
|
|
use crate::ffi;
|
2019-03-04 04:50:43 +00:00
|
|
|
|
use crate::types::PyAny;
|
2019-02-23 17:01:22 +00:00
|
|
|
|
use crate::Python;
|
2018-09-11 20:38:31 +00:00
|
|
|
|
use spin;
|
2018-11-12 20:36:08 +00:00
|
|
|
|
use std::ptr::NonNull;
|
2018-09-11 20:38:31 +00:00
|
|
|
|
use std::{any, marker, rc, sync};
|
2015-01-05 16:05:53 +00:00
|
|
|
|
|
2019-07-07 09:52:25 +00:00
|
|
|
|
static START: sync::Once = sync::Once::new();
|
|
|
|
|
static START_PYO3: sync::Once = sync::Once::new();
|
2015-01-05 16:05:53 +00:00
|
|
|
|
|
2015-06-27 20:45:35 +00:00
|
|
|
|
/// Prepares the use of Python in a free-threaded context.
|
2015-04-18 20:20:19 +00:00
|
|
|
|
///
|
2015-06-27 20:45:35 +00:00
|
|
|
|
/// If the Python interpreter is not already initialized, this function
|
2015-04-18 20:20:19 +00:00
|
|
|
|
/// will initialize it with disabled signal handling
|
2015-06-27 20:45:35 +00:00
|
|
|
|
/// (Python will not raise the `KeyboardInterrupt` exception).
|
2015-04-18 20:20:19 +00:00
|
|
|
|
/// Python signal handling depends on the notion of a 'main thread', which must be
|
2015-06-27 20:45:35 +00:00
|
|
|
|
/// the thread that initializes the Python interpreter.
|
|
|
|
|
///
|
|
|
|
|
/// If both the Python interpreter and Python threading are already initialized,
|
|
|
|
|
/// this function has no effect.
|
|
|
|
|
///
|
|
|
|
|
/// # Panic
|
|
|
|
|
/// If the Python interpreter is initialized but Python threading is not,
|
|
|
|
|
/// a panic occurs.
|
|
|
|
|
/// It is not possible to safely access the Python runtime unless the main
|
|
|
|
|
/// thread (the thread which originally initialized Python) also initializes
|
|
|
|
|
/// threading.
|
|
|
|
|
///
|
2018-11-12 21:28:45 +00:00
|
|
|
|
/// When writing an extension module, the `#[pymodule]` macro
|
2015-06-27 20:45:35 +00:00
|
|
|
|
/// will ensure that Python threading is initialized.
|
|
|
|
|
///
|
2015-01-04 04:50:28 +00:00
|
|
|
|
pub fn prepare_freethreaded_python() {
|
2015-06-27 20:45:35 +00:00
|
|
|
|
// Protect against race conditions when Python is not yet initialized
|
2015-01-04 19:11:18 +00:00
|
|
|
|
// and multiple threads concurrently call 'prepare_freethreaded_python()'.
|
2015-06-27 20:45:35 +00:00
|
|
|
|
// Note that we do not protect against concurrent initialization of the Python runtime
|
|
|
|
|
// by other users of the Python C API.
|
2015-01-04 04:50:28 +00:00
|
|
|
|
START.call_once(|| unsafe {
|
2015-01-04 19:11:18 +00:00
|
|
|
|
if ffi::Py_IsInitialized() != 0 {
|
2015-06-27 20:45:35 +00:00
|
|
|
|
// If Python is already initialized, we expect Python threading to also be initialized,
|
|
|
|
|
// as we can't make the existing Python main thread acquire the GIL.
|
2019-04-23 11:18:42 +00:00
|
|
|
|
#[cfg(not(Py_3_7))]
|
2017-07-18 11:28:49 +00:00
|
|
|
|
assert_ne!(ffi::PyEval_ThreadsInitialized(), 0);
|
2015-01-04 19:11:18 +00:00
|
|
|
|
} else {
|
2018-02-21 18:06:48 +00:00
|
|
|
|
// If Python isn't initialized yet, we expect that Python threading
|
|
|
|
|
// isn't initialized either.
|
2018-02-21 18:29:14 +00:00
|
|
|
|
#[cfg(not(Py_3_7))]
|
2018-02-21 18:06:48 +00:00
|
|
|
|
assert_eq!(ffi::PyEval_ThreadsInitialized(), 0);
|
2015-06-27 20:45:35 +00:00
|
|
|
|
// Initialize Python.
|
2015-01-04 19:11:18 +00:00
|
|
|
|
// We use Py_InitializeEx() with initsigs=0 to disable Python signal handling.
|
|
|
|
|
// Signal handling depends on the notion of a 'main thread', which doesn't exist in this case.
|
2015-06-27 20:45:35 +00:00
|
|
|
|
// Note that the 'main thread' notion in Python isn't documented properly;
|
|
|
|
|
// and running Python without one is not officially supported.
|
2019-04-23 11:18:42 +00:00
|
|
|
|
|
|
|
|
|
// PyPy does not support the embedding API
|
|
|
|
|
#[cfg(not(PyPy))]
|
2015-01-04 19:11:18 +00:00
|
|
|
|
ffi::Py_InitializeEx(0);
|
2019-04-23 11:18:42 +00:00
|
|
|
|
|
|
|
|
|
// > Changed in version 3.7: This function is now called by Py_Initialize(), so you don’t have
|
|
|
|
|
// > to call it yourself anymore.
|
|
|
|
|
#[cfg(not(Py_3_7))]
|
2015-01-04 19:11:18 +00:00
|
|
|
|
ffi::PyEval_InitThreads();
|
|
|
|
|
// PyEval_InitThreads() will acquire the GIL,
|
|
|
|
|
// but we don't want to hold it at this point
|
2015-01-04 04:50:28 +00:00
|
|
|
|
// (it's not acquired in the other code paths)
|
2015-01-04 19:11:18 +00:00
|
|
|
|
// So immediately release the GIL:
|
2019-04-23 11:18:42 +00:00
|
|
|
|
#[cfg(not(PyPy))]
|
2015-01-04 19:11:18 +00:00
|
|
|
|
let _thread_state = ffi::PyEval_SaveThread();
|
2015-06-27 20:45:35 +00:00
|
|
|
|
// Note that the PyThreadState returned by PyEval_SaveThread is also held in TLS by the Python runtime,
|
2015-01-04 19:11:18 +00:00
|
|
|
|
// and will be restored by PyGILState_Ensure.
|
2015-01-04 04:50:28 +00:00
|
|
|
|
}
|
2017-06-21 06:26:28 +00:00
|
|
|
|
|
2018-07-03 19:12:57 +00:00
|
|
|
|
init_once();
|
2017-06-23 18:51:15 +00:00
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[doc(hidden)]
|
2018-07-03 19:12:57 +00:00
|
|
|
|
pub fn init_once() {
|
2017-06-23 18:51:15 +00:00
|
|
|
|
START_PYO3.call_once(|| unsafe {
|
2017-06-21 06:26:28 +00:00
|
|
|
|
// initialize release pool
|
2017-07-18 18:12:35 +00:00
|
|
|
|
POOL = Box::into_raw(Box::new(ReleasePool::new()));
|
2015-01-04 04:50:28 +00:00
|
|
|
|
});
|
2015-01-05 16:05:53 +00:00
|
|
|
|
}
|
|
|
|
|
|
2016-03-05 16:41:04 +00:00
|
|
|
|
/// RAII type that represents the Global Interpreter Lock acquisition.
|
2015-06-27 20:45:35 +00:00
|
|
|
|
///
|
|
|
|
|
/// # Example
|
|
|
|
|
/// ```
|
2017-05-13 05:43:17 +00:00
|
|
|
|
/// use pyo3::Python;
|
2015-06-27 20:45:35 +00:00
|
|
|
|
///
|
|
|
|
|
/// {
|
|
|
|
|
/// let gil_guard = Python::acquire_gil();
|
|
|
|
|
/// let py = gil_guard.python();
|
|
|
|
|
/// } // GIL is released when gil_guard is dropped
|
|
|
|
|
/// ```
|
2015-01-04 23:07:31 +00:00
|
|
|
|
#[must_use]
|
|
|
|
|
pub struct GILGuard {
|
2017-06-23 20:42:46 +00:00
|
|
|
|
owned: usize,
|
|
|
|
|
borrowed: usize,
|
2016-03-05 23:22:16 +00:00
|
|
|
|
gstate: ffi::PyGILState_STATE,
|
|
|
|
|
// hack to opt out of Send on stable rust, which doesn't
|
|
|
|
|
// have negative impls
|
2018-07-30 21:01:46 +00:00
|
|
|
|
no_send: marker::PhantomData<rc::Rc<()>>,
|
2015-01-04 23:07:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-06-11 15:46:23 +00:00
|
|
|
|
/// The Drop implementation for `GILGuard` will release the GIL.
|
2015-01-04 23:07:31 +00:00
|
|
|
|
impl Drop for GILGuard {
|
|
|
|
|
fn drop(&mut self) {
|
2017-06-21 06:26:28 +00:00
|
|
|
|
unsafe {
|
2017-07-18 18:12:35 +00:00
|
|
|
|
let pool: &'static mut ReleasePool = &mut *POOL;
|
2019-08-30 06:46:37 +00:00
|
|
|
|
pool.drain(self.python(), self.owned, self.borrowed, true);
|
2017-06-21 06:26:28 +00:00
|
|
|
|
|
|
|
|
|
ffi::PyGILState_Release(self.gstate);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-18 18:12:35 +00:00
|
|
|
|
/// Release pool
|
|
|
|
|
struct ReleasePool {
|
2018-11-18 10:15:40 +00:00
|
|
|
|
owned: ArrayList<NonNull<ffi::PyObject>>,
|
|
|
|
|
borrowed: ArrayList<NonNull<ffi::PyObject>>,
|
2018-11-14 06:39:07 +00:00
|
|
|
|
pointers: *mut Vec<NonNull<ffi::PyObject>>,
|
2019-06-05 10:01:09 +00:00
|
|
|
|
obj: Vec<Box<dyn any::Any>>,
|
2018-11-14 06:39:07 +00:00
|
|
|
|
p: spin::Mutex<*mut Vec<NonNull<ffi::PyObject>>>,
|
2017-07-09 06:08:57 +00:00
|
|
|
|
}
|
|
|
|
|
|
2017-07-18 18:12:35 +00:00
|
|
|
|
impl ReleasePool {
|
|
|
|
|
fn new() -> ReleasePool {
|
|
|
|
|
ReleasePool {
|
2018-11-18 10:15:40 +00:00
|
|
|
|
owned: ArrayList::new(),
|
|
|
|
|
borrowed: ArrayList::new(),
|
2018-01-19 17:04:42 +00:00
|
|
|
|
pointers: Box::into_raw(Box::new(Vec::with_capacity(256))),
|
2018-11-20 07:21:36 +00:00
|
|
|
|
obj: Vec::with_capacity(8),
|
2018-01-19 17:04:42 +00:00
|
|
|
|
p: spin::Mutex::new(Box::into_raw(Box::new(Vec::with_capacity(256)))),
|
2017-07-09 06:08:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
unsafe fn release_pointers(&mut self) {
|
|
|
|
|
let mut v = self.p.lock();
|
2018-11-18 14:14:00 +00:00
|
|
|
|
let vec = &mut **v;
|
2017-07-13 20:01:31 +00:00
|
|
|
|
if vec.is_empty() {
|
2018-07-30 21:01:46 +00:00
|
|
|
|
return;
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// switch vectors
|
2018-11-18 14:14:00 +00:00
|
|
|
|
std::mem::swap(&mut self.pointers, &mut *v);
|
2017-07-09 06:08:57 +00:00
|
|
|
|
drop(v);
|
|
|
|
|
|
2018-11-18 14:14:00 +00:00
|
|
|
|
// release PyObjects
|
2018-11-20 07:21:36 +00:00
|
|
|
|
for ptr in vec.iter_mut() {
|
2018-11-14 06:39:07 +00:00
|
|
|
|
ffi::Py_DECREF(ptr.as_ptr());
|
2017-07-09 06:08:57 +00:00
|
|
|
|
}
|
|
|
|
|
vec.set_len(0);
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-30 06:46:37 +00:00
|
|
|
|
pub unsafe fn drain(&mut self, _py: Python, owned: usize, borrowed: usize, pointers: bool) {
|
2018-11-18 13:10:13 +00:00
|
|
|
|
// Release owned objects(call decref)
|
2018-11-18 03:13:20 +00:00
|
|
|
|
while owned < self.owned.len() {
|
|
|
|
|
let last = self.owned.pop_back().unwrap();
|
|
|
|
|
ffi::Py_DECREF(last.as_ptr());
|
2017-07-09 06:08:57 +00:00
|
|
|
|
}
|
2018-11-18 13:10:13 +00:00
|
|
|
|
// Release borrowed objects(don't call decref)
|
|
|
|
|
self.borrowed.truncate(borrowed);
|
2017-07-09 06:08:57 +00:00
|
|
|
|
|
2017-07-13 20:01:31 +00:00
|
|
|
|
if pointers {
|
|
|
|
|
self.release_pointers();
|
|
|
|
|
}
|
2018-01-19 17:04:42 +00:00
|
|
|
|
|
|
|
|
|
self.obj.clear();
|
2017-07-09 06:08:57 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-18 18:12:35 +00:00
|
|
|
|
static mut POOL: *mut ReleasePool = ::std::ptr::null_mut();
|
2017-06-21 06:26:28 +00:00
|
|
|
|
|
2017-07-20 21:21:57 +00:00
|
|
|
|
#[doc(hidden)]
|
2019-08-30 06:46:37 +00:00
|
|
|
|
pub struct GILPool<'p> {
|
|
|
|
|
py: Python<'p>,
|
2017-06-23 20:42:46 +00:00
|
|
|
|
owned: usize,
|
|
|
|
|
borrowed: usize,
|
2017-07-13 20:01:31 +00:00
|
|
|
|
pointers: bool,
|
2017-06-22 17:26:07 +00:00
|
|
|
|
no_send: marker::PhantomData<rc::Rc<()>>,
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-30 06:46:37 +00:00
|
|
|
|
impl<'p> GILPool<'p> {
|
2017-06-22 19:32:01 +00:00
|
|
|
|
#[inline]
|
2019-08-30 06:46:37 +00:00
|
|
|
|
pub fn new(py: Python) -> GILPool {
|
2017-08-03 18:37:24 +00:00
|
|
|
|
let p: &'static mut ReleasePool = unsafe { &mut *POOL };
|
2018-07-30 21:01:46 +00:00
|
|
|
|
GILPool {
|
2019-08-30 06:46:37 +00:00
|
|
|
|
py,
|
2018-07-30 21:01:46 +00:00
|
|
|
|
owned: p.owned.len(),
|
|
|
|
|
borrowed: p.borrowed.len(),
|
|
|
|
|
pointers: true,
|
|
|
|
|
no_send: marker::PhantomData,
|
|
|
|
|
}
|
2017-07-09 18:37:20 +00:00
|
|
|
|
}
|
2017-07-13 20:01:31 +00:00
|
|
|
|
#[inline]
|
2019-08-30 06:46:37 +00:00
|
|
|
|
pub fn new_no_pointers(py: Python) -> GILPool {
|
2017-08-03 18:37:24 +00:00
|
|
|
|
let p: &'static mut ReleasePool = unsafe { &mut *POOL };
|
2018-07-30 21:01:46 +00:00
|
|
|
|
GILPool {
|
2019-08-30 06:46:37 +00:00
|
|
|
|
py,
|
2018-07-30 21:01:46 +00:00
|
|
|
|
owned: p.owned.len(),
|
|
|
|
|
borrowed: p.borrowed.len(),
|
|
|
|
|
pointers: false,
|
|
|
|
|
no_send: marker::PhantomData,
|
|
|
|
|
}
|
2017-06-22 17:26:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-08-30 06:46:37 +00:00
|
|
|
|
impl<'p> Drop for GILPool<'p> {
|
2017-06-22 17:26:07 +00:00
|
|
|
|
fn drop(&mut self) {
|
|
|
|
|
unsafe {
|
2017-07-18 18:12:35 +00:00
|
|
|
|
let pool: &'static mut ReleasePool = &mut *POOL;
|
2019-08-30 06:46:37 +00:00
|
|
|
|
pool.drain(self.py, self.owned, self.borrowed, self.pointers);
|
2017-06-22 17:26:07 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-07-30 21:01:46 +00:00
|
|
|
|
pub unsafe fn register_any<'p, T: 'static>(obj: T) -> &'p T {
|
2018-01-19 17:04:42 +00:00
|
|
|
|
let pool: &'static mut ReleasePool = &mut *POOL;
|
|
|
|
|
|
2018-11-18 10:15:40 +00:00
|
|
|
|
pool.obj.push(Box::new(obj));
|
2018-07-30 21:01:46 +00:00
|
|
|
|
pool.obj
|
2018-11-18 10:15:40 +00:00
|
|
|
|
.last()
|
2018-07-30 21:01:46 +00:00
|
|
|
|
.unwrap()
|
|
|
|
|
.as_ref()
|
|
|
|
|
.downcast_ref::<T>()
|
|
|
|
|
.unwrap()
|
2018-01-19 17:04:42 +00:00
|
|
|
|
}
|
|
|
|
|
|
2018-11-12 20:36:08 +00:00
|
|
|
|
pub unsafe fn register_pointer(obj: NonNull<ffi::PyObject>) {
|
2018-11-18 14:14:00 +00:00
|
|
|
|
let pool = &mut *POOL;
|
|
|
|
|
(**pool.p.lock()).push(obj);
|
2017-06-22 17:26:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-04 04:50:43 +00:00
|
|
|
|
pub unsafe fn register_owned(_py: Python, obj: NonNull<ffi::PyObject>) -> &PyAny {
|
2018-11-18 14:14:00 +00:00
|
|
|
|
let pool = &mut *POOL;
|
2019-03-04 04:50:43 +00:00
|
|
|
|
&*(pool.owned.push_back(obj) as *const _ as *const PyAny)
|
2017-06-23 20:42:46 +00:00
|
|
|
|
}
|
2017-06-22 17:26:07 +00:00
|
|
|
|
|
2019-03-04 04:50:43 +00:00
|
|
|
|
pub unsafe fn register_borrowed(_py: Python, obj: NonNull<ffi::PyObject>) -> &PyAny {
|
2018-11-18 14:14:00 +00:00
|
|
|
|
let pool = &mut *POOL;
|
2019-03-04 04:50:43 +00:00
|
|
|
|
&*(pool.borrowed.push_back(obj) as *const _ as *const PyAny)
|
2015-01-04 23:07:31 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl GILGuard {
|
|
|
|
|
/// Acquires the global interpreter lock, which allows access to the Python runtime.
|
2015-06-27 20:45:35 +00:00
|
|
|
|
///
|
|
|
|
|
/// If the Python runtime is not already initialized, this function will initialize it.
|
|
|
|
|
/// See [prepare_freethreaded_python()](fn.prepare_freethreaded_python.html) for details.
|
2015-01-04 23:07:31 +00:00
|
|
|
|
pub fn acquire() -> GILGuard {
|
2017-06-23 20:42:46 +00:00
|
|
|
|
prepare_freethreaded_python();
|
2017-06-21 06:26:28 +00:00
|
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
|
let gstate = ffi::PyGILState_Ensure(); // acquire GIL
|
2017-07-18 18:12:35 +00:00
|
|
|
|
let pool: &'static mut ReleasePool = &mut *POOL;
|
2018-07-30 21:01:46 +00:00
|
|
|
|
GILGuard {
|
|
|
|
|
owned: pool.owned.len(),
|
|
|
|
|
borrowed: pool.borrowed.len(),
|
|
|
|
|
gstate,
|
|
|
|
|
no_send: marker::PhantomData,
|
|
|
|
|
}
|
2017-06-21 06:26:28 +00:00
|
|
|
|
}
|
2015-01-04 23:07:31 +00:00
|
|
|
|
}
|
2015-04-18 20:20:19 +00:00
|
|
|
|
|
|
|
|
|
/// Retrieves the marker type that proves that the GIL was acquired.
|
2015-06-21 22:35:01 +00:00
|
|
|
|
#[inline]
|
2017-07-18 11:28:49 +00:00
|
|
|
|
pub fn python(&self) -> Python {
|
2015-01-04 23:07:31 +00:00
|
|
|
|
unsafe { Python::assume_gil_acquired() }
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
2018-11-18 10:15:40 +00:00
|
|
|
|
use self::array_list::ArrayList;
|
|
|
|
|
|
|
|
|
|
mod array_list {
|
|
|
|
|
use std::collections::LinkedList;
|
|
|
|
|
const BLOCK_SIZE: usize = 256;
|
2018-11-18 13:10:13 +00:00
|
|
|
|
|
|
|
|
|
/// A container type for Release Pool
|
|
|
|
|
/// See #271 for why this is crated
|
2018-11-18 10:15:40 +00:00
|
|
|
|
pub(super) struct ArrayList<T> {
|
2019-07-15 04:32:18 +00:00
|
|
|
|
inner: LinkedList<[Option<T>; BLOCK_SIZE]>,
|
2018-11-18 10:15:40 +00:00
|
|
|
|
length: usize,
|
|
|
|
|
}
|
|
|
|
|
|
2019-07-15 04:32:18 +00:00
|
|
|
|
impl<T: Copy> ArrayList<T> {
|
2018-11-18 10:15:40 +00:00
|
|
|
|
pub fn new() -> Self {
|
|
|
|
|
ArrayList {
|
2018-11-18 13:10:13 +00:00
|
|
|
|
inner: LinkedList::new(),
|
2018-11-18 10:15:40 +00:00
|
|
|
|
length: 0,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
pub fn push_back(&mut self, item: T) -> &T {
|
2018-11-18 15:26:02 +00:00
|
|
|
|
let next_idx = self.next_idx();
|
|
|
|
|
if next_idx == 0 {
|
2019-07-15 04:32:18 +00:00
|
|
|
|
self.inner.push_back([None; BLOCK_SIZE]);
|
2018-11-18 10:15:40 +00:00
|
|
|
|
}
|
2019-07-15 04:32:18 +00:00
|
|
|
|
self.inner.back_mut().unwrap()[next_idx] = Some(item);
|
2018-11-18 10:15:40 +00:00
|
|
|
|
self.length += 1;
|
2019-07-15 04:32:18 +00:00
|
|
|
|
self.inner.back().unwrap()[next_idx].as_ref().unwrap()
|
2018-11-18 10:15:40 +00:00
|
|
|
|
}
|
2018-11-18 15:26:02 +00:00
|
|
|
|
pub fn pop_back(&mut self) -> Option<T> {
|
2018-11-18 10:15:40 +00:00
|
|
|
|
self.length -= 1;
|
2018-11-18 15:26:02 +00:00
|
|
|
|
let current_idx = self.next_idx();
|
2018-12-26 11:18:02 +00:00
|
|
|
|
if current_idx == 0 {
|
2018-11-18 15:26:02 +00:00
|
|
|
|
let last_list = self.inner.pop_back()?;
|
2019-07-15 04:32:18 +00:00
|
|
|
|
return last_list[0];
|
2018-11-18 15:26:02 +00:00
|
|
|
|
}
|
2019-07-15 04:32:18 +00:00
|
|
|
|
self.inner.back().and_then(|arr| arr[current_idx])
|
2018-11-18 10:15:40 +00:00
|
|
|
|
}
|
|
|
|
|
pub fn len(&self) -> usize {
|
|
|
|
|
self.length
|
|
|
|
|
}
|
2018-11-18 13:10:13 +00:00
|
|
|
|
pub fn truncate(&mut self, new_len: usize) {
|
|
|
|
|
if self.length <= new_len {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2018-11-20 07:21:36 +00:00
|
|
|
|
while self.inner.len() > (new_len + BLOCK_SIZE - 1) / BLOCK_SIZE {
|
2018-11-18 13:10:13 +00:00
|
|
|
|
self.inner.pop_back();
|
|
|
|
|
}
|
|
|
|
|
self.length = new_len;
|
|
|
|
|
}
|
2018-11-18 15:26:02 +00:00
|
|
|
|
fn next_idx(&self) -> usize {
|
2018-11-18 13:10:13 +00:00
|
|
|
|
self.length % BLOCK_SIZE
|
|
|
|
|
}
|
2018-11-18 10:15:40 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-13 20:01:31 +00:00
|
|
|
|
#[cfg(test)]
|
|
|
|
|
mod test {
|
2018-11-15 20:58:22 +00:00
|
|
|
|
use super::{GILPool, NonNull, ReleasePool, POOL};
|
2018-10-31 10:43:21 +00:00
|
|
|
|
use crate::object::PyObject;
|
2019-02-24 07:17:44 +00:00
|
|
|
|
use crate::AsPyPointer;
|
2019-02-23 17:01:22 +00:00
|
|
|
|
use crate::Python;
|
|
|
|
|
use crate::ToPyObject;
|
|
|
|
|
use crate::{ffi, gil};
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
2018-08-22 00:16:25 +00:00
|
|
|
|
fn get_object() -> PyObject {
|
|
|
|
|
// Convenience function for getting a single unique object
|
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
|
let py = gil.python();
|
|
|
|
|
|
|
|
|
|
let obj = py.eval("object()", None, None).unwrap();
|
|
|
|
|
|
|
|
|
|
obj.to_object(py)
|
|
|
|
|
}
|
|
|
|
|
|
2017-07-13 20:01:31 +00:00
|
|
|
|
#[test]
|
|
|
|
|
fn test_owned() {
|
2019-02-23 17:01:22 +00:00
|
|
|
|
gil::init_once();
|
2019-03-09 23:28:25 +00:00
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
|
let py = gil.python();
|
|
|
|
|
let obj = get_object();
|
|
|
|
|
let obj_ptr = obj.as_ptr();
|
|
|
|
|
// Ensure that obj does not get freed
|
|
|
|
|
let _ref = obj.clone_ref(py);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
unsafe {
|
2017-07-18 18:12:35 +00:00
|
|
|
|
let p: &'static mut ReleasePool = &mut *POOL;
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
|
let py = gil.python();
|
2019-03-09 23:28:25 +00:00
|
|
|
|
let _ = gil::register_owned(py, obj.into_nonnull());
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 2);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
assert_eq!(p.owned.len(), 1);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
let _gil = Python::acquire_gil();
|
|
|
|
|
assert_eq!(p.owned.len(), 0);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_owned_nested() {
|
2019-02-23 17:01:22 +00:00
|
|
|
|
gil::init_once();
|
2017-08-08 06:52:24 +00:00
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
|
let py = gil.python();
|
2019-03-09 23:28:25 +00:00
|
|
|
|
let obj = get_object();
|
|
|
|
|
// Ensure that obj does not get freed
|
|
|
|
|
let _ref = obj.clone_ref(py);
|
|
|
|
|
let obj_ptr = obj.as_ptr();
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
unsafe {
|
2017-07-18 18:12:35 +00:00
|
|
|
|
let p: &'static mut ReleasePool = &mut *POOL;
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
{
|
2019-08-30 06:46:37 +00:00
|
|
|
|
let _pool = GILPool::new(py);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
assert_eq!(p.owned.len(), 0);
|
|
|
|
|
|
2019-03-09 23:28:25 +00:00
|
|
|
|
let _ = gil::register_owned(py, obj.into_nonnull());
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
assert_eq!(p.owned.len(), 1);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 2);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
{
|
2019-08-30 06:46:37 +00:00
|
|
|
|
let _pool = GILPool::new(py);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
let obj = get_object();
|
|
|
|
|
let _ = gil::register_owned(py, obj.into_nonnull());
|
2017-07-13 20:01:31 +00:00
|
|
|
|
assert_eq!(p.owned.len(), 2);
|
|
|
|
|
}
|
|
|
|
|
assert_eq!(p.owned.len(), 1);
|
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
assert_eq!(p.owned.len(), 0);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_borrowed() {
|
2019-02-23 17:01:22 +00:00
|
|
|
|
gil::init_once();
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
unsafe {
|
2017-07-18 18:12:35 +00:00
|
|
|
|
let p: &'static mut ReleasePool = &mut *POOL;
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
2018-08-22 00:16:25 +00:00
|
|
|
|
let obj = get_object();
|
|
|
|
|
let obj_ptr = obj.as_ptr();
|
2017-07-13 20:01:31 +00:00
|
|
|
|
{
|
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
|
let py = gil.python();
|
|
|
|
|
assert_eq!(p.borrowed.len(), 0);
|
|
|
|
|
|
2019-02-23 17:01:22 +00:00
|
|
|
|
gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap());
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
assert_eq!(p.borrowed.len(), 1);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
let _gil = Python::acquire_gil();
|
|
|
|
|
assert_eq!(p.borrowed.len(), 0);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_borrowed_nested() {
|
2019-02-23 17:01:22 +00:00
|
|
|
|
gil::init_once();
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
unsafe {
|
2017-07-18 18:12:35 +00:00
|
|
|
|
let p: &'static mut ReleasePool = &mut *POOL;
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
2018-08-22 00:16:25 +00:00
|
|
|
|
let obj = get_object();
|
|
|
|
|
let obj_ptr = obj.as_ptr();
|
2017-07-13 20:01:31 +00:00
|
|
|
|
{
|
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
|
let py = gil.python();
|
|
|
|
|
assert_eq!(p.borrowed.len(), 0);
|
|
|
|
|
|
2019-02-23 17:01:22 +00:00
|
|
|
|
gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap());
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
assert_eq!(p.borrowed.len(), 1);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
{
|
2019-08-30 06:46:37 +00:00
|
|
|
|
let _pool = GILPool::new(py);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
assert_eq!(p.borrowed.len(), 1);
|
2019-02-23 17:01:22 +00:00
|
|
|
|
gil::register_borrowed(py, NonNull::new(obj_ptr).unwrap());
|
2017-07-13 20:01:31 +00:00
|
|
|
|
assert_eq!(p.borrowed.len(), 2);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
assert_eq!(p.borrowed.len(), 1);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
|
|
|
|
{
|
|
|
|
|
let _gil = Python::acquire_gil();
|
|
|
|
|
assert_eq!(p.borrowed.len(), 0);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
|
fn test_pyobject_drop() {
|
2019-02-23 17:01:22 +00:00
|
|
|
|
gil::init_once();
|
2019-03-09 23:28:25 +00:00
|
|
|
|
let gil = Python::acquire_gil();
|
|
|
|
|
let py = gil.python();
|
|
|
|
|
let obj = get_object();
|
|
|
|
|
// Ensure that obj does not get freed
|
|
|
|
|
let _ref = obj.clone_ref(py);
|
|
|
|
|
let obj_ptr = obj.as_ptr();
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
unsafe {
|
2017-07-18 18:12:35 +00:00
|
|
|
|
let p: &'static mut ReleasePool = &mut *POOL;
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
assert_eq!(p.owned.len(), 0);
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 2);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
2019-03-05 20:52:44 +00:00
|
|
|
|
drop(obj);
|
2019-04-24 20:41:59 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 2);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
let _gil = Python::acquire_gil();
|
|
|
|
|
}
|
2019-03-09 23:28:25 +00:00
|
|
|
|
assert_eq!(ffi::Py_REFCNT(obj_ptr), 1);
|
2017-07-13 20:01:31 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|