add process group

This commit is contained in:
Jianfeng Jiang
2022-11-10 17:57:39 +08:00
parent b53f99b169
commit dd3b4b0d79
26 changed files with 353 additions and 213 deletions

View File

@ -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"]}

View File

@ -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
}

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 DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Info;
pub const DEFAULT_LOG_LEVEL: LogLevel = LogLevel::Close;

View File

@ -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
}

View File

@ -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));
}
}

View File

@ -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)]

View File

@ -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);

View File

@ -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};

View File

@ -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;

View File

@ -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) => {

View File

@ -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,

View File

@ -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)
}

View File

@ -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>> {

View 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)?)))
}
}

View File

@ -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);

View File

@ -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,

View File

@ -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);
}

View File

@ -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))

View File

@ -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 _);

View 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 _))
}

View 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 _)),
}
}

View File

@ -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),

View 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");
}
}
}
}

View 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))
}

View File

@ -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;

View File

@ -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;