fix pointer release list

This commit is contained in:
Nikolay Kim 2017-07-10 00:37:20 +06:00
parent c1c4648add
commit ce05cb91c0
3 changed files with 50 additions and 35 deletions

View File

@ -71,8 +71,6 @@ pub fn prepare_pyo3_library() {
START_PYO3.call_once(|| unsafe { START_PYO3.call_once(|| unsafe {
// initialize release pool // initialize release pool
POINTERS = Box::into_raw(Box::new(Pointers::new())); POINTERS = Box::into_raw(Box::new(Pointers::new()));
let p: &'static mut Pointers = mem::transmute(POINTERS);
p.init();
}); });
} }
@ -111,6 +109,7 @@ impl Drop for GILGuard {
struct Pointers { struct Pointers {
rc: usize,
owned: Vec<*mut ffi::PyObject>, owned: Vec<*mut ffi::PyObject>,
borrowed: Vec<*mut ffi::PyObject>, borrowed: Vec<*mut ffi::PyObject>,
pointers: *mut Vec<*mut ffi::PyObject>, pointers: *mut Vec<*mut ffi::PyObject>,
@ -120,16 +119,13 @@ struct Pointers {
impl Pointers { impl Pointers {
fn new() -> Pointers { fn new() -> Pointers {
Pointers { Pointers {
rc: 0,
owned: Vec::with_capacity(250), owned: Vec::with_capacity(250),
borrowed: Vec::with_capacity(250), borrowed: Vec::with_capacity(250),
pointers: Box::into_raw(Box::new(Vec::with_capacity(250))), pointers: Box::into_raw(Box::new(Vec::with_capacity(250))),
p: spin::Mutex::new(0 as *mut _), p: spin::Mutex::new(Box::into_raw(Box::new(Vec::with_capacity(250)))),
} }
} }
fn init(&mut self) {
let v = Box::into_raw(Box::new(Vec::with_capacity(250)));
*self.p.lock() = v;
}
unsafe fn release_pointers(&mut self) { unsafe fn release_pointers(&mut self) {
let mut v = self.p.lock(); let mut v = self.p.lock();
@ -161,6 +157,8 @@ impl Pointers {
} }
self.release_pointers(); self.release_pointers();
self.rc -= 1;
} }
} }
@ -176,9 +174,18 @@ impl Pool {
#[inline] #[inline]
pub unsafe fn new() -> Pool { pub unsafe fn new() -> Pool {
let p: &'static mut Pointers = mem::transmute(POINTERS); let p: &'static mut Pointers = mem::transmute(POINTERS);
Pool{ owned: p.owned.len(), p.rc += 1;
Pool {owned: p.owned.len(),
borrowed: p.borrowed.len(), borrowed: p.borrowed.len(),
no_send: marker::PhantomData } no_send: marker::PhantomData}
}
pub unsafe fn new_if_needed() -> Option<Pool> {
let p: &'static mut Pointers = mem::transmute(POINTERS);
if p.rc == 0 {
Some(Pool::new())
} else {
None
}
} }
} }
@ -226,6 +233,7 @@ impl GILGuard {
unsafe { unsafe {
let gstate = ffi::PyGILState_Ensure(); // acquire GIL let gstate = ffi::PyGILState_Ensure(); // acquire GIL
let pool: &'static mut Pointers = mem::transmute(POINTERS); let pool: &'static mut Pointers = mem::transmute(POINTERS);
pool.rc += 1;
GILGuard { owned: pool.owned.len(), GILGuard { owned: pool.owned.len(),
borrowed: pool.borrowed.len(), borrowed: pool.borrowed.len(),

View File

@ -279,7 +279,7 @@ unsafe extern "C" fn tp_dealloc_callback<T>(obj: *mut ffi::PyObject)
debug!("DEALLOC: {:?} - {:?}", obj, debug!("DEALLOC: {:?} - {:?}", obj,
CStr::from_ptr((*(*obj).ob_type).tp_name).to_string_lossy()); CStr::from_ptr((*(*obj).ob_type).tp_name).to_string_lossy());
let guard = AbortOnDrop("Cannot unwind out of tp_dealloc"); let guard = AbortOnDrop("Cannot unwind out of tp_dealloc");
let _pool = pythonrun::Pool::new(); let _pool = pythonrun::Pool::new_if_needed();
let py = Python::assume_gil_acquired(); let py = Python::assume_gil_acquired();
let r = <T as PyObjectAlloc<T>>::dealloc(py, obj); let r = <T as PyObjectAlloc<T>>::dealloc(py, obj);
mem::forget(guard); mem::forget(guard);

View File

@ -62,13 +62,9 @@ fn class_with_docstr() {
{ {
let gil = Python::acquire_gil(); let gil = Python::acquire_gil();
let py = gil.python(); let py = gil.python();
println!("TEST1");
let typeobj = py.get_type::<ClassWithDocs>(); let typeobj = py.get_type::<ClassWithDocs>();
println!("TEST2");
py_run!(py, typeobj, "assert typeobj.__doc__ == 'Line1\\nLine2\\n Line3'"); py_run!(py, typeobj, "assert typeobj.__doc__ == 'Line1\\nLine2\\n Line3'");
println!("TEST3");
} }
println!("TEST4");
} }
#[py::class(name=CustomName)] #[py::class(name=CustomName)]
@ -177,19 +173,27 @@ struct ClassWithFreelist{token: PyToken}
#[test] #[test]
fn class_with_freelist() { fn class_with_freelist() {
let gil = Python::acquire_gil(); let ptr;
let py = gil.python(); {
let gil = Python::acquire_gil();
let py = gil.python();
let inst = Py::new(py, |t| ClassWithFreelist{token: t}).unwrap(); let inst = Py::new(py, |t| ClassWithFreelist{token: t}).unwrap();
let inst2 = Py::new(py, |t| ClassWithFreelist{token: t}).unwrap(); let inst2 = Py::new(py, |t| ClassWithFreelist{token: t}).unwrap();
let ptr = inst.as_ptr(); ptr = inst.as_ptr();
drop(inst); drop(inst);
}
let inst3 = Py::new(py, |t| ClassWithFreelist{token: t}).unwrap(); {
assert_eq!(ptr, inst3.as_ptr()); let gil = Python::acquire_gil();
let py = gil.python();
let inst4 = Py::new(py, |t| ClassWithFreelist{token: t}).unwrap(); let inst3 = Py::new(py, |t| ClassWithFreelist{token: t}).unwrap();
assert_ne!(ptr, inst4.as_ptr()) assert_eq!(ptr, inst3.as_ptr());
let inst4 = Py::new(py, |t| ClassWithFreelist{token: t}).unwrap();
assert_ne!(ptr, inst4.as_ptr())
}
} }
struct TestDropCall { struct TestDropCall {
@ -210,19 +214,22 @@ struct DataIsDropped {
#[test] #[test]
fn data_is_dropped() { fn data_is_dropped() {
let gil = Python::acquire_gil();
let py = gil.python();
let drop_called1 = Arc::new(AtomicBool::new(false)); let drop_called1 = Arc::new(AtomicBool::new(false));
let drop_called2 = Arc::new(AtomicBool::new(false)); let drop_called2 = Arc::new(AtomicBool::new(false));
let inst = py.init(|t| DataIsDropped{
member1: TestDropCall { drop_called: drop_called1.clone() }, {
member2: TestDropCall { drop_called: drop_called2.clone() }, let gil = Python::acquire_gil();
token: t let py = gil.python();
}).unwrap(); let inst = py.init(|t| DataIsDropped{
assert!(drop_called1.load(Ordering::Relaxed) == false); member1: TestDropCall { drop_called: drop_called1.clone() },
assert!(drop_called2.load(Ordering::Relaxed) == false); member2: TestDropCall { drop_called: drop_called2.clone() },
drop(inst); token: t
}).unwrap();
assert!(drop_called1.load(Ordering::Relaxed) == false);
assert!(drop_called2.load(Ordering::Relaxed) == false);
drop(inst);
}
assert!(drop_called1.load(Ordering::Relaxed) == true); assert!(drop_called1.load(Ordering::Relaxed) == true);
assert!(drop_called2.load(Ordering::Relaxed) == true); assert!(drop_called2.load(Ordering::Relaxed) == true);
} }