mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-16 17:46:48 +00:00
add syscall sched_yield
This commit is contained in:
parent
9e8e9e62b2
commit
7ce1938a00
@ -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;
|
||||||
|
@ -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"))]
|
||||||
|
@ -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
|
||||||
|
@ -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.
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
@ -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] {
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
||||||
|
11
src/kxos-std/src/syscall/sched_yield.rs
Normal file
11
src/kxos-std/src/syscall/sched_yield.rs
Normal 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)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user