tg-rcore-tutorial-user 0.4.10

User-space apps for rCore Tutorial chapters (subset for ch2).
Documentation
#![no_std]
#![no_main]

#[macro_use]
extern crate user_lib;

extern crate alloc;

use alloc::vec;
use user_lib::exit;
use user_lib::{
    condvar_create, condvar_signal, condvar_wait, mutex_create, mutex_lock, mutex_unlock,
};
use user_lib::{sleep, thread_create, waittid};

static mut A: usize = 0;

const CONDVAR_ID: usize = 0;
const MUTEX_ID: usize = 0;

// 教学目标:
// 演示条件变量基本用法:线程在条件不满足时等待,被 signal 后继续执行。

unsafe fn first() -> isize {
    sleep(10);
    println!("First work, Change A --> 1 and wakeup Second");
    mutex_lock(MUTEX_ID);
    A = 1;
    condvar_signal(CONDVAR_ID);
    mutex_unlock(MUTEX_ID);
    exit(0)
}

unsafe fn second() -> isize {
    println!("Second want to continue,but need to wait A=1");
    mutex_lock(MUTEX_ID);
    while (&raw const A).read_volatile() == 0 {
        let a = (&raw const A).read_volatile();
        println!("Second: A is {}", a);
        condvar_wait(CONDVAR_ID, MUTEX_ID);
    }
    mutex_unlock(MUTEX_ID);
    let a = (&raw const A).read_volatile();
    println!("A is {}, Second can work now", a);
    exit(0)
}

#[unsafe(no_mangle)]
pub extern "C" fn main() -> i32 {
    // create condvar & mutex
    assert_eq!(condvar_create() as usize, CONDVAR_ID);
    assert_eq!(mutex_create(true) as usize, MUTEX_ID);
    // create threads
    let threads = vec![
        thread_create(first as *const () as usize, 0),
        thread_create(second as *const () as usize, 0),
    ];
    // wait for all threads to complete
    for thread in threads.iter() {
        waittid(*thread as usize);
    }
    println!("test_condvar passed!");
    0
}