mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-30 09:33:30 +00:00
add process group
This commit is contained in:
@ -11,4 +11,4 @@ proc-macro = true
|
||||
[dependencies]
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = "1.0.90"
|
||||
syn = {version = "1.0.90", features = ["extra-traits"]}
|
||||
|
@ -1,9 +1,13 @@
|
||||
use proc_macro2::TokenStream;
|
||||
//! This crate is used to provide a procedural macro to derive Pod trait defined in kxos_frame.
|
||||
//! When use this crate, kxos-frame should also be added as a dependency.
|
||||
//! This macro should only be used outside
|
||||
//! When derive Pod trait, we will do a check whether the derive is safe since Pod trait is an unsafe trait.
|
||||
//! For struct, we will check that the struct has valid repr (e.g,. repr(C), repr(u8)), and each field is Pod type.
|
||||
//! For union and enum, we only check the valid repr.
|
||||
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use quote::quote;
|
||||
use syn::{
|
||||
parse_macro_input, punctuated::Punctuated, token::Comma, Data, DataEnum, DataStruct,
|
||||
DeriveInput, Field, Fields,
|
||||
};
|
||||
use syn::{parse_macro_input, Attribute, Data, DataStruct, DeriveInput, Fields, Generics};
|
||||
|
||||
#[proc_macro_derive(Pod)]
|
||||
pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStream {
|
||||
@ -11,32 +15,38 @@ pub fn derive_pod(input_token: proc_macro::TokenStream) -> proc_macro::TokenStre
|
||||
expand_derive_pod(input).into()
|
||||
}
|
||||
|
||||
const ALLOWED_REPRS: [&'static str; 13] = [
|
||||
"C", "u8", "i8", "u16", "i16", "u32", "i32", "u64", "i64", "usize", "isize", "u128", "i128",
|
||||
];
|
||||
|
||||
fn expand_derive_pod(input: DeriveInput) -> TokenStream {
|
||||
let attrs = input.attrs;
|
||||
let ident = input.ident;
|
||||
let fields = match input.data {
|
||||
Data::Struct(DataStruct { fields, .. }) => match fields {
|
||||
Fields::Named(fields_named) => fields_named.named,
|
||||
Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
|
||||
Fields::Unit => Punctuated::new(),
|
||||
},
|
||||
Data::Enum(DataEnum { variants, .. }) => {
|
||||
let mut fields: Punctuated<Field, Comma> = Punctuated::new();
|
||||
for var in variants {
|
||||
fields.extend(match var.fields {
|
||||
Fields::Named(fields_named) => fields_named.named,
|
||||
Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
|
||||
Fields::Unit => Punctuated::new(),
|
||||
})
|
||||
}
|
||||
fields
|
||||
}
|
||||
// Panic on compilation time if one tries to derive pod for enum or union.
|
||||
// It may not be a good idea, but works now.
|
||||
_ => panic!("derive pod only works for struct and enum now."),
|
||||
let generics = input.generics;
|
||||
match input.data {
|
||||
Data::Struct(data_struct) => impl_pod_for_struct(data_struct, generics, ident, attrs),
|
||||
Data::Enum(..) | Data::Union(..) => impl_pod_for_enum_or_union(attrs, generics, ident),
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_pod_for_struct(
|
||||
data_struct: DataStruct,
|
||||
generics: Generics,
|
||||
ident: Ident,
|
||||
attrs: Vec<Attribute>,
|
||||
) -> TokenStream {
|
||||
if !has_valid_repr(attrs) {
|
||||
panic!("{} has invalid repr to implement Pod", ident.to_string());
|
||||
}
|
||||
let DataStruct { fields, .. } = data_struct;
|
||||
let fields = match fields {
|
||||
Fields::Named(fields_named) => fields_named.named,
|
||||
Fields::Unnamed(fields_unnamed) => fields_unnamed.unnamed,
|
||||
Fields::Unit => panic!("derive pod does not work for struct with unit field"),
|
||||
};
|
||||
|
||||
// deal with generics
|
||||
let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl();
|
||||
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
|
||||
|
||||
let pod_where_predicates = fields
|
||||
.into_iter()
|
||||
@ -61,3 +71,47 @@ fn expand_derive_pod(input: DeriveInput) -> TokenStream {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn impl_pod_for_enum_or_union(
|
||||
attrs: Vec<Attribute>,
|
||||
generics: Generics,
|
||||
ident: Ident,
|
||||
) -> TokenStream {
|
||||
if !has_valid_repr(attrs) {
|
||||
panic!(
|
||||
"{} does not have invalid repr to implement Pod.",
|
||||
ident.to_string()
|
||||
);
|
||||
}
|
||||
|
||||
// deal with generics
|
||||
let (impl_generics, type_generics, where_clause) = generics.split_for_impl();
|
||||
quote! {
|
||||
#[automatically_derived]
|
||||
unsafe impl #impl_generics ::kxos_frame::Pod #type_generics for #ident #where_clause {}
|
||||
}
|
||||
}
|
||||
|
||||
fn has_valid_repr(attrs: Vec<Attribute>) -> bool {
|
||||
for attr in attrs {
|
||||
if let Some(ident) = attr.path.get_ident() {
|
||||
if "repr" == ident.to_string().as_str() {
|
||||
let repr = attr.tokens.to_string();
|
||||
let repr = repr.replace("(", "").replace(")", "");
|
||||
let reprs = repr
|
||||
.split(",")
|
||||
.map(|one_repr| one_repr.trim())
|
||||
.collect::<Vec<_>>();
|
||||
if let Some(_) = ALLOWED_REPRS.iter().position(|allowed_repr| {
|
||||
reprs
|
||||
.iter()
|
||||
.position(|one_repr| one_repr == allowed_repr)
|
||||
.is_some()
|
||||
}) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
@ -15,4 +15,4 @@ pub const PAGE_SIZE_BITS: usize = 0xc;
|
||||
|
||||
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::Close;
|
||||
|
@ -1,10 +1,12 @@
|
||||
//! CPU.
|
||||
|
||||
use core::arch::x86_64::{_fxrstor, _fxsave};
|
||||
use core::fmt::Debug;
|
||||
use core::mem::MaybeUninit;
|
||||
|
||||
use crate::debug;
|
||||
use crate::trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame};
|
||||
use crate::vm::Pod;
|
||||
use crate::{
|
||||
impl_pod_for,
|
||||
trap::{CalleeRegs, CallerRegs, SyscallFrame, TrapFrame},
|
||||
};
|
||||
|
||||
/// Defines a CPU-local variable.
|
||||
#[macro_export]
|
||||
@ -29,9 +31,9 @@ pub fn this_cpu() -> u32 {
|
||||
#[derive(Clone, Default, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct CpuContext {
|
||||
pub fp_regs: FpRegs,
|
||||
pub gp_regs: GpRegs,
|
||||
pub fs_base: u64,
|
||||
pub fp_regs: FpRegs,
|
||||
/// trap information, this field is all zero when it is syscall
|
||||
pub trap_information: TrapInformation,
|
||||
}
|
||||
@ -69,7 +71,10 @@ pub struct GpRegs {
|
||||
pub rflag: u64,
|
||||
}
|
||||
|
||||
impl_pod_for!(GpRegs, TrapInformation, CpuContext, FpRegs);
|
||||
unsafe impl Pod for GpRegs {}
|
||||
unsafe impl Pod for TrapInformation {}
|
||||
unsafe impl Pod for CpuContext {}
|
||||
unsafe impl Pod for FpRegs {}
|
||||
|
||||
impl From<SyscallFrame> for CpuContext {
|
||||
fn from(syscall: SyscallFrame) -> Self {
|
||||
@ -204,7 +209,7 @@ impl Into<TrapFrame> for CpuContext {
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
#[repr(C)]
|
||||
pub struct FpRegs {
|
||||
//buf: Aligned<A16, [u8; 512]>,
|
||||
buf: FxsaveArea,
|
||||
is_valid: bool,
|
||||
}
|
||||
|
||||
@ -214,18 +219,25 @@ impl FpRegs {
|
||||
/// Note that a newly-created instance's floating point state is not
|
||||
/// initialized, thus considered invalid (i.e., `self.is_valid() == false`).
|
||||
pub fn new() -> Self {
|
||||
//let buf = Aligned(unsafe { MaybeUninit::uninit().assume_init() });
|
||||
//let is_valid = false;
|
||||
//Self { buf, is_valid }
|
||||
Self { is_valid: false }
|
||||
// todo!("import aligned")
|
||||
// The buffer address requires 16bytes alignment.
|
||||
Self {
|
||||
buf: unsafe { MaybeUninit::uninit().assume_init() },
|
||||
is_valid: false,
|
||||
}
|
||||
}
|
||||
|
||||
/// Save CPU's current floating pointer states into this instance.
|
||||
pub fn save(&mut self) {
|
||||
// unsafe {
|
||||
// _fxsave(self.buf.as_mut_ptr() as *mut u8);
|
||||
// }
|
||||
debug!("save fpregs");
|
||||
debug!("write addr = 0x{:x}", (&mut self.buf) as *mut _ as usize);
|
||||
let layout = alloc::alloc::Layout::for_value(&self.buf);
|
||||
debug!("layout: {:?}", layout);
|
||||
let ptr = unsafe { alloc::alloc::alloc(layout) } as usize;
|
||||
debug!("ptr = 0x{:x}", ptr);
|
||||
unsafe {
|
||||
_fxsave((&mut self.buf.data).as_mut_ptr() as *mut u8);
|
||||
}
|
||||
debug!("save fpregs success");
|
||||
self.is_valid = true;
|
||||
}
|
||||
|
||||
@ -238,8 +250,8 @@ impl FpRegs {
|
||||
/// It is the caller's responsibility to ensure that the source slice contains
|
||||
/// data that is in xsave/xrstor format. The slice must have a length of 512 bytes.
|
||||
pub unsafe fn save_from_slice(&mut self, src: &[u8]) {
|
||||
//(&mut self.buf).copy_from_slice(src);
|
||||
//self.is_valid = true;
|
||||
(&mut self.buf.data).copy_from_slice(src);
|
||||
self.is_valid = true;
|
||||
}
|
||||
|
||||
/// Returns whether the instance can contains data in valid xsave/xrstor format.
|
||||
@ -259,16 +271,17 @@ impl FpRegs {
|
||||
///
|
||||
/// Panic. If the current state is invalid, the method will panic.
|
||||
pub fn restore(&self) {
|
||||
debug!("restore fpregs");
|
||||
assert!(self.is_valid);
|
||||
//unsafe { _fxrstor(self.buf.as_ptr()) };
|
||||
unsafe { _fxrstor((&self.buf.data).as_ptr()) };
|
||||
debug!("restore fpregs success");
|
||||
}
|
||||
|
||||
/// Returns the floating point state as a slice.
|
||||
///
|
||||
/// Note that the slice may contain garbage if `self.is_valid() == false`.
|
||||
pub fn as_slice(&self) -> &[u8] {
|
||||
//&*self.buf
|
||||
todo!()
|
||||
&self.buf.data
|
||||
}
|
||||
}
|
||||
|
||||
@ -277,3 +290,9 @@ impl Default for FpRegs {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, align(16))]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
struct FxsaveArea {
|
||||
data: [u8; 512], // 512 bytes
|
||||
}
|
||||
|
@ -89,7 +89,7 @@ impl<P> Drop for RcuReclaimer<P> {
|
||||
wq.wake_one();
|
||||
}
|
||||
});
|
||||
wq.wait_until(|| Ok(Some(0u8))).unwrap();
|
||||
wq.wait_until(|| Some(0u8));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -35,43 +35,22 @@ impl WaitQueue {
|
||||
///
|
||||
/// By taking a condition closure, his wait-wakeup mechanism becomes
|
||||
/// more efficient and robust.
|
||||
pub fn wait_until<F, R>(&self, mut cond: F) -> Result<R>
|
||||
pub fn wait_until<F, R>(&self, mut cond: F) -> R
|
||||
where
|
||||
F: FnMut() -> Result<Option<R>>,
|
||||
F: FnMut() -> Option<R>,
|
||||
{
|
||||
let waiter = Arc::new(Waiter::new());
|
||||
self.enqueue(&waiter);
|
||||
loop {
|
||||
let ret_value = match cond() {
|
||||
Ok(Some(ret_value)) => Some(Ok(ret_value)),
|
||||
Ok(None) => None,
|
||||
Err(err) => Some(Err(err)),
|
||||
};
|
||||
if let Some(ret_value) = ret_value {
|
||||
if let Some(res) = cond() {
|
||||
waiter.set_finished();
|
||||
self.finish_wait();
|
||||
return ret_value;
|
||||
}
|
||||
return res;
|
||||
};
|
||||
waiter.wait();
|
||||
}
|
||||
}
|
||||
|
||||
/// Wait on an waiter with data until the waiter is woken up.
|
||||
/// Note this func cannot be implemented with wait_until. This func always requires the waiter become woken.
|
||||
/// While wait_until does not check the waiter if cond is true.
|
||||
/// TODO: This function can take a timeout param further.
|
||||
// pub fn wait_on(&self, data: D) {
|
||||
// let index = self
|
||||
// .waiters
|
||||
// .lock()
|
||||
// .iter()
|
||||
// .position(|waiter| *waiter.data() == data);
|
||||
// if let Some(index) = index {
|
||||
// let waiter = self.waiters.lock().iter().nth(index).unwrap().clone();
|
||||
// waiter.wait();
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Wake one waiter thread, if there is one.
|
||||
pub fn wake_one(&self) {
|
||||
if let Some(waiter) = self.waiters.lock().front() {
|
||||
@ -89,107 +68,6 @@ impl WaitQueue {
|
||||
}
|
||||
}
|
||||
|
||||
/// Wake all waiters if given condition returns true.
|
||||
/// The condition will check the data carried by waiter if it satisfy some relation with cond_data
|
||||
// pub fn wake_all_on_condition<F, C>(&self, cond_data: &C, cond: F)
|
||||
// where
|
||||
// F: Fn(&D, &C) -> bool,
|
||||
// {
|
||||
// self.waiters.lock().iter().for_each(|waiter| {
|
||||
// if cond(waiter.data(), cond_data) {
|
||||
// waiter.wake_up()
|
||||
// }
|
||||
// })
|
||||
// }
|
||||
|
||||
/// Wake at most max_count waiters if given condition is true.
|
||||
/// returns the number of woken waiters
|
||||
// pub fn batch_wake_and_deque<F, C>(&self, max_count: usize, cond_data: &C, cond: F) -> usize
|
||||
// where
|
||||
// F: Fn(&D, &C) -> bool,
|
||||
// {
|
||||
// let mut count = 0;
|
||||
// let mut waiters_to_wake = Vec::new();
|
||||
// self.waiters.lock().retain(|waiter| {
|
||||
// if count >= max_count || waiter.is_woken_up() || !cond(waiter.data(), cond_data) {
|
||||
// true
|
||||
// } else {
|
||||
// waiters_to_wake.push(waiter.clone());
|
||||
// count += 1;
|
||||
// false
|
||||
// }
|
||||
// });
|
||||
// waiters_to_wake.into_iter().for_each(|waiter| {
|
||||
// waiter.wake_up();
|
||||
// });
|
||||
// return count;
|
||||
// }
|
||||
|
||||
/// create a waiter with given data, and enqueue
|
||||
// pub fn enqueue(&self) {
|
||||
// let waiter = Arc::new(Waiter::new(data));
|
||||
// self.enqueue_waiter(&waiter);
|
||||
// }
|
||||
|
||||
/// dequeue a waiter with given data
|
||||
// pub fn dequeue(&self, data: D) {
|
||||
// let waiter = Arc::new(Waiter::new(data));
|
||||
// self.dequeue_waiter(&waiter);
|
||||
// }
|
||||
|
||||
/// update the waiters data
|
||||
/// if cond(old_data, old_value) is true.
|
||||
/// The new data should be calculated by get_new_data(old_data, new_value).
|
||||
// pub fn update_waiters_data<F1, F2, C>(
|
||||
// &self,
|
||||
// cond: F1,
|
||||
// old_value: &C,
|
||||
// new_value: &C,
|
||||
// get_new_data: F2,
|
||||
// max_count: usize,
|
||||
// ) where
|
||||
// F1: Fn(&C, &D) -> bool,
|
||||
// F2: Fn(&D, &C) -> D,
|
||||
// {
|
||||
// let mut waiters = self.waiters.lock();
|
||||
// let len = waiters.len();
|
||||
// let mut count = 0;
|
||||
// for index in 0..len {
|
||||
// let waiter = &waiters[index];
|
||||
// let old_data = waiter.data();
|
||||
// if cond(old_value, waiter.data()) {
|
||||
// let new_data = get_new_data(old_data, new_value);
|
||||
// let new_waiter = Arc::new(Waiter::new(new_data));
|
||||
// waiters[index] = new_waiter;
|
||||
// count += 1;
|
||||
// if count >= max_count {
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
/// remove waiters for which the cond returns true
|
||||
// pub fn remove_waiters<C, F>(&self, cond: F, cond_data: &C, max_count: usize) -> Vec<D>
|
||||
// where
|
||||
// F: Fn(&D, &C) -> bool,
|
||||
// {
|
||||
// let mut removed_waiters = Vec::new();
|
||||
// let mut count = 0;
|
||||
// self.waiters.lock().retain(|waiter| {
|
||||
// let data = waiter.data();
|
||||
// if count >= max_count || !cond(data, cond_data) {
|
||||
// true
|
||||
// } else {
|
||||
// count += 1;
|
||||
// removed_waiters.push(data.clone());
|
||||
// false
|
||||
// }
|
||||
// });
|
||||
|
||||
// removed_waiters
|
||||
// }
|
||||
|
||||
// enqueue a waiter into current waitqueue. If waiter is exclusive, add to the back of waitqueue.
|
||||
// Otherwise, add to the front of waitqueue
|
||||
fn enqueue(&self, waiter: &Arc<Waiter>) {
|
||||
@ -204,17 +82,6 @@ impl WaitQueue {
|
||||
fn finish_wait(&self) {
|
||||
self.waiters.lock().retain(|waiter| !waiter.is_finished())
|
||||
}
|
||||
|
||||
// fn dequeue_waiter(&self, waiter_ref: &WaiterRef<D>) {
|
||||
// let mut waiters_lock = self.waiters.lock();
|
||||
// let index = waiters_lock
|
||||
// .iter()
|
||||
// .position(|waiter_| *waiter_ref.data() == *waiter_.data());
|
||||
// if let Some(index) = index {
|
||||
// waiters_lock.remove(index);
|
||||
// }
|
||||
// drop(waiters_lock);
|
||||
// }
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -119,13 +119,15 @@ impl<'a> UserMode<'a> {
|
||||
self.current.syscall_frame().caller.rcx = self.user_space.cpu_ctx.gp_regs.rip;
|
||||
// write fsbase
|
||||
wrfsbase(self.user_space.cpu_ctx.fs_base);
|
||||
|
||||
let fp_regs = self.user_space.cpu_ctx.fp_regs;
|
||||
if fp_regs.is_valid() {
|
||||
fp_regs.restore();
|
||||
}
|
||||
self.executed = true;
|
||||
} else {
|
||||
if self.current.inner_exclusive_access().is_from_trap {
|
||||
*self.current.trap_frame() = self.context.into();
|
||||
} else {
|
||||
// x86_64_util::wrfsbase(self.context.fs_base);
|
||||
*self.current.syscall_frame() = self.context.into();
|
||||
self.current.syscall_frame().caller.rcx = self.context.gp_regs.rip;
|
||||
}
|
||||
@ -135,6 +137,12 @@ impl<'a> UserMode<'a> {
|
||||
debug!("write fsbase: 0x{:x}", self.context.fs_base);
|
||||
wrfsbase(self.context.fs_base);
|
||||
}
|
||||
|
||||
// write fp_regs
|
||||
// let fp_regs = self.context.fp_regs;
|
||||
// if fp_regs.is_valid() {
|
||||
// fp_regs.restore();
|
||||
// }
|
||||
}
|
||||
|
||||
let mut current_task_inner = self.current.inner_exclusive_access();
|
||||
@ -152,10 +160,12 @@ impl<'a> UserMode<'a> {
|
||||
if self.current.inner_exclusive_access().is_from_trap {
|
||||
self.context = CpuContext::from(*self.current.trap_frame());
|
||||
self.context.fs_base = rdfsbase();
|
||||
// self.context.fp_regs.save();
|
||||
UserEvent::Exception
|
||||
} else {
|
||||
self.context = CpuContext::from(*self.current.syscall_frame());
|
||||
self.context.fs_base = rdfsbase();
|
||||
// self.context.fp_regs.save();
|
||||
// debug!("[kernel] syscall id:{}", self.context.gp_regs.rax);
|
||||
// debug!("[kernel] rsp: 0x{:x}", self.context.gp_regs.rsp);
|
||||
// debug!("[kernel] rcx: 0x{:x}", self.context.gp_regs.rcx);
|
||||
|
@ -7,7 +7,6 @@ pub mod msix;
|
||||
pub mod util;
|
||||
extern crate alloc;
|
||||
use kxos_frame::info;
|
||||
#[macro_use]
|
||||
extern crate kxos_frame_pod_derive;
|
||||
|
||||
use alloc::{sync::Arc, vec::Vec};
|
||||
|
@ -4,7 +4,6 @@ use crate::process::Process;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use kxos_frame::info;
|
||||
use kxos_frame_pod_derive::Pod;
|
||||
use kxos_pci::PCIDevice;
|
||||
use kxos_virtio::PCIVirtioDevice;
|
||||
use lazy_static::lazy_static;
|
||||
|
@ -205,6 +205,12 @@ impl From<core::ffi::FromBytesUntilNulError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<core::ffi::FromBytesWithNulError> for Error {
|
||||
fn from(_: core::ffi::FromBytesWithNulError) -> Self {
|
||||
Error::with_message(Errno::E2BIG, "Cannot find null in cstring")
|
||||
}
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! return_errno {
|
||||
($errno: expr) => {
|
||||
|
@ -19,6 +19,7 @@ pub const S_IFLNK: u32 = 0o120000;
|
||||
|
||||
/// File Stat
|
||||
#[derive(Debug, Clone, Copy, Pod, Default)]
|
||||
#[repr(C)]
|
||||
pub struct Stat {
|
||||
/// ID of device containing file
|
||||
st_dev: dev_t,
|
||||
|
@ -161,7 +161,7 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result<
|
||||
child.set_process_group(Arc::downgrade(&parent_process_group));
|
||||
|
||||
current!().add_child(child.clone());
|
||||
table::add_process(child_pid, child.clone());
|
||||
table::add_process(child.clone());
|
||||
deal_with_clone_args(clone_args, &child)?;
|
||||
Ok(child)
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use core::sync::atomic::{AtomicI32, AtomicUsize, Ordering};
|
||||
|
||||
use self::name::ProcessName;
|
||||
use self::process_group::ProcessGroup;
|
||||
use self::process_vm::mmap_area::MmapArea;
|
||||
use self::process_vm::user_heap::UserHeap;
|
||||
@ -19,6 +20,7 @@ pub mod clone;
|
||||
pub mod elf;
|
||||
pub mod exception;
|
||||
pub mod fifo_scheduler;
|
||||
pub mod name;
|
||||
pub mod process_filter;
|
||||
pub mod process_group;
|
||||
pub mod process_vm;
|
||||
@ -56,6 +58,8 @@ pub struct Process {
|
||||
children: Mutex<BTreeMap<usize, Arc<Process>>>,
|
||||
/// Process group
|
||||
process_group: Mutex<Option<Weak<ProcessGroup>>>,
|
||||
/// Process name
|
||||
process_name: Mutex<Option<ProcessName>>,
|
||||
|
||||
// Signal
|
||||
sig_dispositions: Mutex<SigDispositions>,
|
||||
@ -101,6 +105,11 @@ impl Process {
|
||||
};
|
||||
let children = BTreeMap::new();
|
||||
let waiting_children = WaitQueue::new();
|
||||
let process_name = exec_filename.as_ref().map(|filename| {
|
||||
let mut process_name = ProcessName::new();
|
||||
process_name.set_name(filename).unwrap();
|
||||
process_name
|
||||
});
|
||||
Self {
|
||||
pid,
|
||||
task,
|
||||
@ -113,6 +122,7 @@ impl Process {
|
||||
parent: Mutex::new(parent),
|
||||
children: Mutex::new(children),
|
||||
process_group: Mutex::new(process_group),
|
||||
process_name: Mutex::new(process_name),
|
||||
sig_dispositions: Mutex::new(sig_dispositions),
|
||||
sig_queues: Mutex::new(sig_queues),
|
||||
sig_mask: Mutex::new(sig_mask),
|
||||
@ -182,7 +192,7 @@ impl Process {
|
||||
});
|
||||
// Set process group
|
||||
user_process.create_and_set_process_group();
|
||||
table::add_process(pid, user_process.clone());
|
||||
table::add_process(user_process.clone());
|
||||
let parent = user_process
|
||||
.parent()
|
||||
.expect("[Internel error] User process should always have parent");
|
||||
@ -214,7 +224,7 @@ impl Process {
|
||||
)
|
||||
});
|
||||
kernel_process.create_and_set_process_group();
|
||||
table::add_process(pid, kernel_process.clone());
|
||||
table::add_process(kernel_process.clone());
|
||||
if let Some(parent) = kernel_process.parent() {
|
||||
parent.add_child(kernel_process.clone());
|
||||
}
|
||||
@ -241,6 +251,10 @@ impl Process {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_name(&self) -> &Mutex<Option<ProcessName>> {
|
||||
&self.process_name
|
||||
}
|
||||
|
||||
pub fn process_group(&self) -> &Mutex<Option<Weak<ProcessGroup>>> {
|
||||
&self.process_group
|
||||
}
|
||||
@ -259,12 +273,14 @@ impl Process {
|
||||
let _ = self.parent.lock().insert(parent);
|
||||
}
|
||||
|
||||
/// Set process group for current process. If old process group exists,
|
||||
/// remove current process from old process group.
|
||||
pub fn set_process_group(&self, process_group: Weak<ProcessGroup>) {
|
||||
if self.process_group.lock().is_none() {
|
||||
let _ = self.process_group.lock().insert(process_group);
|
||||
} else {
|
||||
todo!("We should do something with old group")
|
||||
if let Some(old_process_group) = &*self.process_group().lock() {
|
||||
let old_process_group = old_process_group.upgrade().unwrap();
|
||||
old_process_group.remove_process(self.pid());
|
||||
}
|
||||
let _ = self.process_group.lock().insert(process_group);
|
||||
}
|
||||
|
||||
/// create a new process group for the process and add it to globle table.
|
||||
@ -273,7 +289,7 @@ impl Process {
|
||||
let process_group = Arc::new(ProcessGroup::new(self.clone()));
|
||||
let pgid = process_group.pgid();
|
||||
self.set_process_group(Arc::downgrade(&process_group));
|
||||
table::add_process_group(pgid, process_group);
|
||||
table::add_process_group(process_group);
|
||||
}
|
||||
|
||||
pub fn parent(&self) -> Option<Arc<Process>> {
|
||||
|
31
src/kxos-std/src/process/name.rs
Normal file
31
src/kxos-std/src/process/name.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
pub const MAX_PROCESS_NAME_LEN: usize = 128;
|
||||
pub struct ProcessName {
|
||||
inner: [u8; MAX_PROCESS_NAME_LEN],
|
||||
count: usize,
|
||||
}
|
||||
|
||||
impl ProcessName {
|
||||
pub fn new() -> Self {
|
||||
ProcessName {
|
||||
inner: [0; MAX_PROCESS_NAME_LEN],
|
||||
count: 0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn set_name(&mut self, name: &CStr) -> Result<()> {
|
||||
let bytes = name.to_bytes_with_nul();
|
||||
let bytes_len = bytes.len();
|
||||
if bytes_len > MAX_PROCESS_NAME_LEN {
|
||||
return_errno_with_message!(Errno::E2BIG, "process name is too long");
|
||||
}
|
||||
self.count = bytes_len;
|
||||
self.inner[..bytes_len].clone_from_slice(bytes);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_name(&self) -> Result<Option<&CStr>> {
|
||||
Ok(Some(&(CStr::from_bytes_with_nul(&self.inner)?)))
|
||||
}
|
||||
}
|
@ -43,6 +43,8 @@ impl ProcessGroup {
|
||||
self.inner.lock().processes.insert(process.pid(), process);
|
||||
}
|
||||
|
||||
/// remove a process from this process group.
|
||||
/// If this group contains no processes now, the group itself will be deleted from global table.
|
||||
pub fn remove_process(&self, pid: Pid) {
|
||||
let mut inner_lock = self.inner.lock();
|
||||
inner_lock.processes.remove(&pid);
|
||||
|
@ -89,6 +89,7 @@ pub struct mcontext_t {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, Pod, Default)]
|
||||
#[repr(C)]
|
||||
pub struct SignalCpuContext {
|
||||
pub gp_regs: GpRegs,
|
||||
pub fpregs_on_heap: u64,
|
||||
|
@ -13,7 +13,8 @@ lazy_static! {
|
||||
}
|
||||
|
||||
/// add a process to global table
|
||||
pub fn add_process(pid: Pid, process: Arc<Process>) {
|
||||
pub fn add_process(process: Arc<Process>) {
|
||||
let pid = process.pid();
|
||||
PROCESS_TABLE.lock().insert(pid, process);
|
||||
}
|
||||
|
||||
@ -40,7 +41,8 @@ pub fn get_all_processes() -> Vec<Arc<Process>> {
|
||||
}
|
||||
|
||||
/// add process group to global table
|
||||
pub fn add_process_group(pgid: Pgid, process_group: Arc<ProcessGroup>) {
|
||||
pub fn add_process_group(process_group: Arc<ProcessGroup>) {
|
||||
let pgid = process_group.pgid();
|
||||
PROCESS_GROUP_TABLE.lock().insert(pgid, process_group);
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ pub fn wait_child_exit(
|
||||
drop(children_lock);
|
||||
|
||||
if unwaited_children.len() == 0 {
|
||||
return Err(kxos_frame::Error::NoChild);
|
||||
return Some(Err(kxos_frame::Error::NoChild));
|
||||
}
|
||||
|
||||
// return immediately if we find a zombie child
|
||||
@ -54,19 +54,19 @@ pub fn wait_child_exit(
|
||||
let exit_code = zombie_child.exit_code();
|
||||
if wait_options.contains(WaitOptions::WNOWAIT) {
|
||||
// does not reap child, directly return
|
||||
return Ok(Some((zombie_pid, exit_code)));
|
||||
return Some(Ok((zombie_pid, exit_code)));
|
||||
} else {
|
||||
let exit_code = current.reap_zombie_child(zombie_pid);
|
||||
return Ok(Some((zombie_pid, exit_code)));
|
||||
return Some(Ok((zombie_pid, exit_code)));
|
||||
}
|
||||
}
|
||||
|
||||
if wait_options.contains(WaitOptions::WNOHANG) {
|
||||
return Ok(Some((0, 0)));
|
||||
return Some(Ok((0, 0)));
|
||||
}
|
||||
|
||||
// wait
|
||||
Ok(None)
|
||||
None
|
||||
})?;
|
||||
|
||||
Ok((pid, exit_code))
|
||||
|
@ -2,6 +2,7 @@ use crate::prelude::*;
|
||||
|
||||
use crate::syscall::{SyscallReturn, SYS_EXIT_GROUP};
|
||||
|
||||
/// Exit all thread in a process.
|
||||
pub fn sys_exit_group(exit_code: u64) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_EXIT_GROUP]", SYS_EXIT_GROUP);
|
||||
current!().exit(exit_code as _);
|
||||
|
8
src/kxos-std/src/syscall/getpgrp.rs
Normal file
8
src/kxos-std/src/syscall/getpgrp.rs
Normal file
@ -0,0 +1,8 @@
|
||||
use super::{SyscallReturn, SYS_GETPGRP};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub fn sys_getpgrp() -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_GETPGRP]", SYS_GETPGRP);
|
||||
let current = current!();
|
||||
Ok(SyscallReturn::Return(current.pgid() as _))
|
||||
}
|
14
src/kxos-std/src/syscall/getppid.rs
Normal file
14
src/kxos-std/src/syscall/getppid.rs
Normal file
@ -0,0 +1,14 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use super::SYS_GETPPID;
|
||||
|
||||
pub fn sys_getppid() -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_GETPPID]", SYS_GETPPID);
|
||||
let current = current!();
|
||||
let parent = current.parent();
|
||||
match parent {
|
||||
None => Ok(SyscallReturn::Return(0)),
|
||||
Some(parent) => Ok(SyscallReturn::Return(parent.pid() as _)),
|
||||
}
|
||||
}
|
@ -14,17 +14,21 @@ use crate::syscall::futex::sys_futex;
|
||||
use crate::syscall::getegid::sys_getegid;
|
||||
use crate::syscall::geteuid::sys_geteuid;
|
||||
use crate::syscall::getgid::sys_getgid;
|
||||
use crate::syscall::getpgrp::sys_getpgrp;
|
||||
use crate::syscall::getpid::sys_getpid;
|
||||
use crate::syscall::getppid::sys_getppid;
|
||||
use crate::syscall::gettid::sys_gettid;
|
||||
use crate::syscall::getuid::sys_getuid;
|
||||
use crate::syscall::kill::sys_kill;
|
||||
use crate::syscall::mmap::sys_mmap;
|
||||
use crate::syscall::mprotect::sys_mprotect;
|
||||
use crate::syscall::prctl::sys_prctl;
|
||||
use crate::syscall::readlink::sys_readlink;
|
||||
use crate::syscall::rt_sigaction::sys_rt_sigaction;
|
||||
use crate::syscall::rt_sigprocmask::sys_rt_sigprocmask;
|
||||
use crate::syscall::rt_sigreturn::sys_rt_sigreturn;
|
||||
use crate::syscall::sched_yield::sys_sched_yield;
|
||||
use crate::syscall::setpgid::sys_setpgid;
|
||||
use crate::syscall::tgkill::sys_tgkill;
|
||||
use crate::syscall::uname::sys_uname;
|
||||
use crate::syscall::wait4::sys_wait4;
|
||||
@ -38,7 +42,7 @@ mod access;
|
||||
mod arch_prctl;
|
||||
mod brk;
|
||||
mod clone;
|
||||
pub mod constants;
|
||||
mod constants;
|
||||
mod execve;
|
||||
mod exit;
|
||||
mod exit_group;
|
||||
@ -48,17 +52,21 @@ mod futex;
|
||||
mod getegid;
|
||||
mod geteuid;
|
||||
mod getgid;
|
||||
mod getpgrp;
|
||||
mod getpid;
|
||||
mod getppid;
|
||||
mod gettid;
|
||||
mod getuid;
|
||||
mod kill;
|
||||
mod mmap;
|
||||
mod mprotect;
|
||||
mod prctl;
|
||||
mod readlink;
|
||||
mod rt_sigaction;
|
||||
mod rt_sigprocmask;
|
||||
mod rt_sigreturn;
|
||||
mod sched_yield;
|
||||
mod setpgid;
|
||||
mod tgkill;
|
||||
mod uname;
|
||||
mod wait4;
|
||||
@ -87,13 +95,14 @@ define_syscall_nums!(
|
||||
SYS_WAIT4 = 61,
|
||||
SYS_KILL = 62,
|
||||
SYS_UNAME = 63,
|
||||
SYS_GETPPID = 64,
|
||||
SYS_FCNTL = 72,
|
||||
SYS_READLINK = 89,
|
||||
SYS_GETUID = 102,
|
||||
SYS_GETGID = 104,
|
||||
SYS_GETEUID = 107,
|
||||
SYS_GETEGID = 108,
|
||||
SYS_SETPGID = 109,
|
||||
SYS_GETPPID = 110,
|
||||
SYS_GETPGRP = 111,
|
||||
SYS_PRCTL = 157,
|
||||
SYS_ARCH_PRCTL = 158,
|
||||
@ -179,15 +188,16 @@ pub fn syscall_dispatch(
|
||||
SYS_WAIT4 => syscall_handler!(3, sys_wait4, args),
|
||||
SYS_KILL => syscall_handler!(2, sys_kill, args),
|
||||
SYS_UNAME => syscall_handler!(1, sys_uname, args),
|
||||
SYS_GETPPID => todo!(),
|
||||
SYS_FCNTL => todo!(),
|
||||
SYS_READLINK => syscall_handler!(3, sys_readlink, args),
|
||||
SYS_GETUID => syscall_handler!(0, sys_getuid),
|
||||
SYS_GETGID => syscall_handler!(0, sys_getgid),
|
||||
SYS_GETEUID => syscall_handler!(0, sys_geteuid),
|
||||
SYS_GETEGID => syscall_handler!(0, sys_getegid),
|
||||
SYS_GETPGRP => todo!(),
|
||||
SYS_PRCTL => todo!(),
|
||||
SYS_SETPGID => syscall_handler!(2, sys_setpgid, args),
|
||||
SYS_GETPPID => syscall_handler!(0, sys_getppid),
|
||||
SYS_GETPGRP => syscall_handler!(0, sys_getpgrp),
|
||||
SYS_PRCTL => syscall_handler!(5, sys_prctl, args),
|
||||
SYS_ARCH_PRCTL => syscall_handler!(2, sys_arch_prctl, args, context),
|
||||
SYS_GETCWD => todo!(),
|
||||
SYS_GETTID => syscall_handler!(0, sys_gettid),
|
||||
|
61
src/kxos-std/src/syscall/prctl.rs
Normal file
61
src/kxos-std/src/syscall/prctl.rs
Normal file
@ -0,0 +1,61 @@
|
||||
use crate::memory::read_cstring_from_user;
|
||||
use crate::memory::write_bytes_to_user;
|
||||
use crate::prelude::*;
|
||||
use crate::process::name::MAX_PROCESS_NAME_LEN;
|
||||
|
||||
use super::SyscallReturn;
|
||||
use super::SYS_PRCTL;
|
||||
pub fn sys_prctl(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_PRCTL]", SYS_PRCTL);
|
||||
let prctl_cmd = PrctlCmd::from_args(option, arg2, arg3, arg4, arg5)?;
|
||||
debug!("prctl cmd = {:?}", prctl_cmd);
|
||||
let current = current!();
|
||||
match prctl_cmd {
|
||||
PrctlCmd::PR_GET_NAME(write_to_addr) => {
|
||||
let process_name = current.process_name().lock();
|
||||
if let Some(process_name) = &*process_name {
|
||||
if let Some(process_name) = process_name.get_name()? {
|
||||
write_bytes_to_user(write_to_addr, process_name.to_bytes_with_nul())?;
|
||||
}
|
||||
}
|
||||
}
|
||||
PrctlCmd::PR_SET_NAME(read_addr) => {
|
||||
let mut process_name = current.process_name().lock();
|
||||
if let Some(process_name) = &mut *process_name {
|
||||
let new_process_name = read_cstring_from_user(read_addr, MAX_PROCESS_NAME_LEN)?;
|
||||
process_name.set_name(&new_process_name)?;
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
||||
|
||||
const PR_SET_NAME: i32 = 15;
|
||||
const PR_GET_NAME: i32 = 16;
|
||||
const PR_SET_TIMERSLACK: i32 = 29;
|
||||
const PR_GET_TIMERSLACK: i32 = 30;
|
||||
|
||||
#[allow(non_camel_case_types)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub enum PrctlCmd {
|
||||
PR_SET_NAME(Vaddr),
|
||||
PR_GET_NAME(Vaddr),
|
||||
PR_SET_TIMERSLACK(u64),
|
||||
PR_GET_TIMERSLACK,
|
||||
}
|
||||
|
||||
impl PrctlCmd {
|
||||
fn from_args(option: i32, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> Result<PrctlCmd> {
|
||||
match option {
|
||||
PR_SET_NAME => Ok(PrctlCmd::PR_SET_NAME(arg2 as _)),
|
||||
PR_GET_NAME => Ok(PrctlCmd::PR_GET_NAME(arg2 as _)),
|
||||
PR_GET_TIMERSLACK => todo!(),
|
||||
PR_SET_TIMERSLACK => todo!(),
|
||||
_ => {
|
||||
debug!("prctl cmd number: {}", option);
|
||||
return_errno_with_message!(Errno::EINVAL, "unsupported prctl command");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
40
src/kxos-std/src/syscall/setpgid.rs
Normal file
40
src/kxos-std/src/syscall/setpgid.rs
Normal file
@ -0,0 +1,40 @@
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::{process_group::ProcessGroup, table, Pgid, Pid},
|
||||
};
|
||||
|
||||
use super::{SyscallReturn, SYS_SETPGID};
|
||||
|
||||
pub fn sys_setpgid(pid: Pid, pgid: Pgid) -> Result<SyscallReturn> {
|
||||
debug!("[syscall][id={}][SYS_PRCTL]", SYS_SETPGID);
|
||||
let current = current!();
|
||||
// if pid is 0, pid should be the pid of current process
|
||||
let pid = if pid == 0 { current.pid() } else { pid };
|
||||
// if pgid is 0, pgid should be pid
|
||||
let pgid = if pgid == 0 { pid } else { pgid };
|
||||
debug!("pid = {}, pgid = {}", pid, pgid);
|
||||
|
||||
if current.pid() != pid {
|
||||
return_errno_with_message!(
|
||||
Errno::EACCES,
|
||||
"cannot set pgid for process other than current"
|
||||
);
|
||||
}
|
||||
|
||||
// only can move process to an existing group or self
|
||||
if pgid != pid && table::pgid_to_process_group(pgid).is_none() {
|
||||
return_errno_with_message!(Errno::EPERM, "process group must exist");
|
||||
}
|
||||
|
||||
if let Some(new_process_group) = table::pgid_to_process_group(pgid) {
|
||||
new_process_group.add_process(current.clone());
|
||||
current.set_process_group(Arc::downgrade(&new_process_group));
|
||||
} else {
|
||||
let new_process_group = Arc::new(ProcessGroup::new(current.clone()));
|
||||
new_process_group.add_process(current.clone());
|
||||
current.set_process_group(Arc::downgrade(&new_process_group));
|
||||
table::add_process_group(new_process_group);
|
||||
}
|
||||
|
||||
Ok(SyscallReturn::Return(0))
|
||||
}
|
@ -1,4 +1,3 @@
|
||||
use kxos_frame::Pod;
|
||||
use kxos_pci::capability::vendor::virtio::CapabilityVirtioData;
|
||||
use kxos_pci::util::BAR;
|
||||
use kxos_util::frame_ptr::InFramePtr;
|
||||
|
@ -5,7 +5,6 @@ use alloc::vec::Vec;
|
||||
use bitflags::bitflags;
|
||||
use core::sync::atomic::{fence, Ordering};
|
||||
use kxos_frame::offset_of;
|
||||
use kxos_frame::Pod;
|
||||
use kxos_util::frame_ptr::InFramePtr;
|
||||
#[derive(Debug)]
|
||||
pub enum QueueError {
|
||||
@ -255,6 +254,7 @@ fn set_buf(inframe_ptr: &InFramePtr<Descriptor>, buf: &[u8]) {
|
||||
bitflags! {
|
||||
/// Descriptor flags
|
||||
#[derive(Pod)]
|
||||
#[repr(C)]
|
||||
struct DescFlags: u16 {
|
||||
const NEXT = 1;
|
||||
const WRITE = 2;
|
||||
|
Reference in New Issue
Block a user