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
66
67
//! Test function ensuring threads are working properly.

use core::fmt::Write;
use alloc::string::String;
use alloc::vec::Vec;
use alloc::sync::Arc;

use spin::Mutex;

use sunrise_libuser::twili::IPipeProxy;
use sunrise_libuser::error::Error;
use sunrise_libuser::threads::{self, Thread};

/// Help string.
pub static HELP: &str = "test_threads: Run threads that concurrently print As and Bs";

/// Test function ensuring threads are working properly.
pub fn main(_stdin: IPipeProxy, stdout: IPipeProxy, _stderr: IPipeProxy, _args: Vec<String>) -> Result<(), Error> {
    #[doc(hidden)]
    fn thread_a(terminal: usize) {
        let terminal = unsafe {
            Arc::from_raw(terminal as *const Mutex<IPipeProxy>)
        };
        let mut i = 0;
        while i < 10 {
            if let Some(mut lock) = terminal.try_lock() {
                let _ = writeln!(lock, "A");
                i += 1;
            }
            let _ = libuser::syscalls::sleep_thread(0);
        }
    }

    #[doc(hidden)]
    fn thread_b(terminal: usize) {
        // Wrap in a block to forcibly call Arc destructor before exiting the thread.
        {
            let terminal = unsafe {
                Arc::from_raw(terminal as *const Mutex<IPipeProxy>)
            };
            let mut i = 0;
            while i < 10 {
                if let Some(mut lock) = terminal.try_lock() {
                    let _ = writeln!(lock, "B");
                    i += 1;
                }
                let _ = libuser::syscalls::sleep_thread(0);
            }
        }
    }

    let terminal = Arc::new(Mutex::new(stdout));

    let t = Thread::create(thread_b, Arc::into_raw(terminal.clone()) as usize, threads::DEFAULT_STACK_SIZE)
        .expect("Failed to create thread B");
    t.start()
        .expect("Failed to start thread B");


    // thread is running b, run a meanwhile
    thread_a(Arc::into_raw(terminal) as usize);

    // Wait for thread_b to terminate.
    t.join().expect("Cannot wait for thread B to finish");

    Ok(())
}