1use std::{
4 fmt,
5 sync::Arc,
6 thread::{self, ThreadId},
7 time::Duration,
8};
9
10use parking_lot::Mutex;
11use scheme_rs_macros::bridge;
12
13use crate::{
14 exceptions::Exception,
15 gc::{Gc, Trace},
16 proc::{ContBarrier, Procedure},
17 records::{RecordTypeDescriptor, SchemeCompatible, rtd},
18 value::Value,
19};
20
21#[derive(Trace)]
22pub struct JoinHandle {
23 #[trace(skip)]
24 id: ThreadId,
25 result: Gc<Mutex<Result<Vec<Value>, Exception>>>,
26}
27
28impl fmt::Debug for JoinHandle {
29 fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 Ok(())
31 }
32}
33
34impl SchemeCompatible for JoinHandle {
35 fn rtd() -> Arc<RecordTypeDescriptor> {
36 rtd!(name: "join-handle", sealed: true, opaque: true)
37 }
38}
39
40#[bridge(name = "spawn", lib = "(threads (1))")]
41pub fn spawn(thunk: Procedure) -> Result<Vec<Value>, Exception> {
42 let cell = Gc::new(Mutex::new(Ok(Vec::new())));
43 let cell_cloned = cell.clone();
44 let join_handle = thread::spawn(move || {
45 let mut cell_write = cell_cloned.lock();
46
47 #[cfg(not(feature = "async"))]
48 {
49 *cell_write = thunk.call(&[], &mut ContBarrier::new());
50 }
51
52 #[cfg(feature = "async")]
53 {
54 *cell_write = thunk.call_sync(&[], &mut ContBarrier::new());
55 }
56 });
57 let id = join_handle.thread().id();
58 Ok(vec![Value::from_rust_type(JoinHandle { id, result: cell })])
59}
60
61#[bridge(name = "join", lib = "(threads (1))")]
62pub fn join(handle: &Value) -> Result<Vec<Value>, Exception> {
63 let handle = handle.try_to_rust_type::<JoinHandle>()?;
64 let curr_id = thread::current().id();
65 if curr_id == handle.id {
66 Err(Exception::error(format!(
67 "thread {curr_id:?} attempted to join itself"
68 )))
69 } else {
70 handle.result.lock().clone()
71 }
72}
73
74#[bridge(name = "sleep", lib = "(threads (1))")]
75pub fn sleep(ms: u64) -> Result<Vec<Value>, Exception> {
76 thread::sleep(Duration::from_millis(ms));
77 Ok(Vec::new())
78}
79
80#[bridge(name = "join-handle?", lib = "(threads (1))")]
81pub fn join_handle_pred(obj: &Value) -> Result<Vec<Value>, Exception> {
82 Ok(vec![Value::from(
83 obj.cast_to_rust_type::<JoinHandle>().is_some(),
84 )])
85}