rename 'process' crate to 'thread'

toolchain_update
WangRunji 6 years ago
parent 238de1b282
commit 5bffce787b

@ -1,7 +1,8 @@
[package]
name = "rcore-process"
name = "rcore-thread"
version = "0.1.0"
authors = ["WangRunji <wangrunji0408@163.com>"]
description = "Bare-metal thread scheduler and executor"
edition = "2018"
[dependencies]

@ -1,3 +1,5 @@
//! Enable and disable interrupt for each architecture.
#[inline(always)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn disable_and_store() -> usize {

@ -9,12 +9,12 @@
extern crate alloc;
mod process_manager;
mod thread_pool;
mod processor;
pub mod scheduler;
pub mod thread;
pub mod std_thread;
mod event_hub;
mod interrupt;
pub use crate::process_manager::*;
pub use crate::thread_pool::*;
pub use crate::processor::Processor;

@ -2,10 +2,10 @@ use alloc::boxed::Box;
use alloc::sync::Arc;
use log::*;
use core::cell::UnsafeCell;
use crate::process_manager::*;
use crate::thread_pool::*;
use crate::interrupt;
/// Process executor
/// Thread executor
///
/// Per-CPU struct. Defined at global.
/// Only accessed by associated CPU with interrupt disabled.
@ -18,9 +18,9 @@ unsafe impl Sync for Processor {}
struct ProcessorInner {
id: usize,
proc: Option<(Pid, Box<Context>)>,
proc: Option<(Tid, Box<Context>)>,
loop_context: Box<Context>,
manager: Arc<ProcessManager>,
manager: Arc<ThreadPool>,
}
impl Processor {
@ -28,7 +28,7 @@ impl Processor {
Processor { inner: UnsafeCell::new(None) }
}
pub unsafe fn init(&self, id: usize, context: Box<Context>, manager: Arc<ProcessManager>) {
pub unsafe fn init(&self, id: usize, context: Box<Context>, manager: Arc<ThreadPool>) {
*self.inner.get() = Some(ProcessorInner {
id,
proc: None,
@ -76,7 +76,7 @@ impl Processor {
}
}
pub fn pid(&self) -> Pid {
pub fn tid(&self) -> Tid {
self.inner().proc.as_ref().unwrap().0
}
@ -84,13 +84,13 @@ impl Processor {
&*self.inner().proc.as_ref().unwrap().1
}
pub fn manager(&self) -> &ProcessManager {
pub fn manager(&self) -> &ThreadPool {
&*self.inner().manager
}
pub fn tick(&self) {
let flags = unsafe { interrupt::disable_and_store() };
let need_reschedule = self.manager().tick(self.pid());
let need_reschedule = self.manager().tick(self.tid());
unsafe { interrupt::restore(flags); }
if need_reschedule {

@ -1,4 +1,4 @@
//! Thread std-like interface
//! `std::thread`-like interface
//!
//! Based on Processor. Used in kernel.
//!
@ -11,7 +11,7 @@ use core::marker::PhantomData;
use core::time::Duration;
use log::*;
use crate::processor::*;
use crate::process_manager::*;
use crate::thread_pool::*;
#[linkage = "weak"]
#[no_mangle]
@ -30,7 +30,7 @@ fn new_kernel_context(_entry: extern fn(usize) -> !, _arg: usize) -> Box<Context
/// Gets a handle to the thread that invokes it.
pub fn current() -> Thread {
Thread { pid: processor().pid() }
Thread { pid: processor().tid() }
}
/// Puts the current thread to sleep for the specified amount of time.
@ -160,7 +160,7 @@ impl<T> JoinHandle<T> {
}
}
/// Force construct a JoinHandle struct
pub unsafe fn _of(pid: Pid) -> JoinHandle<T> {
pub unsafe fn _of(pid: Tid) -> JoinHandle<T> {
JoinHandle {
thread: Thread { pid },
mark: PhantomData,

@ -5,17 +5,15 @@ use log::*;
use crate::scheduler::Scheduler;
use crate::event_hub::EventHub;
struct Process {
#[allow(dead_code)]
id: Pid,
struct Thread {
status: Status,
status_after_stop: Status,
context: Option<Box<Context>>,
parent: Pid,
children: Vec<Pid>,
parent: Tid,
children: Vec<Tid>,
}
pub type Pid = usize;
pub type Tid = usize;
type ExitCode = usize;
#[derive(Debug, Clone, Eq, PartialEq)]
@ -23,37 +21,37 @@ pub enum Status {
Ready,
Running(usize),
Sleeping,
Waiting(Pid),
Waiting(Tid),
/// aka ZOMBIE. Its context was dropped.
Exited(ExitCode),
}
#[derive(Eq, PartialEq)]
enum Event {
Wakeup(Pid),
Wakeup(Tid),
}
pub trait Context {
unsafe fn switch_to(&mut self, target: &mut Context);
}
pub struct ProcessManager {
procs: Vec<Mutex<Option<Process>>>,
pub struct ThreadPool {
threads: Vec<Mutex<Option<Thread>>>,
scheduler: Mutex<Box<Scheduler>>,
event_hub: Mutex<EventHub<Event>>,
}
impl ProcessManager {
impl ThreadPool {
pub fn new(scheduler: Box<Scheduler>, max_proc_num: usize) -> Self {
ProcessManager {
procs: new_vec_default(max_proc_num),
ThreadPool {
threads: new_vec_default(max_proc_num),
scheduler: Mutex::new(scheduler),
event_hub: Mutex::new(EventHub::new()),
}
}
fn alloc_pid(&self) -> Pid {
for (i, proc) in self.procs.iter().enumerate() {
fn alloc_tid(&self) -> Tid {
for (i, proc) in self.threads.iter().enumerate() {
if proc.lock().is_none() {
return i;
}
@ -62,82 +60,81 @@ impl ProcessManager {
}
/// Add a new process
pub fn add(&self, context: Box<Context>, parent: Pid) -> Pid {
let pid = self.alloc_pid();
*(&self.procs[pid]).lock() = Some(Process {
id: pid,
pub fn add(&self, context: Box<Context>, parent: Tid) -> Tid {
let tid = self.alloc_tid();
*(&self.threads[tid]).lock() = Some(Thread {
status: Status::Ready,
status_after_stop: Status::Ready,
context: Some(context),
parent,
children: Vec::new(),
});
self.scheduler.lock().insert(pid);
self.procs[parent].lock().as_mut().expect("invalid parent proc")
.children.push(pid);
pid
self.scheduler.lock().insert(tid);
self.threads[parent].lock().as_mut().expect("invalid parent proc")
.children.push(tid);
tid
}
/// Make process `pid` time slice -= 1.
/// Make process `tid` time slice -= 1.
/// Return true if time slice == 0.
/// Called by timer interrupt handler.
pub fn tick(&self, pid: Pid) -> bool {
pub fn tick(&self, tid: Tid) -> bool {
let mut event_hub = self.event_hub.lock();
event_hub.tick();
while let Some(event) = event_hub.pop() {
match event {
Event::Wakeup(pid) => self.set_status(pid, Status::Ready),
Event::Wakeup(tid) => self.set_status(tid, Status::Ready),
}
}
self.scheduler.lock().tick(pid)
self.scheduler.lock().tick(tid)
}
/// Set the priority of process `pid`
pub fn set_priority(&self, pid: Pid, priority: u8) {
self.scheduler.lock().set_priority(pid, priority);
/// Set the priority of process `tid`
pub fn set_priority(&self, tid: Tid, priority: u8) {
self.scheduler.lock().set_priority(tid, priority);
}
/// Called by Processor to get a process to run.
/// The manager first mark it `Running`,
/// then take out and return its Context.
pub fn run(&self, cpu_id: usize) -> (Pid, Box<Context>) {
pub fn run(&self, cpu_id: usize) -> (Tid, Box<Context>) {
let mut scheduler = self.scheduler.lock();
let pid = scheduler.select()
let tid = scheduler.select()
.expect("failed to select a runnable process");
scheduler.remove(pid);
let mut proc_lock = self.procs[pid].lock();
scheduler.remove(tid);
let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("process not exist");
proc.status = Status::Running(cpu_id);
(pid, proc.context.take().expect("context not exist"))
(tid, proc.context.take().expect("context not exist"))
}
/// Called by Processor to finish running a process
/// and give its context back.
pub fn stop(&self, pid: Pid, context: Box<Context>) {
let mut proc_lock = self.procs[pid].lock();
pub fn stop(&self, tid: Tid, context: Box<Context>) {
let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("process not exist");
proc.status = proc.status_after_stop.clone();
proc.status_after_stop = Status::Ready;
proc.context = Some(context);
match proc.status {
Status::Ready => self.scheduler.lock().insert(pid),
Status::Exited(_) => self.exit_handler(pid, proc),
Status::Ready => self.scheduler.lock().insert(tid),
Status::Exited(_) => self.exit_handler(tid, proc),
_ => {}
}
}
/// Switch the status of a process.
/// Insert/Remove it to/from scheduler if necessary.
fn set_status(&self, pid: Pid, status: Status) {
let mut proc_lock = self.procs[pid].lock();
fn set_status(&self, tid: Tid, status: Status) {
let mut proc_lock = self.threads[tid].lock();
let mut proc = proc_lock.as_mut().expect("process not exist");
trace!("process {} {:?} -> {:?}", pid, proc.status, status);
trace!("process {} {:?} -> {:?}", tid, proc.status, status);
match (&proc.status, &status) {
(Status::Ready, Status::Ready) => return,
(Status::Ready, _) => self.scheduler.lock().remove(pid),
(Status::Ready, _) => self.scheduler.lock().remove(tid),
(Status::Exited(_), _) => panic!("can not set status for a exited process"),
(Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(pid)),
(_, Status::Ready) => self.scheduler.lock().insert(pid),
(Status::Sleeping, Status::Exited(_)) => self.event_hub.lock().remove(Event::Wakeup(tid)),
(_, Status::Ready) => self.scheduler.lock().insert(tid),
_ => {}
}
match proc.status {
@ -145,19 +142,19 @@ impl ProcessManager {
_ => proc.status = status,
}
match proc.status {
Status::Exited(_) => self.exit_handler(pid, proc),
Status::Exited(_) => self.exit_handler(tid, proc),
_ => {}
}
}
pub fn get_status(&self, pid: Pid) -> Option<Status> {
self.procs[pid].lock().as_ref().map(|p| p.status.clone())
pub fn get_status(&self, tid: Tid) -> Option<Status> {
self.threads[tid].lock().as_ref().map(|p| p.status.clone())
}
/// Remove an exited proc `pid`.
/// Remove an exited proc `tid`.
/// Its all children will be set parent to 0.
pub fn remove(&self, pid: Pid) {
let mut proc_lock = self.procs[pid].lock();
pub fn remove(&self, tid: Tid) {
let mut proc_lock = self.threads[tid].lock();
let proc = proc_lock.as_ref().expect("process not exist");
match proc.status {
Status::Exited(_) => {}
@ -165,49 +162,49 @@ impl ProcessManager {
}
// orphan procs
for child in proc.children.iter() {
(&self.procs[*child]).lock().as_mut().expect("process not exist").parent = 0;
(&self.threads[*child]).lock().as_mut().expect("process not exist").parent = 0;
}
// remove self from parent's children list
self.procs[proc.parent].lock().as_mut().expect("process not exist")
.children.retain(|&i| i != pid);
// release the pid
self.threads[proc.parent].lock().as_mut().expect("process not exist")
.children.retain(|&i| i != tid);
// release the tid
*proc_lock = None;
}
/// Sleep `pid` for `time` ticks.
/// Sleep `tid` for `time` ticks.
/// `time` == 0 means sleep forever
pub fn sleep(&self, pid: Pid, time: usize) {
self.set_status(pid, Status::Sleeping);
pub fn sleep(&self, tid: Tid, time: usize) {
self.set_status(tid, Status::Sleeping);
if time != 0 {
self.event_hub.lock().push(time, Event::Wakeup(pid));
self.event_hub.lock().push(time, Event::Wakeup(tid));
}
}
pub fn wakeup(&self, pid: Pid) {
self.set_status(pid, Status::Ready);
pub fn wakeup(&self, tid: Tid) {
self.set_status(tid, Status::Ready);
}
pub fn wait(&self, pid: Pid, target: Pid) {
self.set_status(pid, Status::Waiting(target));
pub fn wait(&self, tid: Tid, target: Tid) {
self.set_status(tid, Status::Waiting(target));
}
pub fn wait_child(&self, pid: Pid) {
self.set_status(pid, Status::Waiting(0));
pub fn wait_child(&self, tid: Tid) {
self.set_status(tid, Status::Waiting(0));
}
pub fn get_children(&self, pid: Pid) -> Vec<Pid> {
self.procs[pid].lock().as_ref().expect("process not exist").children.clone()
pub fn get_children(&self, tid: Tid) -> Vec<Tid> {
self.threads[tid].lock().as_ref().expect("process not exist").children.clone()
}
pub fn exit(&self, pid: Pid, code: ExitCode) {
// NOTE: if `pid` is running, status change will be deferred.
self.set_status(pid, Status::Exited(code));
pub fn exit(&self, tid: Tid, code: ExitCode) {
// NOTE: if `tid` is running, status change will be deferred.
self.set_status(tid, Status::Exited(code));
}
/// Called when a process exit
fn exit_handler(&self, pid: Pid, proc: &mut Process) {
fn exit_handler(&self, tid: Tid, proc: &mut Thread) {
// wakeup parent if waiting
let parent = proc.parent;
match self.get_status(parent).expect("process not exist") {
Status::Waiting(target) if target == pid || target == 0 => self.wakeup(parent),
Status::Waiting(target) if target == tid || target == 0 => self.wakeup(parent),
_ => {}
}
// drop its context

4
kernel/Cargo.lock generated

@ -248,7 +248,7 @@ dependencies = [
"pc-keyboard 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"rcore-memory 0.1.0",
"rcore-process 0.1.0",
"rcore-thread 0.1.0",
"riscv 0.3.0 (git+https://github.com/riscv-and-rust-and-decaf/riscv)",
"simple-filesystem 0.1.0 (git+https://github.com/wangrunji0408/SimpleFileSystem-Rust)",
"smoltcp 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -267,7 +267,7 @@ dependencies = [
]
[[package]]
name = "rcore-process"
name = "rcore-thread"
version = "0.1.0"
dependencies = [
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",

@ -47,7 +47,7 @@ lazy_static = { version = "1.2", features = ["spin_no_std"] }
smoltcp = { version = "0.5.0", default-features = false, features = ["alloc", "log", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp"] }
bit-allocator = { path = "../crate/bit-allocator" }
rcore-memory = { path = "../crate/memory" }
rcore-process = { path = "../crate/process" }
rcore-thread = { path = "../crate/thread" }
simple-filesystem = { git = "https://github.com/wangrunji0408/SimpleFileSystem-Rust" }
[target.'cfg(target_arch = "x86_64")'.dependencies]

@ -13,7 +13,7 @@
extern crate alloc;
pub use crate::process::{processor, new_kernel_context};
use rcore_process::thread;
use rcore_thread::std_thread as thread;
use linked_list_allocator::LockedHeap;
#[macro_use] // print!

@ -3,7 +3,7 @@ use alloc::{boxed::Box, collections::BTreeMap, string::String, sync::Arc, vec::V
use log::*;
use simple_filesystem::file::File;
use spin::Mutex;
use rcore_process::Context;
use rcore_thread::Context;
use xmas_elf::{ElfFile, header, program::{Flags, Type}};
use crate::arch::interrupt::{Context as ArchContext, TrapFrame};

@ -1,5 +1,5 @@
pub use self::context::Process;
pub use rcore_process::*;
pub use rcore_thread::*;
use crate::consts::{MAX_CPU_NUM, MAX_PROCESS_NUM};
use crate::arch::cpu;
use alloc::{boxed::Box, sync::Arc};
@ -10,7 +10,7 @@ pub mod context;
pub fn init() {
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass
let scheduler = Box::new(scheduler::RRScheduler::new(5));
let manager = Arc::new(ProcessManager::new(scheduler, MAX_PROCESS_NUM));
let manager = Arc::new(ThreadPool::new(scheduler, MAX_PROCESS_NUM));
unsafe {
for cpu_id in 0..MAX_CPU_NUM {

@ -3,6 +3,7 @@
use alloc::string::String;
use crate::fs::{ROOT_INODE, INodeExt};
use crate::process::*;
use crate::thread;
pub fn run_user_shell() {
if let Ok(inode) = ROOT_INODE.lookup("sh") {

@ -14,7 +14,7 @@ pub fn timer() {
pub fn error(tf: &TrapFrame) -> ! {
error!("{:#x?}", tf);
let pid = processor().pid();
let pid = processor().tid();
error!("On CPU{} Process {}", cpu::id(), pid);
processor().manager().exit(pid, 0x100);

Loading…
Cancel
Save