ch8-dev
parent
1493ec9459
commit
24b3c82b8a
@ -0,0 +1,70 @@
|
||||
use alloc::sync::Arc;
|
||||
use crate::{mm::kernel_token, task::{TaskControlBlock, add_task, current_task}, trap::{TrapContext, trap_handler}};
|
||||
|
||||
pub fn sys_thread_create(entry: usize) -> isize {
|
||||
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_tid as isize
|
||||
}
|
||||
|
||||
pub fn sys_gettid() -> isize {
|
||||
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 {
|
||||
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
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use user_lib::{exit, thread_create, waittid};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
static mut A: usize = 0;
|
||||
const PER_THREAD: usize = 10000000;
|
||||
const THREAD_COUNT: usize = 50;
|
||||
|
||||
unsafe fn f() -> ! {
|
||||
for _ in 0..PER_THREAD {
|
||||
let a = &mut A as *mut usize;
|
||||
let cur = a.read_volatile();
|
||||
a.write_volatile(cur + 1);
|
||||
}
|
||||
exit(0)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
let mut v = Vec::new();
|
||||
for _ in 0..THREAD_COUNT {
|
||||
v.push(thread_create(f as usize) as usize);
|
||||
}
|
||||
for tid in v.iter() {
|
||||
waittid(*tid);
|
||||
}
|
||||
assert_eq!(unsafe { A }, PER_THREAD * THREAD_COUNT);
|
||||
println!("total = {}", unsafe { A });
|
||||
0
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
|
||||
#[macro_use]
|
||||
extern crate user_lib;
|
||||
extern crate alloc;
|
||||
|
||||
use user_lib::{thread_create, waittid, exit};
|
||||
use alloc::vec::Vec;
|
||||
|
||||
pub fn thread_a() -> ! {
|
||||
for _ in 0..1000 { print!("a"); }
|
||||
exit(1)
|
||||
}
|
||||
|
||||
pub fn thread_b() -> ! {
|
||||
for _ in 0..1000 { print!("b"); }
|
||||
exit(2)
|
||||
}
|
||||
|
||||
pub fn thread_c() -> ! {
|
||||
for _ in 0..1000 { print!("c"); }
|
||||
exit(3)
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub fn main() -> i32 {
|
||||
let mut v = Vec::new();
|
||||
v.push(thread_create(thread_a as usize));
|
||||
v.push(thread_create(thread_b as usize));
|
||||
v.push(thread_create(thread_c as usize));
|
||||
for tid in v.iter() {
|
||||
let exit_code = waittid(*tid as usize);
|
||||
println!("thread#{} exited with code {}", tid, exit_code);
|
||||
}
|
||||
println!("main thread exited.");
|
||||
0
|
||||
}
|
Loading…
Reference in new issue