Gist · 2 / URL: https://kallithea.mmp.dnsalias.org/_admin/gists/2
Public Gist
drop時にwbが必要っぽい upgrade時にwbをかければ救えるっポイけどどうなの?
Expires: in 18 days and 4 hours
tomoki - created 11 days and 19 hours ago
added file: patch wb fail
patch wb fail
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::<Vec<_>>();
+        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<RFtlObj> {
+        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<R>(&self, f: impl FnOnce(RFtlObj) -> R) -> Option<R> {
-        self.upgrade().map(f)
+    pub fn map_upgrade_no_wb<R>(&self, f: impl FnOnce(RFtlObj) -> R) -> Option<R> {
+        self.upgrade_no_wb().map(f)
     }
 }
 
@@ -153,13 +161,13 @@ impl RwWeakObj {
     /// 強参照の取得
     #[inline]
     pub fn upgrade(&self) -> Option<RFtlObj> {
-        self.with_inner(|w| w.upgrade())
+        self.with_inner(|w| w.upgrade_no_wb())
     }
 
     /// 強参照に対するマップ処理
     #[inline]
-    pub fn map_upgrade<R>(&self, f: impl FnOnce(RFtlObj) -> R) -> Option<R> {
-        self.with_inner(|w| w.map_upgrade(f))
+    pub fn map_upgrade_no_wb<R>(&self, f: impl FnOnce(RFtlObj) -> R) -> Option<R> {
+        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<U>(&self, f: impl FnOnce(RFtlObj) -> U) -> Option<U> {
         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<R>(&self, f: impl FnOnce(RFtlObj) -> R) -> Option<R> {
         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<R>(&self, f: impl FnOnce(RFtlObj, RFtlObj) -> R) -> Option<R> {
         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::<Option<Vec<_>>>())
+        self.with_inner(|v| v.iter().map(WeakObj::upgrade_no_wb).collect::<Option<Vec<_>>>())
             .expect("require vector element")
     }
 }
@@ -201,14 +201,14 @@ impl VectorObject for RFtlObj {
     /// フォールバックあり
     #[inline]
     fn get(&self, i: usize, fallback: impl Into<Option<RFtlObj>>) -> Option<RFtlObj> {
-        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<RFtlObj> {
-        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<RFtlObj> {
-        self.with_inner_vec_mut(|vec| vec.pop())?.upgrade()
+        self.with_inner_vec_mut(|vec| vec.pop())?.upgrade_no_wb()
     }
 
     /// リストオブジェクトに変換