     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
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89

    use crate::{
        mm::kernel_token,
        task::{add_task, current_task, TaskControlBlock},
        trap::{trap_handler, TrapContext},
    };
    use alloc::sync::Arc;

    pub fn sys_thread_create(entry: usize, arg: usize) -> isize {
        kprintln!("[KERN] syscall::thread::sys_thread_create begin");
        let task = current_task().unwrap();
        let process = task.process.upgrade().unwrap();
        // create a new thread
        let new_task = Arc::new(TaskControlBlock::new(
            Arc::clone(&process),
            task.inner_exclusive_access()
                .res
                .as_ref()
                .unwrap()
                .ustack_base,
            true,
        ));
        // add new task to scheduler
        add_task(Arc::clone(&new_task));
        let new_task_inner = new_task.inner_exclusive_access();
        let new_task_res = new_task_inner.res.as_ref().unwrap();
        let new_task_tid = new_task_res.tid;
        let mut process_inner = process.inner_exclusive_access();
        // add new thread to current process
        let tasks = &mut process_inner.tasks;
        while tasks.len() < new_task_tid + 1 {
            tasks.push(None);
        }
        tasks[new_task_tid] = Some(Arc::clone(&new_task));
        let new_task_trap_cx = new_task_inner.get_trap_cx();
        *new_task_trap_cx = TrapContext::app_init_context(
            entry,
            new_task_res.ustack_top(),
            kernel_token(),
            new_task.kstack.get_top(),
            trap_handler as usize,
        );
        (*new_task_trap_cx).x[10] = arg;
        kprintln!("[KERN] syscall::thread::sys_thread_create end");
        new_task_tid as isize
    }

    pub fn sys_gettid() -> isize {
        kprintln!("[KERN] syscall::thread::sys_gettid begin");
        current_task()
            .unwrap()
            .inner_exclusive_access()
            .res
            .as_ref()
            .unwrap()
            .tid as isize
    }

    /// thread does not exist, return -1
    /// thread has not exited yet, return -2
    /// otherwise, return thread's exit code
    pub fn sys_waittid(tid: usize) -> i32 {
        kprintln!("[KERN] syscall::thread::sys_waittid begin");
        let task = current_task().unwrap();
        let process = task.process.upgrade().unwrap();
        let task_inner = task.inner_exclusive_access();
        let mut process_inner = process.inner_exclusive_access();
        // a thread cannot wait for itself
        if task_inner.res.as_ref().unwrap().tid == tid {
            return -1;
        }
        let mut exit_code: Option<i32> = None;
        let waited_task = process_inner.tasks[tid].as_ref();
        if let Some(waited_task) = waited_task {
            if let Some(waited_exit_code) = waited_task.inner_exclusive_access().exit_code {
                exit_code = Some(waited_exit_code);
            }
        } else {
            // waited thread does not exist
            return -1;
        }
        if let Some(exit_code) = exit_code {
            // dealloc the exited thread
            process_inner.tasks[tid] = None;
            exit_code
        } else {
            // waited thread has not exited
            -2
        }
    }