rune/
threads.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
//! Multi-threaded elisp support.
use crate::core::{
    env::Env,
    gc::{Block, Context, RootSet},
    object::{CloneIn, Object},
};
use rune_core::macros::root;
use rune_macros::defun;
use std::thread::{self, JoinHandle};

#[defun]
fn go(obj: Object) {
    go_internal(obj);
}

fn go_internal(obj: Object) -> JoinHandle<()> {
    let block = Block::new_local_unchecked();
    let sexp = obj.clone_in(&block);
    let raw = sexp.into_raw();
    crate::debug::enable_debug();
    thread::spawn(move || {
        let roots = &RootSet::default();
        let cx = &mut Context::from_block(block, roots);
        root!(env, new(Env), cx);
        let obj = unsafe { Object::from_raw(raw) };
        root!(obj, cx);
        _ = crate::interpreter::eval(obj, None, env, cx);
    })
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_go() {
        let roots = &RootSet::default();
        let cx = &mut Context::new(roots);
        let obj = cx.add("test string");
        go_internal(obj).join().unwrap();
    }

    #[test]
    fn test_go_eval() {
        let roots = &RootSet::default();
        let cx = &mut Context::new(roots);
        let threads = [
            go_internal(crate::reader::read("(if nil 1 2 3)", cx).unwrap().0),
            go_internal(crate::reader::read("(progn (defvar foo 1) foo)", cx).unwrap().0),
            go_internal(crate::reader::read("(progn (defvar foo 1) (makunbound 'foo) (let ((fn #'(lambda () (defvar foo 3))) (foo 7)) (funcall fn)) foo)", cx).unwrap().0),
        ];
        for thread in threads {
            thread.join().unwrap();
        }
    }

    #[test]
    fn test_go_message() {
        let roots = &RootSet::default();
        println!("hello main thread");
        let cx = &mut Context::new(roots);
        let obj = crate::reader::read("(message \"hello from thread\")", cx).unwrap().0;
        go_internal(obj).join().unwrap();
    }
}