diff --git a/ftllisp-object/src/object/gc.rs b/ftllisp-object/src/object/gc.rs index aacd60e..1b479bb 100644 --- a/ftllisp-object/src/object/gc.rs +++ b/ftllisp-object/src/object/gc.rs @@ -473,10 +473,12 @@ mod test { use super::{GCManaged, GCManagedWeak, GC}; use crate::object::{RFtlObj, WeakObj}; use crate::vector::VectorObject; + use num::FromPrimitive; use parking_lot::{Mutex, RwLock}; use std::collections::{HashMap, HashSet}; use std::sync::LazyLock; use std::sync::{Arc, Weak}; + use std::thread::sleep; use std::time::{Duration, Instant}; use std::{thread, usize}; @@ -1400,4 +1402,40 @@ mod test { d.subsec_nanos() ); } + + #[test] + fn test_drop_during_gc() { + let _lock = LOCK_GCTEST.lock(); + // let gc_instance = RFtlObj::gc_instance(); + RFtlObj::gc_verbose(true); + let n = 1000000usize; + let mut fr = Vec::with_capacity(n); + let mut to = Vec::with_capacity(n); + let nil = RFtlObj::nil(); + for _ in 0..n { + let x = RFtlObj::from_usize(n).unwrap().cons(&nil); + fr.push(x.cons(&nil)); + to.push(nil.cons_mut(&nil)); + } + RFtlObj::gc(); + let to_weak = to.iter().map(|w| w.downgrade()).collect::>(); + let handle = thread::spawn(move || { + // GC中に長時間処理をシミュレート + for i in 0..n { + // carを取り出して取り出し元はdropさせる + let x = fr.pop().unwrap().car().unwrap(); + // x.gc_write_barrier(); + // 取り出したオブジェクトをtoにセットする + to[i].set_car(x.clone()); + } + sleep(Duration::from_secs(5)); + }); + RFtlObj::gc(); + assert!(to_weak + .iter() + .all(|w| w.upgrade().is_some_and(|o| o.car().is_some()))); + handle.join().unwrap(); + RFtlObj::gc(); + RFtlObj::gc_verbose(false); + } } diff --git a/ftllisp-object/src/object/weak.rs b/ftllisp-object/src/object/weak.rs index 4c0777c..31182fa 100644 --- a/ftllisp-object/src/object/weak.rs +++ b/ftllisp-object/src/object/weak.rs @@ -60,6 +60,14 @@ impl WeakObj { } } + #[inline] + pub fn upgrade_no_wb(&self) -> Option { + match &self.inner { + WeakOrStrong::Weak(w) => w.upgrade().map(|rc| RFtlObj::with_ptr(Pin::new(rc))), + WeakOrStrong::Strong(o) => o.clone(), + } + } + /// gc対象の強参照構造体の取得 /// /// GC対象以外はNone @@ -144,8 +152,8 @@ impl Drop for WeakObj { impl WeakObj { /// 強参照に対するマップ処理 #[inline] - pub fn map_upgrade(&self, f: impl FnOnce(RFtlObj) -> R) -> Option { - self.upgrade().map(f) + pub fn map_upgrade_no_wb(&self, f: impl FnOnce(RFtlObj) -> R) -> Option { + self.upgrade_no_wb().map(f) } } @@ -153,13 +161,13 @@ impl RwWeakObj { /// 強参照の取得 #[inline] pub fn upgrade(&self) -> Option { - self.with_inner(|w| w.upgrade()) + self.with_inner(|w| w.upgrade_no_wb()) } /// 強参照に対するマップ処理 #[inline] - pub fn map_upgrade(&self, f: impl FnOnce(RFtlObj) -> R) -> Option { - self.with_inner(|w| w.map_upgrade(f)) + pub fn map_upgrade_no_wb(&self, f: impl FnOnce(RFtlObj) -> R) -> Option { + self.with_inner(|w| w.map_upgrade_no_wb(f)) } /// 強参照による置換 diff --git a/ftllisp-object/src/pair.rs b/ftllisp-object/src/pair.rs index 550bce9..3fe5d3b 100644 --- a/ftllisp-object/src/pair.rs +++ b/ftllisp-object/src/pair.rs @@ -105,8 +105,8 @@ impl RFtlObj { #[inline] fn map_car(&self, f: impl FnOnce(RFtlObj) -> U) -> Option { match self.as_pair()? { - Pair::Immutable { car, cdr: _ } => car.map_upgrade(f), - Pair::Mutable { car, cdr: _ } => car.map_upgrade(f), + Pair::Immutable { car, cdr: _ } => car.map_upgrade_no_wb(f), + Pair::Mutable { car, cdr: _ } => car.map_upgrade_no_wb(f), } } @@ -119,8 +119,8 @@ impl RFtlObj { #[inline] pub fn map_cdr(&self, f: impl FnOnce(RFtlObj) -> R) -> Option { match self.as_pair()? { - Pair::Immutable { car: _, cdr } => cdr.map_upgrade(f), - Pair::Mutable { car: _, cdr } => cdr.map_upgrade(f), + Pair::Immutable { car: _, cdr } => cdr.map_upgrade_no_wb(f), + Pair::Mutable { car: _, cdr } => cdr.map_upgrade_no_wb(f), } } @@ -134,10 +134,10 @@ impl RFtlObj { pub fn map_car_and_cdr(&self, f: impl FnOnce(RFtlObj, RFtlObj) -> R) -> Option { match self.as_pair()? { Pair::Immutable { car, cdr } => car - .map_upgrade(|car| cdr.map_upgrade(|cdr| f(car, cdr))) + .map_upgrade_no_wb(|car| cdr.map_upgrade_no_wb(|cdr| f(car, cdr))) .flatten(), Pair::Mutable { car, cdr } => car - .map_upgrade(|car| cdr.map_upgrade(|cdr| f(car, cdr))) + .map_upgrade_no_wb(|car| cdr.map_upgrade_no_wb(|cdr| f(car, cdr))) .flatten(), } } diff --git a/ftllisp-object/src/vector.rs b/ftllisp-object/src/vector.rs index 82ed76d..b3c5751 100644 --- a/ftllisp-object/src/vector.rs +++ b/ftllisp-object/src/vector.rs @@ -41,7 +41,7 @@ impl Vector { #[inline] fn to_vec(&self) -> VecRFtlObj { - self.with_inner(|v| v.iter().map(WeakObj::upgrade).collect::>>()) + self.with_inner(|v| v.iter().map(WeakObj::upgrade_no_wb).collect::>>()) .expect("require vector element") } } @@ -201,14 +201,14 @@ impl VectorObject for RFtlObj { /// フォールバックあり #[inline] fn get(&self, i: usize, fallback: impl Into>) -> Option { - self.with_inner_vec(|vec| vec.get(i)?.upgrade()) + self.with_inner_vec(|vec| vec.get(i)?.upgrade_no_wb()) .or_else(|| fallback.into()) } /// 最終要素取得 #[inline] fn last(&self) -> Option { - self.with_inner_vec(|vec| vec.last()?.upgrade()) + self.with_inner_vec(|vec| vec.last()?.upgrade_no_wb()) } /// 要素設定 @@ -237,7 +237,7 @@ impl VectorObject for RFtlObj { /// 不変ベクタまたはベクタ以外のオブジェクトの場合panic #[inline] fn pop(&self) -> Option { - self.with_inner_vec_mut(|vec| vec.pop())?.upgrade() + self.with_inner_vec_mut(|vec| vec.pop())?.upgrade_no_wb() } /// リストオブジェクトに変換