add syscall sched_yield

This commit is contained in:
Jianfeng Jiang 2022-09-27 13:52:21 +08:00
parent 9e8e9e62b2
commit 7ce1938a00
10 changed files with 62 additions and 52 deletions

View File

@ -15,4 +15,4 @@ pub const PAGE_SIZE_BITS: usize = 0xc;
pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS; pub const KVA_START: usize = (usize::MAX) << PAGE_SIZE_BITS;
pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info; pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Trace;

View File

@ -35,6 +35,7 @@ use core::{mem, panic::PanicInfo};
pub use self::error::Error; pub use self::error::Error;
pub use self::prelude::Result; pub use self::prelude::Result;
pub(crate) use self::sync::up::UPSafeCell; pub(crate) use self::sync::up::UPSafeCell;
use alloc::vec::Vec; use alloc::vec::Vec;
use bootloader::{ use bootloader::{
boot_info::{FrameBuffer, MemoryRegionKind}, boot_info::{FrameBuffer, MemoryRegionKind},
@ -45,6 +46,8 @@ pub use trap::{allocate_irq, IrqAllocateHandle, TrapFrame};
use trap::{IrqCallbackHandle, IrqLine}; use trap::{IrqCallbackHandle, IrqLine};
pub use vm::Pod; pub use vm::Pod;
use x86_64_util::enable_common_cpu_features; use x86_64_util::enable_common_cpu_features;
pub use util::AlignExt;
static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new(); static mut IRQ_CALLBACK_LIST: Vec<IrqCallbackHandle> = Vec::new();
#[cfg(not(feature = "serial_print"))] #[cfg(not(feature = "serial_print"))]

View File

@ -51,7 +51,9 @@ pub(crate) fn get_idle_task_cx_ptr() -> *mut TaskContext {
/// call this function to switch to other task by using GLOBAL_SCHEDULER /// call this function to switch to other task by using GLOBAL_SCHEDULER
pub fn schedule() { pub fn schedule() {
switch_to_task(fetch_task().expect("no more task found")); if let Some(task) = fetch_task() {
switch_to_task(task);
}
} }
/// call this function to switch to other task /// call this function to switch to other task

View File

@ -128,7 +128,7 @@ impl Task {
/// Note that this method cannot be simply named "yield" as the name is /// Note that this method cannot be simply named "yield" as the name is
/// a Rust keyword. /// a Rust keyword.
pub fn yield_now() { pub fn yield_now() {
todo!() schedule();
} }
/// Spawns a task that executes a function. /// Spawns a task that executes a function.

View File

@ -2,6 +2,9 @@
/// `u64`, and `usize`, to provide methods to make integers aligned to a /// `u64`, and `usize`, to provide methods to make integers aligned to a
/// power of two. /// power of two.
pub trait AlignExt { pub trait AlignExt {
/// returns whether the number is a power of two
fn is_power_of_two(&self) -> bool;
/// Returns to the smallest number that is greater than or equal to /// Returns to the smallest number that is greater than or equal to
/// `self` and is a multiple of the given power of two. /// `self` and is a multiple of the given power of two.
/// ///
@ -41,6 +44,10 @@ macro_rules! impl_align_ext {
($( $uint_type:ty ),+,) => { ($( $uint_type:ty ),+,) => {
$( $(
impl AlignExt for $uint_type { impl AlignExt for $uint_type {
fn is_power_of_two(&self) -> bool {
(*self != 0) && ((*self & (*self - 1)) == 0)
}
fn align_up(self, align: Self) -> Self { fn align_up(self, align: Self) -> Self {
assert!(align.is_power_of_two() && align >= 2); assert!(align.is_power_of_two() && align >= 2);
self.checked_add(align - 1).unwrap() & !(align - 1) self.checked_add(align - 1).unwrap() & !(align - 1)
@ -69,29 +76,29 @@ mod test {
#[test] #[test]
fn test_align_up() { fn test_align_up() {
let input_ns = [0, 1, 2, 9, 15, 21, 32, 47, 50]; let input_ns = [0usize, 1, 2, 9, 15, 21, 32, 47, 50];
let input_as = [2, 2, 2, 2, 4, 4, 8, 8, 8]; let input_as = [2usize, 2, 2, 2, 4, 4, 8, 8, 8];
let output_ns = [0, 2, 2, 10, 16, 24, 32, 48, 56]; let output_ns = [0usize, 2, 2, 10, 16, 24, 32, 48, 56];
for i in 0..input_ns.len() { for i in 0..input_ns.len() {
let n = input_ns[i]; let n = input_ns[i];
let a = input_as[i]; let a = input_as[i];
let n2 = output_ns[i]; let n2 = output_ns[i];
assert!(align_up(n, a) == n2); assert!(n.align_up(a) == n2);
} }
} }
#[test] #[test]
fn test_align_down() { fn test_align_down() {
let input_ns = [0, 1, 2, 9, 15, 21, 32, 47, 50]; let input_ns = [0usize, 1, 2, 9, 15, 21, 32, 47, 50];
let input_as = [2, 2, 2, 2, 4, 4, 8, 8, 8]; let input_as = [2usize, 2, 2, 2, 4, 4, 8, 8, 8];
let output_ns = [0, 0, 2, 8, 12, 20, 32, 40, 48]; let output_ns = [0usize, 0, 2, 8, 12, 20, 32, 40, 48];
for i in 0..input_ns.len() { for i in 0..input_ns.len() {
let n = input_ns[i]; let n = input_ns[i];
let a = input_as[i]; let a = input_as[i];
let n2 = output_ns[i]; let n2 = output_ns[i];
assert!(align_down(n, a) == n2); assert!(n.align_down(a) == n2);
} }
} }
} }

View File

@ -44,6 +44,12 @@ pub fn init_process() {
process.pid() process.pid()
); );
let hello_c_content = read_hello_c_content();
// glibc requires the filename starts as "/"
let hello_c_filename = CString::new("/hello_c").unwrap();
let process = Process::spawn_user_process(hello_c_filename, hello_c_content);
info!("spawn hello_c process, pid = {}", process.pid());
let fork_content = read_fork_content(); let fork_content = read_fork_content();
let fork_filename = CString::new("fork").unwrap(); let fork_filename = CString::new("fork").unwrap();
let process = Process::spawn_user_process(fork_filename, fork_content); let process = Process::spawn_user_process(fork_filename, fork_content);
@ -52,13 +58,11 @@ pub fn init_process() {
process.pid() process.pid()
); );
let hello_c_content = read_hello_c_content(); loop {
// glibc requires the filename starts as "/" // We don't have preemptive scheduler now.
let hello_c_filename = CString::new("/hello_c").unwrap(); // The long running init process should yield its own execution to allow other tasks to go on.
let process = Process::spawn_user_process(hello_c_filename, hello_c_content); Process::yield_now();
info!("spawn hello_c process, pid = {}", process.pid()); }
loop {}
} }
/// first process never return /// first process never return

View File

@ -10,6 +10,7 @@ use kxos_frame::{
config::PAGE_SIZE, config::PAGE_SIZE,
debug, debug,
vm::{Vaddr, VmIo, VmPerm, VmSpace}, vm::{Vaddr, VmIo, VmPerm, VmSpace},
AlignExt,
}; };
use super::{ use super::{
@ -252,9 +253,8 @@ impl InitStack {
} }
/// returns the u64 start address /// returns the u64 start address
fn write_u64(&mut self, val: u64, vm_space: &VmSpace) -> u64 { fn write_u64(&mut self, val: u64, vm_space: &VmSpace) -> u64 {
let start_address = align_down(self.pos - 8, 8); let start_address = (self.pos - 8).align_down(8);
self.pos = start_address; self.pos = start_address;
// debug!("start_address: 0x{:x}", start_address);
vm_space vm_space
.write_val(start_address, &val) .write_val(start_address, &val)
.expect("Write u64 failed"); .expect("Write u64 failed");
@ -289,16 +289,6 @@ impl InitStack {
} }
} }
fn is_power_of_two(val: usize) -> bool {
(val != 0) && ((val & (val - 1)) == 0)
}
/// align should be the pow of 2
fn align_down(vaddr: usize, align: usize) -> usize {
assert!(is_power_of_two(align));
vaddr & !(align - 1)
}
/// generate random [u8; 16]. /// generate random [u8; 16].
/// FIXME: generate really random value. Now only return array with fixed values. /// FIXME: generate really random value. Now only return array with fixed values.
fn generate_random_for_aux_vec() -> [u8; 16] { fn generate_random_for_aux_vec() -> [u8; 16] {

View File

@ -7,7 +7,6 @@ use alloc::{
vec::Vec, vec::Vec,
}; };
use kxos_frame::cpu::CpuContext; use kxos_frame::cpu::CpuContext;
use kxos_frame::vm::{Vaddr, VmPerm};
// use kxos_frame::{sync::SpinLock, task::Task, user::UserSpace}; // use kxos_frame::{sync::SpinLock, task::Task, user::UserSpace};
use kxos_frame::{ use kxos_frame::{
debug, debug,
@ -20,7 +19,6 @@ use spin::Mutex;
use crate::memory::mmap_area::MmapArea; use crate::memory::mmap_area::MmapArea;
use crate::memory::user_heap::UserHeap; use crate::memory::user_heap::UserHeap;
use crate::process::task::create_forked_task; use crate::process::task::create_forked_task;
use crate::syscall::mmap::MMapFlags;
use self::status::ProcessStatus; use self::status::ProcessStatus;
use self::task::create_user_task_from_elf; use self::task::create_user_task_from_elf;
@ -140,6 +138,7 @@ impl Process {
}) })
} }
/// returns the pid
pub fn pid(&self) -> usize { pub fn pid(&self) -> usize {
self.pid self.pid
} }
@ -183,10 +182,16 @@ impl Process {
self.task.send_to_scheduler(); self.task.send_to_scheduler();
} }
/// yield the current process to allow other processes to run
pub fn yield_now() {
Task::yield_now();
}
fn user_space(&self) -> Option<&Arc<UserSpace>> { fn user_space(&self) -> Option<&Arc<UserSpace>> {
self.user_space.as_ref() self.user_space.as_ref()
} }
/// returns the vm space if the process does have, otherwise None
pub fn vm_space(&self) -> Option<&VmSpace> { pub fn vm_space(&self) -> Option<&VmSpace> {
match self.user_space { match self.user_space {
None => None, None => None,
@ -194,6 +199,7 @@ impl Process {
} }
} }
/// returns the user heap if the process does have, otherwise None
pub fn user_heap(&self) -> Option<&UserHeap> { pub fn user_heap(&self) -> Option<&UserHeap> {
match self.user_vm { match self.user_vm {
None => None, None => None,
@ -201,6 +207,7 @@ impl Process {
} }
} }
/// returns the mmap area if the process does have, otherwise None
pub fn mmap_area(&self) -> Option<&MmapArea> { pub fn mmap_area(&self) -> Option<&MmapArea> {
match self.user_vm { match self.user_vm {
None => None, None => None,
@ -208,10 +215,13 @@ impl Process {
} }
} }
/// whether the process has child process
pub fn has_child(&self) -> bool { pub fn has_child(&self) -> bool {
self.children.lock().len() != 0 self.children.lock().len() != 0
} }
/// get the first(and only) child process
/// FIXME: deal with multiple children processes
pub fn get_child_process(&self) -> Arc<Process> { pub fn get_child_process(&self) -> Arc<Process> {
let children_lock = self.children.lock(); let children_lock = self.children.lock();
let child_len = children_lock.len(); let child_len = children_lock.len();
@ -223,6 +233,7 @@ impl Process {
.clone() .clone()
} }
/// Fork a child process
/// WorkAround: This function only create a new process, but did not schedule the process to run /// WorkAround: This function only create a new process, but did not schedule the process to run
pub fn fork(parent_context: CpuContext) -> Arc<Process> { pub fn fork(parent_context: CpuContext) -> Arc<Process> {
let child_pid = new_pid(); let child_pid = new_pid();
@ -271,29 +282,9 @@ impl Process {
child child
} }
pub fn mmap(&self, len: usize, vm_perm: VmPerm, flags: MMapFlags, offset: usize) -> Vaddr {
let mmap_area = self
.mmap_area()
.expect("mmap should work on process with mmap area");
let user_space = self
.user_space()
.expect("mmap should work on process with user space");
let vm_space = user_space.vm_space();
mmap_area.mmap(len, offset, vm_perm, flags, vm_space)
}
pub fn filename(&self) -> Option<&CString> { pub fn filename(&self) -> Option<&CString> {
self.filename.as_ref() self.filename.as_ref()
} }
// pub fn copy_bytes_from_user(&self, vaddr: Vaddr, buf: &mut [u8]) {
// self.user_space()
// .unwrap()
// .vm_space()
// .read_bytes(vaddr, buf)
// .unwrap();
// }
// }
} }
/// Get the init process /// Get the init process

View File

@ -32,6 +32,7 @@ mod gettid;
pub mod mmap; pub mod mmap;
mod mprotect; mod mprotect;
mod readlink; mod readlink;
mod sched_yield;
mod tgkill; mod tgkill;
mod uname; mod uname;
mod write; mod write;
@ -45,6 +46,7 @@ const SYS_BRK: u64 = 12;
const SYS_RT_SIGACTION: u64 = 13; const SYS_RT_SIGACTION: u64 = 13;
const SYS_RT_SIGPROCMASK: u64 = 14; const SYS_RT_SIGPROCMASK: u64 = 14;
const SYS_WRITEV: u64 = 20; const SYS_WRITEV: u64 = 20;
const SYS_SCHED_YIELD: u64 = 24;
const SYS_GETPID: u64 = 39; const SYS_GETPID: u64 = 39;
const SYS_FORK: u64 = 57; const SYS_FORK: u64 = 57;
const SYS_EXIT: u64 = 60; const SYS_EXIT: u64 = 60;

View File

@ -0,0 +1,11 @@
use kxos_frame::debug;
use crate::{process::Process, syscall::SYS_SCHED_YIELD};
use super::SyscallResult;
pub fn sys_sched_yield() -> SyscallResult {
debug!("[syscall][id={}][SYS_SCHED_YIELD]", SYS_SCHED_YIELD);
Process::yield_now();
SyscallResult::Return(0)
}