Skip to main content

onion_vm/types/
thread_handle.rs

1//! Onion 线程句柄(ThreadHandle)类型模块。
2//!
3//! 提供 Onion 语言运行时的线程句柄类型实现,支持线程安全的并发任务管理、
4//! 结果获取、GC 跟踪与类型扩展。可用于多线程并发计算与任务同步。
5//!
6//! # 主要功能
7//! - 线程句柄的创建与状态检测
8//! - 线程结果的安全获取与同步
9//! - 支持 GC 跟踪与升级
10//! - 提供类型扩展与属性访问
11
12use std::{
13    any::Any,
14    collections::VecDeque,
15    fmt::{Debug, Formatter},
16    sync::Mutex,
17    thread::JoinHandle,
18};
19
20use arc_gc::{
21    arc::{GCArc, GCArcWeak},
22    gc::GC,
23    traceable::GCTraceable,
24};
25
26use crate::{
27    lambda::runnable::RuntimeError,
28    types::object::{GCArcStorage, OnionStaticObject},
29};
30
31use super::object::{OnionObject, OnionObjectCell, OnionObjectExt};
32
33/// Onion 线程句柄类型。
34///
35/// 封装 JoinHandle 以适配 OnionObject,支持线程安全的并发任务管理。
36///
37/// # 字段
38/// - `inner`: (线程句柄, 完成状态, 结果弱引用) 的互斥封装
39pub struct OnionThreadHandle {
40    inner: Mutex<(
41        Option<JoinHandle<Result<Box<OnionStaticObject>, RuntimeError>>>,
42        bool,
43        GCArcWeak<OnionObjectCell>,
44    )>,
45}
46
47impl OnionThreadHandle {
48    /// 创建新的线程句柄。
49    ///
50    /// # 参数
51    /// - `handle`: Rust JoinHandle 对象
52    /// - `gc`: Onion GC 管理器,用于分配初始结果对象
53    ///
54    /// # 返回
55    /// - `(Self, GCArcStorage)`: 新的线程句柄和对应的 GC 存储
56    pub fn new(
57        handle: JoinHandle<Result<Box<OnionStaticObject>, RuntimeError>>,
58        gc: &mut GC<OnionObjectCell>,
59    ) -> (Self, GCArcStorage) {
60        let tmp = gc.create(OnionObjectCell::from(OnionObject::Undefined(None)));
61        (
62            Self {
63                inner: Mutex::new((Some(handle), false, tmp.as_weak())),
64            },
65            GCArcStorage::Single(tmp),
66        )
67    }
68
69    /// 检查线程是否已完成(非阻塞)。
70    ///
71    /// # 返回
72    /// - `true`: 线程已完成
73    /// - `false`: 线程仍在运行
74    pub fn is_finished(&self) -> bool {
75        let guard = self.inner.lock().unwrap();
76        guard.1 || guard.0.is_none()
77    }
78}
79
80impl Debug for OnionThreadHandle {
81    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
82        let guard = self.inner.lock().unwrap();
83        write!(
84            f,
85            "OnionThreadHandle(finished: {}, has_handle: {})",
86            guard.1 || guard.0.is_none(),
87            guard.0.is_some()
88        )
89    }
90}
91
92impl GCTraceable<OnionObjectCell> for OnionThreadHandle {
93    fn collect(&self, queue: &mut VecDeque<GCArcWeak<OnionObjectCell>>) {
94        let guard = self.inner.lock().unwrap();
95        queue.push_back(guard.2.clone());
96    }
97}
98
99impl OnionObjectExt for OnionThreadHandle {
100    fn as_any(&self) -> &dyn Any {
101        self
102    }
103
104    fn repr(&self, _ptrs: &Vec<*const OnionObject>) -> Result<String, RuntimeError> {
105        Ok(format!("ThreadHandle(finished: {})", self.is_finished()))
106    }
107
108    fn equals(&self, _other: &OnionObject) -> Result<bool, RuntimeError> {
109        Ok(false)
110    }
111
112    fn upgrade(&self, collected: &mut Vec<GCArc<OnionObjectCell>>) {
113        let guard = self.inner.lock().unwrap();
114        if let Some(strong) = guard.2.upgrade() {
115            collected.push(strong);
116        }
117    }
118    
119    fn to_boolean(&self) -> Result<bool, RuntimeError> {
120        // A thread handle is "truthy" if it hasn't finished yet
121        Ok(!self.is_finished())
122    }
123
124    fn type_of(&self) -> Result<String, RuntimeError> {
125        Ok("ThreadHandle".to_string())
126    }
127
128    fn value_of(&self) -> Result<OnionStaticObject, RuntimeError> {
129        let mut guard = self.inner.lock().unwrap();
130        // 句柄已经被取走,意味着线程已经结束
131        if guard.0.is_none() {
132            return if let Some(strong_ref) = guard.2.upgrade() {
133                strong_ref.as_ref().with_data(|data| Ok(data.stabilize()))
134            } else {
135                Err(RuntimeError::BrokenReference)
136            };
137        }
138        // 非阻塞地检查线程是否结束,通过handle来检查
139        if let Some(handle) = guard.0.as_ref() {
140            if !handle.is_finished() {
141                return Err(RuntimeError::Pending);
142            }
143        }
144
145        // 线程已经完成,可以安全地 join 并获取结果
146        if let Some(handle) = guard.0.take() {
147            guard.1 = true;
148            drop(guard); // 释放锁
149            match handle.join() {
150                Ok(result) => match result {
151                    Ok(obj) => {
152                        // 由于Handle是抽象的Mut容器,因此应当将结果写入GCArcWeak中
153
154                        // 步骤 1: 克隆结果,不持有任何目标锁。
155                        // 我们从 obj 中提取出最终要写入的值。
156                        // 这里的 clone() 是浅拷贝,非常快。
157                        // 这一步之后,new_value 就与 obj 的锁解耦了。
158                        let new_value = obj.weak().clone();
159
160                        // 步骤 2: 获取目标锁并写入。
161                        match self.inner.lock().unwrap().2.upgrade() {
162                            Some(arc) => {
163                                // 现在我们可以安全地获取写锁,因为我们不再需要访问 obj。
164                                arc.as_ref().with_data_mut(|to| {
165                                    *to = new_value;
166                                    Ok(())
167                                })?;
168                            }
169                            None => return Err(RuntimeError::BrokenReference),
170                        };
171
172                        // 注意:这里返回的 obj 是 join 的原始结果,
173                        // 而不是我们刚刚写入的值,这在逻辑上是正确的。
174                        // Ok(*obj) 表示线程成功返回了这个 OnionStaticObject。
175                        return Ok(*obj);
176                    }
177                    Err(err) => Err(err),
178                },
179                Err(_) => Err(RuntimeError::DetailedError("Thread join failed".into())),
180            }
181        } else {
182            Err(RuntimeError::DetailedError(
183                "Failed to take thread handle after finished check"
184                    .to_string()
185                    .into(),
186            ))
187        }
188    }
189
190    fn with_attribute(
191        &self,
192        key: &OnionObject,
193        f: &mut dyn FnMut(&OnionObject) -> Result<(), RuntimeError>,
194    ) -> Result<(), RuntimeError> {
195        match key {
196            OnionObject::String(s) => match s.as_ref() {
197                "is_finished" => f(&OnionObject::Boolean(self.is_finished())),
198                "has_handle" => {
199                    let guard = self.inner.lock().unwrap();
200                    let has_handle = guard.0.is_some();
201                    f(&OnionObject::Boolean(has_handle))
202                }
203                "has_result" => {
204                    let guard = self.inner.lock().unwrap();
205                    let has_result = guard.2.upgrade().is_some();
206                    f(&OnionObject::Boolean(has_result))
207                }
208                _ => Err(RuntimeError::InvalidOperation(
209                    format!("Attribute '{}' not found in ThreadHandle", s).into(),
210                )),
211            },
212            _ => Err(RuntimeError::InvalidOperation(
213                format!("Attribute {:?} not found in ThreadHandle", key).into(),
214            )),
215        }
216    }
217}