mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-17 02:26:46 +00:00
add basic support for signal
This commit is contained in:
parent
7a5660ed5d
commit
f86cd1e6bc
@ -2,18 +2,17 @@
|
||||
|
||||
pub(crate) use alloc::boxed::Box;
|
||||
pub(crate) use alloc::collections::BTreeMap;
|
||||
pub(crate) use alloc::collections::LinkedList;
|
||||
pub(crate) use alloc::collections::VecDeque;
|
||||
pub(crate) use alloc::ffi::CString;
|
||||
pub(crate) use alloc::sync::Arc;
|
||||
pub(crate) use alloc::sync::Weak;
|
||||
#[allow(unused)]
|
||||
pub(crate) use alloc::vec;
|
||||
pub(crate) use alloc::vec::Vec;
|
||||
pub(crate) use bitflags::bitflags;
|
||||
pub(crate) use core::ffi::CStr;
|
||||
pub(crate) use kxos_frame::config::PAGE_SIZE;
|
||||
pub(crate) use kxos_frame::vm::Vaddr;
|
||||
#[allow(unused)]
|
||||
pub(crate) use kxos_frame::{debug, error, info, trace, warn};
|
||||
pub(crate) use spin::Mutex;
|
||||
|
||||
|
@ -6,7 +6,7 @@ use kxos_frame::{
|
||||
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::{new_pid, table, task::create_new_task},
|
||||
process::{new_pid, signal::sig_queues::SigQueues, table, task::create_new_task},
|
||||
};
|
||||
|
||||
use super::Process;
|
||||
@ -127,6 +127,13 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result<
|
||||
debug!("child process pid: {}", child_pid);
|
||||
debug!("rip = 0x{:x}", child_cpu_context.gp_regs.rip);
|
||||
|
||||
// inherit parent's sig disposition
|
||||
let child_sig_dispositions = current.sig_dispositions().lock().clone();
|
||||
// sig queue is set empty
|
||||
let child_sig_queues = SigQueues::new();
|
||||
// inherit parent's sig mask
|
||||
let child_sig_mask = current.sig_mask().lock().clone();
|
||||
|
||||
let child = Arc::new_cyclic(|child_process_ref| {
|
||||
let weak_child_process = child_process_ref.clone();
|
||||
let child_task = create_new_task(child_user_space.clone(), weak_child_process);
|
||||
@ -136,8 +143,23 @@ pub fn clone_child(parent_context: CpuContext, clone_args: CloneArgs) -> Result<
|
||||
child_file_name,
|
||||
child_user_vm,
|
||||
Some(child_user_space),
|
||||
None,
|
||||
child_sig_dispositions,
|
||||
child_sig_queues,
|
||||
child_sig_mask,
|
||||
)
|
||||
});
|
||||
// Inherit parent's process group
|
||||
let parent_process_group = current
|
||||
.process_group()
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|ppgrp| ppgrp.upgrade())
|
||||
.flatten()
|
||||
.unwrap();
|
||||
parent_process_group.add_process(child.clone());
|
||||
child.set_process_group(Arc::downgrade(&parent_process_group));
|
||||
|
||||
Process::current().add_child(child.clone());
|
||||
table::add_process(child_pid, child.clone());
|
||||
deal_with_clone_args(clone_args, &child)?;
|
||||
|
@ -5,9 +5,13 @@ use kxos_frame::sync::WaitQueue;
|
||||
use kxos_frame::{task::Task, user::UserSpace, vm::VmSpace};
|
||||
|
||||
use self::process_filter::ProcessFilter;
|
||||
use self::process_group::ProcessGroup;
|
||||
use self::process_vm::mmap_area::MmapArea;
|
||||
use self::process_vm::user_heap::UserHeap;
|
||||
use self::process_vm::UserVm;
|
||||
use self::signal::sig_disposition::SigDispositions;
|
||||
use self::signal::sig_mask::SigMask;
|
||||
use self::signal::sig_queues::SigQueues;
|
||||
use self::status::ProcessStatus;
|
||||
use self::task::create_user_task_from_elf;
|
||||
|
||||
@ -15,7 +19,9 @@ pub mod clone;
|
||||
pub mod elf;
|
||||
pub mod fifo_scheduler;
|
||||
pub mod process_filter;
|
||||
pub mod process_group;
|
||||
pub mod process_vm;
|
||||
pub mod signal;
|
||||
pub mod status;
|
||||
pub mod table;
|
||||
pub mod task;
|
||||
@ -47,6 +53,14 @@ pub struct Process {
|
||||
parent: Mutex<Option<Weak<Process>>>,
|
||||
/// Children processes
|
||||
children: Mutex<BTreeMap<usize, Arc<Process>>>,
|
||||
/// Process group
|
||||
process_group: Mutex<Option<Weak<ProcessGroup>>>,
|
||||
|
||||
// Signal
|
||||
sig_dispositions: Mutex<SigDispositions>,
|
||||
sig_queues: Mutex<SigQueues>,
|
||||
/// Process-level sigmask
|
||||
sig_mask: Mutex<SigMask>,
|
||||
}
|
||||
|
||||
impl Process {
|
||||
@ -69,6 +83,10 @@ impl Process {
|
||||
exec_filename: Option<CString>,
|
||||
user_vm: Option<UserVm>,
|
||||
user_space: Option<Arc<UserSpace>>,
|
||||
process_group: Option<Weak<ProcessGroup>>,
|
||||
sig_dispositions: SigDispositions,
|
||||
sig_queues: SigQueues,
|
||||
sig_mask: SigMask,
|
||||
) -> Self {
|
||||
let parent = if pid == 0 {
|
||||
debug!("Init process does not has parent");
|
||||
@ -91,6 +109,10 @@ impl Process {
|
||||
status: Mutex::new(ProcessStatus::Runnable),
|
||||
parent: Mutex::new(parent),
|
||||
children: Mutex::new(children),
|
||||
process_group: Mutex::new(process_group),
|
||||
sig_dispositions: Mutex::new(sig_dispositions),
|
||||
sig_queues: Mutex::new(sig_queues),
|
||||
sig_mask: Mutex::new(sig_mask),
|
||||
}
|
||||
}
|
||||
|
||||
@ -124,8 +146,23 @@ impl Process {
|
||||
let task = create_user_task_from_elf(filename, elf_file_content, weak_process);
|
||||
let user_space = task.user_space().map(|user_space| user_space.clone());
|
||||
let user_vm = UserVm::new();
|
||||
Process::new(pid, task, cloned_filename, Some(user_vm), user_space)
|
||||
let sig_dispositions = SigDispositions::new();
|
||||
let sig_queues = SigQueues::new();
|
||||
let sig_mask = SigMask::new_empty();
|
||||
Process::new(
|
||||
pid,
|
||||
task,
|
||||
cloned_filename,
|
||||
Some(user_vm),
|
||||
user_space,
|
||||
None,
|
||||
sig_dispositions,
|
||||
sig_queues,
|
||||
sig_mask,
|
||||
)
|
||||
});
|
||||
// Set process group
|
||||
user_process.create_and_set_process_group();
|
||||
table::add_process(pid, user_process.clone());
|
||||
user_process
|
||||
}
|
||||
@ -138,8 +175,22 @@ impl Process {
|
||||
let kernel_process = Arc::new_cyclic(|weak_process_ref| {
|
||||
let weak_process = weak_process_ref.clone();
|
||||
let task = Task::new(task_fn, weak_process, None).expect("spawn kernel task failed");
|
||||
Process::new(pid, task, None, None, None)
|
||||
let sig_dispositions = SigDispositions::new();
|
||||
let sig_queues = SigQueues::new();
|
||||
let sig_mask = SigMask::new_empty();
|
||||
Process::new(
|
||||
pid,
|
||||
task,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
sig_dispositions,
|
||||
sig_queues,
|
||||
sig_mask,
|
||||
)
|
||||
});
|
||||
kernel_process.create_and_set_process_group();
|
||||
table::add_process(pid, kernel_process.clone());
|
||||
kernel_process
|
||||
}
|
||||
@ -151,7 +202,21 @@ impl Process {
|
||||
|
||||
/// returns the process group id of the process
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
todo!()
|
||||
if let Some(process_group) = self
|
||||
.process_group
|
||||
.lock()
|
||||
.as_ref()
|
||||
.map(|process_group| process_group.upgrade())
|
||||
.flatten()
|
||||
{
|
||||
process_group.pgid()
|
||||
} else {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
pub fn process_group(&self) -> &Mutex<Option<Weak<ProcessGroup>>> {
|
||||
&self.process_group
|
||||
}
|
||||
|
||||
/// add a child process
|
||||
@ -165,6 +230,23 @@ impl Process {
|
||||
let _ = self.parent.lock().insert(parent);
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
||||
}
|
||||
|
||||
/// create a new process group for the process and add it to globle table.
|
||||
/// Then set the process group for current process.
|
||||
fn create_and_set_process_group(self: &Arc<Self>) {
|
||||
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);
|
||||
}
|
||||
|
||||
fn parent(&self) -> Option<Arc<Process>> {
|
||||
self.parent
|
||||
.lock()
|
||||
@ -173,17 +255,13 @@ impl Process {
|
||||
.flatten()
|
||||
}
|
||||
|
||||
/// Set the exit code when calling exit or exit_group
|
||||
pub fn set_exit_code(&self, exit_code: i32) {
|
||||
self.exit_code.store(exit_code, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Exit current process
|
||||
/// Set the status of current process as Zombie
|
||||
/// Move all children to init process
|
||||
/// Wake up the parent wait queue if parent is waiting for self
|
||||
pub fn exit(&self) {
|
||||
/// Exit current process.
|
||||
/// Set the status of current process as Zombie and set exit code.
|
||||
/// Move all children to init process.
|
||||
/// Wake up the parent wait queue if parent is waiting for self.
|
||||
pub fn exit(&self, exit_code: i32) {
|
||||
self.status.lock().set_zombie();
|
||||
self.exit_code.store(exit_code, Ordering::Relaxed);
|
||||
// move children to the init process
|
||||
let current_process = Process::current();
|
||||
if !current_process.is_init_process() {
|
||||
@ -267,15 +345,15 @@ impl Process {
|
||||
/// We current just remove the child from the children map.
|
||||
pub fn reap_zombie_child(&self, pid: Pid) -> i32 {
|
||||
let child_process = self.children.lock().remove(&pid).unwrap();
|
||||
assert!(child_process.status() == ProcessStatus::Zombie);
|
||||
table::delete_process(child_process.pid());
|
||||
assert!(child_process.status().lock().is_zombie());
|
||||
table::remove_process(child_process.pid());
|
||||
child_process.exit_code()
|
||||
}
|
||||
|
||||
/// Get any zombie child
|
||||
pub fn get_zombie_child(&self) -> Option<Arc<Process>> {
|
||||
for (_, child_process) in self.children.lock().iter() {
|
||||
if child_process.status().is_zombie() {
|
||||
if child_process.status().lock().is_zombie() {
|
||||
return Some(child_process.clone());
|
||||
}
|
||||
}
|
||||
@ -295,8 +373,20 @@ impl Process {
|
||||
self.filename.as_ref()
|
||||
}
|
||||
|
||||
pub fn status(&self) -> ProcessStatus {
|
||||
self.status.lock().clone()
|
||||
pub fn status(&self) -> &Mutex<ProcessStatus> {
|
||||
&self.status
|
||||
}
|
||||
|
||||
pub fn sig_dispositions(&self) -> &Mutex<SigDispositions> {
|
||||
&self.sig_dispositions
|
||||
}
|
||||
|
||||
pub fn sig_queues(&self) -> &Mutex<SigQueues> {
|
||||
&self.sig_queues
|
||||
}
|
||||
|
||||
pub fn sig_mask(&self) -> &Mutex<SigMask> {
|
||||
&self.sig_mask
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -20,9 +20,10 @@ impl ProcessFilter {
|
||||
}
|
||||
}
|
||||
|
||||
// used for wait4
|
||||
pub fn from_wait_pid(wait_pid: isize) -> Self {
|
||||
// used for wait4 and kill
|
||||
pub fn from_id(wait_pid: isize) -> Self {
|
||||
// https://man7.org/linux/man-pages/man2/waitpid.2.html
|
||||
// https://man7.org/linux/man-pages/man2/kill.2.html
|
||||
if wait_pid < -1 {
|
||||
// process group ID is equal to the absolute value of pid.
|
||||
ProcessFilter::WithPgid((-wait_pid) as Pgid)
|
||||
|
53
src/kxos-std/src/process/process_group.rs
Normal file
53
src/kxos-std/src/process/process_group.rs
Normal file
@ -0,0 +1,53 @@
|
||||
use super::{Pgid, Pid, Process};
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct ProcessGroup {
|
||||
inner: Mutex<ProcessGroupInner>,
|
||||
}
|
||||
|
||||
struct ProcessGroupInner {
|
||||
pgid: Pgid,
|
||||
processes: BTreeMap<Pid, Arc<Process>>,
|
||||
leader_process: Option<Arc<Process>>,
|
||||
}
|
||||
|
||||
impl ProcessGroup {
|
||||
fn default() -> Self {
|
||||
ProcessGroup {
|
||||
inner: Mutex::new(ProcessGroupInner {
|
||||
pgid: 0,
|
||||
processes: BTreeMap::new(),
|
||||
leader_process: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn new(process: Arc<Process>) -> Self {
|
||||
let process_group = ProcessGroup::default();
|
||||
let pid = process.pid();
|
||||
process_group.set_pgid(pid);
|
||||
process_group.add_process(process.clone());
|
||||
process_group.set_leader_process(process);
|
||||
process_group
|
||||
}
|
||||
|
||||
pub fn set_pgid(&self, pgid: Pgid) {
|
||||
self.inner.lock().pgid = pgid;
|
||||
}
|
||||
|
||||
pub fn set_leader_process(&self, leader_process: Arc<Process>) {
|
||||
self.inner.lock().leader_process = Some(leader_process);
|
||||
}
|
||||
|
||||
pub fn add_process(&self, process: Arc<Process>) {
|
||||
self.inner.lock().processes.insert(process.pid(), process);
|
||||
}
|
||||
|
||||
pub fn remove_process(&self, pid: Pid) {
|
||||
self.inner.lock().processes.remove(&pid);
|
||||
}
|
||||
|
||||
pub fn pgid(&self) -> Pgid {
|
||||
self.inner.lock().pgid
|
||||
}
|
||||
}
|
57
src/kxos-std/src/process/signal/constants.rs
Normal file
57
src/kxos-std/src/process/signal/constants.rs
Normal file
@ -0,0 +1,57 @@
|
||||
/// Standard signals
|
||||
pub(super) const MIN_STD_SIG_NUM: u8 = 1;
|
||||
pub(super) const MAX_STD_SIG_NUM: u8 = 31; // inclusive
|
||||
/// Real-time signals
|
||||
pub(super) const MIN_RT_SIG_NUM: u8 = 32;
|
||||
pub(super) const MAX_RT_SIG_NUM: u8 = 64; // inclusive
|
||||
/// Count the number of signals
|
||||
pub(super) const COUNT_STD_SIGS: usize = 31;
|
||||
pub(super) const COUNT_RT_SIGS: usize = 33;
|
||||
pub(super) const COUNT_ALL_SIGS: usize = 64;
|
||||
|
||||
pub const SIG_DFL: usize = 0;
|
||||
pub const SIG_IGN: usize = 1;
|
||||
|
||||
use super::sig_num::SigNum;
|
||||
|
||||
macro_rules! define_std_signums {
|
||||
( $( $name: ident = $num: expr ),+, ) => {
|
||||
$(
|
||||
pub const $name : SigNum = SigNum::from_u8($num);
|
||||
)*
|
||||
}
|
||||
}
|
||||
|
||||
define_std_signums! {
|
||||
SIGHUP = 1, // Hangup detected on controlling terminal or death of controlling process
|
||||
SIGINT = 2, // Interrupt from keyboard
|
||||
SIGQUIT = 3, // Quit from keyboard
|
||||
SIGILL = 4, // Illegal Instruction
|
||||
SIGTRAP = 5, // Trace/breakpoint trap
|
||||
SIGABRT = 6, // Abort signal from abort(3)
|
||||
SIGBUS = 7, // Bus error (bad memory access)
|
||||
SIGFPE = 8, // Floating-point exception
|
||||
SIGKILL = 9, // Kill signal
|
||||
SIGUSR1 = 10, // User-defined signal 1
|
||||
SIGSEGV = 11, // Invalid memory reference
|
||||
SIGUSR2 = 12, // User-defined signal 2
|
||||
SIGPIPE = 13, // Broken pipe: write to pipe with no readers; see pipe(7)
|
||||
SIGALRM = 14, // Timer signal from alarm(2)
|
||||
SIGTERM = 15, // Termination signal
|
||||
SIGSTKFLT = 16, // Stack fault on coprocessor (unused)
|
||||
SIGCHLD = 17, // Child stopped or terminated
|
||||
SIGCONT = 18, // Continue if stopped
|
||||
SIGSTOP = 19, // Stop process
|
||||
SIGTSTP = 20, // Stop typed at terminal
|
||||
SIGTTIN = 21, // Terminal input for background process
|
||||
SIGTTOU = 22, // Terminal output for background process
|
||||
SIGURG = 23, // Urgent condition on socket (4.2BSD)
|
||||
SIGXCPU = 24, // CPU time limit exceeded (4.2BSD); see setrlimit(2)
|
||||
SIGXFSZ = 25, // File size limit exceeded (4.2BSD); see setrlimit(2)
|
||||
SIGVTALRM = 26, // Virtual alarm clock (4.2BSD)
|
||||
SIGPROF = 27, // Profiling timer expired
|
||||
SIGWINCH = 28, // Window resize signal (4.3BSD, Sun)
|
||||
SIGIO = 29, // I/O now possible (4.2BSD)
|
||||
SIGPWR = 30, // Power failure (System V)
|
||||
SIGSYS = 31, // Bad system call (SVr4); see also seccomp(2)
|
||||
}
|
59
src/kxos-std/src/process/signal/mod.rs
Normal file
59
src/kxos-std/src/process/signal/mod.rs
Normal file
@ -0,0 +1,59 @@
|
||||
pub mod constants;
|
||||
pub mod sig_action;
|
||||
pub mod sig_disposition;
|
||||
pub mod sig_mask;
|
||||
pub mod sig_num;
|
||||
pub mod sig_queues;
|
||||
pub mod signals;
|
||||
|
||||
use crate::{
|
||||
prelude::*,
|
||||
process::signal::sig_action::{SigAction, SigDefaultAction},
|
||||
};
|
||||
|
||||
/// Handle pending signal for current process
|
||||
pub fn handle_pending_signal() {
|
||||
let current = current!();
|
||||
let sig_queues = current.sig_queues();
|
||||
let mut sig_queues_guard = sig_queues.lock();
|
||||
let sig_mask = current.sig_mask().lock().clone();
|
||||
if let Some(signal) = sig_queues_guard.dequeue(&sig_mask) {
|
||||
let sig_num = signal.num();
|
||||
debug!("sig_num = {:?}", sig_num);
|
||||
let sig_action = current.sig_dispositions().lock().get(sig_num);
|
||||
match sig_action {
|
||||
SigAction::Ign => {
|
||||
debug!("Ignore signal {:?}", sig_num);
|
||||
}
|
||||
SigAction::User { .. } => todo!(),
|
||||
SigAction::Dfl => {
|
||||
let sig_default_action = SigDefaultAction::from_signum(sig_num);
|
||||
match sig_default_action {
|
||||
SigDefaultAction::Core | SigDefaultAction::Term => {
|
||||
// FIXME: How to set correct status if process is terminated
|
||||
current.exit(1);
|
||||
}
|
||||
SigDefaultAction::Ign => {}
|
||||
SigDefaultAction::Stop => {
|
||||
let mut status_guard = current.status().lock();
|
||||
if status_guard.is_runnable() {
|
||||
status_guard.set_suspend();
|
||||
} else {
|
||||
panic!("Try to suspend a not running process.")
|
||||
}
|
||||
drop(status_guard);
|
||||
}
|
||||
SigDefaultAction::Cont => {
|
||||
let mut status_guard = current.status().lock();
|
||||
if status_guard.is_suspend() {
|
||||
status_guard.set_runnable();
|
||||
} else {
|
||||
panic!("Try to continue a not suspended process.")
|
||||
}
|
||||
drop(status_guard);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
94
src/kxos-std/src/process/signal/sig_action.rs
Normal file
94
src/kxos-std/src/process/signal/sig_action.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use super::{constants::*, sig_mask::SigMask, sig_num::SigNum};
|
||||
use bitflags::bitflags;
|
||||
use kxos_frame::warn;
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub enum SigAction {
|
||||
Dfl, // Default action
|
||||
Ign, // Ignore this signal
|
||||
User {
|
||||
// User-given handler
|
||||
handler_addr: usize,
|
||||
flags: SigActionFlags,
|
||||
restorer_addr: usize,
|
||||
mask: SigMask,
|
||||
},
|
||||
}
|
||||
|
||||
impl Default for SigAction {
|
||||
fn default() -> Self {
|
||||
SigAction::Dfl
|
||||
}
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct SigActionFlags: u32 {
|
||||
const SA_NOCLDSTOP = 1;
|
||||
const SA_NOCLDWAIT = 2;
|
||||
const SA_SIGINFO = 4;
|
||||
const SA_ONSTACK = 0x08000000;
|
||||
const SA_RESTART = 0x10000000;
|
||||
const SA_NODEFER = 0x40000000;
|
||||
const SA_RESETHAND = 0x80000000;
|
||||
const SA_RESTORER = 0x04000000;
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u32> for SigActionFlags {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(bits: u32) -> Result<Self, Self::Error> {
|
||||
let flags = SigActionFlags::from_bits(bits).ok_or_else(|| "invalid sigaction flags")?;
|
||||
if flags.contains(SigActionFlags::SA_RESTART) {
|
||||
warn!("SA_RESTART is not supported");
|
||||
}
|
||||
Ok(flags)
|
||||
}
|
||||
}
|
||||
|
||||
impl SigActionFlags {
|
||||
pub fn to_u32(&self) -> u32 {
|
||||
self.bits()
|
||||
}
|
||||
}
|
||||
|
||||
/// The default action to signals
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum SigDefaultAction {
|
||||
Term, // Default action is to terminate the process.
|
||||
Ign, // Default action is to ignore the signal.
|
||||
Core, // Default action is to terminate the process and dump core (see core(5)).
|
||||
Stop, // Default action is to stop the process.
|
||||
Cont, // Default action is to continue the process if it is currently stopped.
|
||||
}
|
||||
|
||||
impl SigDefaultAction {
|
||||
pub fn from_signum(num: SigNum) -> SigDefaultAction {
|
||||
match num {
|
||||
SIGABRT | // = SIGIOT
|
||||
SIGBUS |
|
||||
SIGFPE |
|
||||
SIGILL |
|
||||
SIGQUIT |
|
||||
SIGSEGV |
|
||||
SIGSYS | // = SIGUNUSED
|
||||
SIGTRAP |
|
||||
SIGXCPU |
|
||||
SIGXFSZ
|
||||
=> SigDefaultAction::Core,
|
||||
SIGCHLD |
|
||||
SIGURG |
|
||||
SIGWINCH
|
||||
=> SigDefaultAction::Ign,
|
||||
SIGCONT
|
||||
=> SigDefaultAction::Cont,
|
||||
SIGSTOP |
|
||||
SIGTSTP |
|
||||
SIGTTIN |
|
||||
SIGTTOU
|
||||
=> SigDefaultAction::Stop,
|
||||
_
|
||||
=> SigDefaultAction::Term,
|
||||
}
|
||||
}
|
||||
}
|
49
src/kxos-std/src/process/signal/sig_disposition.rs
Normal file
49
src/kxos-std/src/process/signal/sig_disposition.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use super::{constants::*, sig_action::SigAction, sig_num::SigNum};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct SigDispositions {
|
||||
// SigNum -> SigAction
|
||||
map: [SigAction; COUNT_ALL_SIGS],
|
||||
}
|
||||
|
||||
impl SigDispositions {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
map: [SigAction::default(); COUNT_ALL_SIGS],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get(&self, num: SigNum) -> SigAction {
|
||||
let idx = Self::num_to_idx(num);
|
||||
self.map[idx]
|
||||
}
|
||||
|
||||
pub fn set(&mut self, num: SigNum, sa: SigAction) {
|
||||
let idx = Self::num_to_idx(num);
|
||||
self.map[idx] = sa;
|
||||
}
|
||||
|
||||
pub fn set_default(&mut self, num: SigNum) {
|
||||
let idx = Self::num_to_idx(num);
|
||||
self.map[idx] = SigAction::Dfl;
|
||||
}
|
||||
|
||||
/// man 7 signal:
|
||||
/// When execve, the handled signals are reset to the default; the dispositions of
|
||||
/// ignored signals are left unchanged.
|
||||
/// This function should be used when execve.
|
||||
pub fn inherit(&mut self) {
|
||||
for sigaction in &mut self.map {
|
||||
match sigaction {
|
||||
SigAction::User { .. } => {
|
||||
*sigaction = SigAction::Dfl;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn num_to_idx(num: SigNum) -> usize {
|
||||
(num.as_u8() - MIN_STD_SIG_NUM) as usize
|
||||
}
|
||||
}
|
45
src/kxos-std/src/process/signal/sig_mask.rs
Normal file
45
src/kxos-std/src/process/signal/sig_mask.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use super::{constants::MIN_STD_SIG_NUM, sig_num::SigNum};
|
||||
|
||||
#[derive(Debug, Copy, Clone, Default, PartialEq, Eq)]
|
||||
pub struct SigMask {
|
||||
bits: u64,
|
||||
}
|
||||
|
||||
impl SigMask {
|
||||
pub const fn from_u64(bits: u64) -> Self {
|
||||
SigMask { bits }
|
||||
}
|
||||
|
||||
pub const fn new_empty() -> Self {
|
||||
SigMask::from_u64(0)
|
||||
}
|
||||
|
||||
pub const fn new_full() -> Self {
|
||||
SigMask::from_u64(!0)
|
||||
}
|
||||
|
||||
pub const fn as_u64(&self) -> u64 {
|
||||
self.bits
|
||||
}
|
||||
|
||||
pub const fn empty(&self) -> bool {
|
||||
self.bits == 0
|
||||
}
|
||||
|
||||
pub const fn full(&self) -> bool {
|
||||
self.bits == !0
|
||||
}
|
||||
|
||||
pub fn count(&self) -> usize {
|
||||
self.bits.count_ones() as usize
|
||||
}
|
||||
|
||||
pub fn contains(&self, signum: SigNum) -> bool {
|
||||
let idx = Self::num_to_idx(signum);
|
||||
(self.bits & (1_u64 << idx)) != 0
|
||||
}
|
||||
|
||||
fn num_to_idx(num: SigNum) -> usize {
|
||||
(num.as_u8() - MIN_STD_SIG_NUM) as usize
|
||||
}
|
||||
}
|
28
src/kxos-std/src/process/signal/sig_num.rs
Normal file
28
src/kxos-std/src/process/signal/sig_num.rs
Normal file
@ -0,0 +1,28 @@
|
||||
use super::constants::*;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct SigNum {
|
||||
sig_num: u8,
|
||||
}
|
||||
|
||||
impl SigNum {
|
||||
// Safety: This function should only be used when signum is ensured to be valid.
|
||||
pub const fn from_u8(sig_num: u8) -> Self {
|
||||
if sig_num > MAX_RT_SIG_NUM || sig_num < MIN_STD_SIG_NUM {
|
||||
unreachable!()
|
||||
}
|
||||
SigNum { sig_num }
|
||||
}
|
||||
|
||||
pub const fn as_u8(&self) -> u8 {
|
||||
self.sig_num
|
||||
}
|
||||
|
||||
pub fn is_std(&self) -> bool {
|
||||
self.sig_num <= MAX_STD_SIG_NUM
|
||||
}
|
||||
|
||||
pub fn is_real_time(&self) -> bool {
|
||||
self.sig_num >= MIN_RT_SIG_NUM
|
||||
}
|
||||
}
|
143
src/kxos-std/src/process/signal/sig_queues.rs
Normal file
143
src/kxos-std/src/process/signal/sig_queues.rs
Normal file
@ -0,0 +1,143 @@
|
||||
use super::constants::*;
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::sig_mask::SigMask;
|
||||
use super::sig_num::SigNum;
|
||||
use super::signals::Signal;
|
||||
|
||||
pub struct SigQueues {
|
||||
count: usize,
|
||||
std_queues: Vec<Option<Box<dyn Signal>>>,
|
||||
rt_queues: Vec<VecDeque<Box<dyn Signal>>>,
|
||||
}
|
||||
|
||||
impl SigQueues {
|
||||
pub fn new() -> Self {
|
||||
let count = 0;
|
||||
let std_queues = (0..COUNT_STD_SIGS).map(|_| None).collect();
|
||||
let rt_queues = (0..COUNT_RT_SIGS).map(|_| Default::default()).collect();
|
||||
// let notifier = Notifier::new();
|
||||
SigQueues {
|
||||
count,
|
||||
std_queues,
|
||||
rt_queues,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn empty(&self) -> bool {
|
||||
self.count == 0
|
||||
}
|
||||
|
||||
pub fn enqueue(&mut self, signal: Box<dyn Signal>) {
|
||||
let signum = signal.num();
|
||||
if signum.is_std() {
|
||||
// Standard signals
|
||||
//
|
||||
// From signal(7):
|
||||
//
|
||||
// Standard signals do not queue. If multiple instances of a standard
|
||||
// signal are generated while that signal is blocked, then only one
|
||||
// instance of the signal is marked as pending (and the signal will be
|
||||
// delivered just once when it is unblocked). In the case where a
|
||||
// standard signal is already pending, the siginfo_t structure (see
|
||||
// sigaction(2)) associated with that signal is not overwritten on
|
||||
// arrival of subsequent instances of the same signal. Thus, the
|
||||
// process will receive the information associated with the first
|
||||
// instance of the signal.
|
||||
let queue = self.get_std_queue_mut(signum);
|
||||
if queue.is_some() {
|
||||
// If there is already a signal pending, just ignore all subsequent signals
|
||||
return;
|
||||
}
|
||||
*queue = Some(signal);
|
||||
self.count += 1;
|
||||
} else {
|
||||
// Real-time signals
|
||||
let queue = self.get_rt_queue_mut(signum);
|
||||
queue.push_back(signal);
|
||||
self.count += 1;
|
||||
}
|
||||
|
||||
// self.notifier.broadcast(&signum);
|
||||
}
|
||||
|
||||
pub fn dequeue(&mut self, blocked: &SigMask) -> Option<Box<dyn Signal>> {
|
||||
// Fast path for the common case of no pending signals
|
||||
if self.empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Deliver standard signals.
|
||||
//
|
||||
// According to signal(7):
|
||||
// If both standard and real-time signals are pending for a process,
|
||||
// POSIX leaves it unspecified which is delivered first. Linux, like
|
||||
// many other implementations, gives priority to standard signals in
|
||||
// this case.
|
||||
|
||||
// POSIX leaves unspecified which to deliver first if there are multiple
|
||||
// pending standard signals. So we are free to define our own. The
|
||||
// principle is to give more urgent signals higher priority (like SIGKILL).
|
||||
const ORDERED_STD_SIGS: [SigNum; COUNT_STD_SIGS] = [
|
||||
SIGKILL, SIGTERM, SIGSTOP, SIGCONT, SIGSEGV, SIGILL, SIGHUP, SIGINT, SIGQUIT, SIGTRAP,
|
||||
SIGABRT, SIGBUS, SIGFPE, SIGUSR1, SIGUSR2, SIGPIPE, SIGALRM, SIGSTKFLT, SIGCHLD,
|
||||
SIGTSTP, SIGTTIN, SIGTTOU, SIGURG, SIGXCPU, SIGXFSZ, SIGVTALRM, SIGPROF, SIGWINCH,
|
||||
SIGIO, SIGPWR, SIGSYS,
|
||||
];
|
||||
for &signum in &ORDERED_STD_SIGS {
|
||||
if blocked.contains(signum) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let queue = self.get_std_queue_mut(signum);
|
||||
let signal = queue.take();
|
||||
if signal.is_some() {
|
||||
self.count -= 1;
|
||||
return signal;
|
||||
}
|
||||
}
|
||||
|
||||
// If no standard signals, then deliver real-time signals.
|
||||
//
|
||||
// According to signal (7):
|
||||
// Real-time signals are delivered in a guaranteed order. Multiple
|
||||
// real-time signals of the same type are delivered in the order
|
||||
// they were sent. If different real-time signals are sent to a
|
||||
// process, they are delivered starting with the lowest-numbered
|
||||
// signal. (I.e., low-numbered signals have highest priority.)
|
||||
for signum in MIN_RT_SIG_NUM..=MAX_RT_SIG_NUM {
|
||||
let signum = SigNum::from_u8(signum);
|
||||
if blocked.contains(signum) {
|
||||
continue;
|
||||
}
|
||||
|
||||
let queue = self.get_rt_queue_mut(signum);
|
||||
let signal = queue.pop_front();
|
||||
if signal.is_some() {
|
||||
self.count -= 1;
|
||||
return signal;
|
||||
}
|
||||
}
|
||||
|
||||
// There must be pending but blocked signals
|
||||
None
|
||||
}
|
||||
|
||||
fn get_std_queue_mut(&mut self, signum: SigNum) -> &mut Option<Box<dyn Signal>> {
|
||||
debug_assert!(signum.is_std());
|
||||
let idx = (signum.as_u8() - MIN_STD_SIG_NUM) as usize;
|
||||
&mut self.std_queues[idx]
|
||||
}
|
||||
|
||||
fn get_rt_queue_mut(&mut self, signum: SigNum) -> &mut VecDeque<Box<dyn Signal>> {
|
||||
debug_assert!(signum.is_real_time());
|
||||
let idx = (signum.as_u8() - MIN_RT_SIG_NUM) as usize;
|
||||
&mut self.rt_queues[idx]
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for SigQueues {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
10
src/kxos-std/src/process/signal/signals/mod.rs
Normal file
10
src/kxos-std/src/process/signal/signals/mod.rs
Normal file
@ -0,0 +1,10 @@
|
||||
pub mod user;
|
||||
|
||||
use core::fmt::Debug;
|
||||
|
||||
use super::sig_num::SigNum;
|
||||
|
||||
pub trait Signal: Send + Sync + Debug {
|
||||
/// Returns the number of the signal.
|
||||
fn num(&self) -> SigNum;
|
||||
}
|
49
src/kxos-std/src/process/signal/signals/user.rs
Normal file
49
src/kxos-std/src/process/signal/signals/user.rs
Normal file
@ -0,0 +1,49 @@
|
||||
use crate::process::{signal::sig_num::SigNum, Pid};
|
||||
|
||||
use super::Signal;
|
||||
|
||||
pub type Uid = usize;
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct UserSignal {
|
||||
num: SigNum,
|
||||
pid: Pid,
|
||||
uid: Uid,
|
||||
kind: UserSignalKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum UserSignalKind {
|
||||
Kill,
|
||||
Tkill,
|
||||
Sigqueue,
|
||||
}
|
||||
|
||||
impl UserSignal {
|
||||
pub fn new(num: SigNum, kind: UserSignalKind, pid: Pid, uid: Uid) -> Self {
|
||||
Self {
|
||||
num,
|
||||
kind,
|
||||
pid,
|
||||
uid,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pid(&self) -> Pid {
|
||||
self.pid
|
||||
}
|
||||
|
||||
pub fn uid(&self) -> Uid {
|
||||
self.uid
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> UserSignalKind {
|
||||
self.kind
|
||||
}
|
||||
}
|
||||
|
||||
impl Signal for UserSignal {
|
||||
fn num(&self) -> SigNum {
|
||||
self.num
|
||||
}
|
||||
}
|
@ -2,7 +2,11 @@
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum ProcessStatus {
|
||||
/// Can be scheduled to run
|
||||
Runnable,
|
||||
/// Suspend until be woken by SIGCONT signal
|
||||
SuspendSignalable,
|
||||
/// Exit while not reaped by parent
|
||||
Zombie,
|
||||
}
|
||||
|
||||
@ -14,4 +18,20 @@ impl ProcessStatus {
|
||||
pub fn is_zombie(&self) -> bool {
|
||||
*self == ProcessStatus::Zombie
|
||||
}
|
||||
|
||||
pub fn set_suspend(&mut self) {
|
||||
*self = ProcessStatus::SuspendSignalable;
|
||||
}
|
||||
|
||||
pub fn is_suspend(&self) -> bool {
|
||||
*self == ProcessStatus::SuspendSignalable
|
||||
}
|
||||
|
||||
pub fn set_runnable(&mut self) {
|
||||
*self = ProcessStatus::Runnable;
|
||||
}
|
||||
|
||||
pub fn is_runnable(&self) -> bool {
|
||||
*self == ProcessStatus::Runnable
|
||||
}
|
||||
}
|
||||
|
@ -4,10 +4,12 @@
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
use super::{Pid, Process};
|
||||
use super::{process_group::ProcessGroup, Pgid, Pid, Process};
|
||||
|
||||
lazy_static! {
|
||||
static ref PROCESS_TABLE: Mutex<BTreeMap<Pid, Arc<Process>>> = Mutex::new(BTreeMap::new());
|
||||
static ref PROCESS_GROUP_TABLE: Mutex<BTreeMap<Pgid, Arc<ProcessGroup>>> =
|
||||
Mutex::new(BTreeMap::new());
|
||||
}
|
||||
|
||||
/// add a process to global table
|
||||
@ -15,8 +17,8 @@ pub fn add_process(pid: Pid, process: Arc<Process>) {
|
||||
PROCESS_TABLE.lock().insert(pid, process);
|
||||
}
|
||||
|
||||
/// delete a process from global table
|
||||
pub fn delete_process(pid: Pid) {
|
||||
/// remove a process from global table
|
||||
pub fn remove_process(pid: Pid) {
|
||||
PROCESS_TABLE.lock().remove(&pid);
|
||||
}
|
||||
|
||||
@ -36,3 +38,21 @@ pub fn get_all_processes() -> Vec<Arc<Process>> {
|
||||
.map(|(_, process)| process.clone())
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// add process group to global table
|
||||
pub fn add_process_group(pgid: Pgid, process_group: Arc<ProcessGroup>) {
|
||||
PROCESS_GROUP_TABLE.lock().insert(pgid, process_group);
|
||||
}
|
||||
|
||||
/// remove process group from global table
|
||||
pub fn remove_process_group(pgid: Pgid) {
|
||||
PROCESS_GROUP_TABLE.lock().remove(&pgid);
|
||||
}
|
||||
|
||||
/// get a process group with pgid
|
||||
pub fn pgid_to_process_group(pgid: Pgid) -> Option<Arc<ProcessGroup>> {
|
||||
PROCESS_GROUP_TABLE
|
||||
.lock()
|
||||
.get(&pgid)
|
||||
.map(|process_group| process_group.clone())
|
||||
}
|
||||
|
@ -7,7 +7,7 @@ use kxos_frame::{
|
||||
vm::VmSpace,
|
||||
};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{prelude::*, process::signal::handle_pending_signal};
|
||||
|
||||
use crate::syscall::syscall_handler;
|
||||
|
||||
@ -47,28 +47,33 @@ pub fn create_new_task(userspace: Arc<UserSpace>, parent: Weak<Process>) -> Arc<
|
||||
loop {
|
||||
let user_event = user_mode.execute();
|
||||
let context = user_mode.context_mut();
|
||||
if let HandlerResult::Exit = handle_user_event(user_event, context) {
|
||||
// FIXME: How to set task status? How to set exit code of process?
|
||||
// handle user event:
|
||||
handle_user_event(user_event, context);
|
||||
let current = current!();
|
||||
// should be do this comparison before handle signal?
|
||||
if current.status().lock().is_zombie() {
|
||||
break;
|
||||
}
|
||||
// debug!("before return to user space: {:#x?}", context);
|
||||
handle_pending_signal();
|
||||
if current.status().lock().is_zombie() {
|
||||
break;
|
||||
}
|
||||
// If current is suspended, wait for a signal to wake up self
|
||||
while current.status().lock().is_suspend() {
|
||||
Process::yield_now();
|
||||
debug!("{} is suspended.", current.pid());
|
||||
handle_pending_signal();
|
||||
}
|
||||
}
|
||||
let current_process = Process::current();
|
||||
current_process.exit();
|
||||
}
|
||||
|
||||
Task::new(user_task_entry, parent, Some(userspace)).expect("spawn task failed")
|
||||
}
|
||||
|
||||
fn handle_user_event(user_event: UserEvent, context: &mut CpuContext) -> HandlerResult {
|
||||
fn handle_user_event(user_event: UserEvent, context: &mut CpuContext) {
|
||||
match user_event {
|
||||
UserEvent::Syscall => syscall_handler(context),
|
||||
UserEvent::Fault => todo!(),
|
||||
UserEvent::Exception => todo!(),
|
||||
}
|
||||
}
|
||||
|
||||
pub enum HandlerResult {
|
||||
Exit,
|
||||
Continue,
|
||||
}
|
||||
|
@ -35,6 +35,8 @@ pub fn sys_execve(
|
||||
let elf_load_info =
|
||||
load_elf_to_vm_space(filename, elf_file_content, &vm_space).expect("load elf failed");
|
||||
debug!("load elf in execve succeeds");
|
||||
// set signal disposition to default
|
||||
current.sig_dispositions().lock().inherit();
|
||||
// set cpu context to default
|
||||
let defalut_content = CpuContext::default();
|
||||
context.gp_regs = defalut_content.gp_regs;
|
||||
|
@ -1,11 +1,11 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::{process::Process, syscall::SYS_EXIT};
|
||||
use crate::syscall::SYS_EXIT;
|
||||
|
||||
use super::SyscallResult;
|
||||
|
||||
pub fn sys_exit(exit_code: i32) -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_EXIT]", SYS_EXIT);
|
||||
Process::current().set_exit_code(exit_code);
|
||||
SyscallResult::Exit(exit_code)
|
||||
current!().exit(exit_code);
|
||||
SyscallResult::NotReturn
|
||||
}
|
||||
|
@ -1,12 +1,9 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::{
|
||||
process::Process,
|
||||
syscall::{SyscallResult, SYS_EXIT_GROUP},
|
||||
};
|
||||
use crate::syscall::{SyscallResult, SYS_EXIT_GROUP};
|
||||
|
||||
pub fn sys_exit_group(exit_code: u64) -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_EXIT_GROUP]", SYS_EXIT_GROUP);
|
||||
Process::current().set_exit_code(exit_code as _);
|
||||
SyscallResult::Exit(exit_code as _)
|
||||
current!().exit(exit_code as _);
|
||||
SyscallResult::NotReturn
|
||||
}
|
||||
|
55
src/kxos-std/src/syscall/kill.rs
Normal file
55
src/kxos-std/src/syscall/kill.rs
Normal file
@ -0,0 +1,55 @@
|
||||
use crate::prelude::*;
|
||||
|
||||
use crate::process::signal::signals::user::{UserSignal, UserSignalKind};
|
||||
use crate::process::{table, Process};
|
||||
use crate::{
|
||||
process::{process_filter::ProcessFilter, signal::sig_num::SigNum},
|
||||
syscall::SYS_KILL,
|
||||
};
|
||||
|
||||
use super::SyscallResult;
|
||||
|
||||
pub fn sys_kill(process_filter: u64, sig_num: u64) -> SyscallResult {
|
||||
debug!("[syscall][id={}][SYS_KILL]", SYS_KILL);
|
||||
let process_filter = ProcessFilter::from_id(process_filter as _);
|
||||
let sig_num = SigNum::from_u8(sig_num as _);
|
||||
let _ = do_sys_kill(process_filter, sig_num);
|
||||
SyscallResult::Return(0)
|
||||
}
|
||||
|
||||
pub fn do_sys_kill(process_filter: ProcessFilter, sig_num: SigNum) -> Result<()> {
|
||||
let current = current!();
|
||||
let pid = current.pid();
|
||||
// FIXME: use the correct uid
|
||||
let uid = 0;
|
||||
let processes = get_processes(&process_filter)?;
|
||||
for process in processes.iter() {
|
||||
if process.status().lock().is_zombie() {
|
||||
continue;
|
||||
}
|
||||
|
||||
let signal = Box::new(UserSignal::new(sig_num, UserSignalKind::Kill, pid, uid));
|
||||
let sig_queues = process.sig_queues();
|
||||
sig_queues.lock().enqueue(signal);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_processes(filter: &ProcessFilter) -> Result<Vec<Arc<Process>>> {
|
||||
let processes = match filter {
|
||||
ProcessFilter::Any => {
|
||||
let mut processes = table::get_all_processes();
|
||||
processes.retain(|process| process.pid() != 0);
|
||||
processes
|
||||
}
|
||||
ProcessFilter::WithPid(pid) => {
|
||||
let process = table::pid_to_process(*pid);
|
||||
match process {
|
||||
None => return_errno!(Errno::ESRCH),
|
||||
Some(process) => vec![process],
|
||||
}
|
||||
}
|
||||
ProcessFilter::WithPgid(_) => todo!(),
|
||||
};
|
||||
Ok(processes)
|
||||
}
|
@ -3,10 +3,10 @@
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::syscall::clone::sys_clone;
|
||||
use crate::syscall::kill::sys_kill;
|
||||
use alloc::borrow::ToOwned;
|
||||
use kxos_frame::cpu::CpuContext;
|
||||
|
||||
use crate::process::task::HandlerResult;
|
||||
use crate::syscall::access::sys_access;
|
||||
use crate::syscall::arch_prctl::sys_arch_prctl;
|
||||
use crate::syscall::brk::sys_brk;
|
||||
@ -41,6 +41,7 @@ mod fstat;
|
||||
mod futex;
|
||||
mod getpid;
|
||||
mod gettid;
|
||||
mod kill;
|
||||
mod mmap;
|
||||
mod mprotect;
|
||||
mod readlink;
|
||||
@ -68,6 +69,7 @@ const SYS_FORK: u64 = 57;
|
||||
const SYS_EXECVE: u64 = 59;
|
||||
const SYS_EXIT: u64 = 60;
|
||||
const SYS_WAIT4: u64 = 61;
|
||||
const SYS_KILL: u64 = 62;
|
||||
const SYS_UNAME: u64 = 63;
|
||||
const SYS_READLINK: u64 = 89;
|
||||
const SYS_GETUID: u64 = 102;
|
||||
@ -87,9 +89,8 @@ pub struct SyscallArgument {
|
||||
}
|
||||
|
||||
pub enum SyscallResult {
|
||||
Exit(i32),
|
||||
Return(i32),
|
||||
ReturnNothing, // execve return nothing
|
||||
NotReturn,
|
||||
}
|
||||
|
||||
impl SyscallArgument {
|
||||
@ -109,19 +110,14 @@ impl SyscallArgument {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn syscall_handler(context: &mut CpuContext) -> HandlerResult {
|
||||
pub fn syscall_handler(context: &mut CpuContext) {
|
||||
let syscall_frame = SyscallArgument::new_from_context(context);
|
||||
let syscall_return =
|
||||
syscall_dispatch(syscall_frame.syscall_number, syscall_frame.args, context);
|
||||
|
||||
match syscall_return {
|
||||
SyscallResult::Return(return_value) => {
|
||||
// FIXME: set return value?
|
||||
context.gp_regs.rax = return_value as u64;
|
||||
HandlerResult::Continue
|
||||
}
|
||||
SyscallResult::Exit(exit_code) => HandlerResult::Exit,
|
||||
SyscallResult::ReturnNothing => HandlerResult::Continue,
|
||||
if let SyscallResult::Return(return_value) = syscall_return {
|
||||
// FIXME: set return value?
|
||||
context.gp_regs.rax = return_value as u64;
|
||||
}
|
||||
}
|
||||
|
||||
@ -153,6 +149,7 @@ pub fn syscall_dispatch(
|
||||
SYS_EXECVE => sys_execve(args[0] as _, args[1] as _, args[2] as _, context),
|
||||
SYS_EXIT => sys_exit(args[0] as _),
|
||||
SYS_WAIT4 => sys_wait4(args[0], args[1], args[2]),
|
||||
SYS_KILL => sys_kill(args[0], args[1]),
|
||||
SYS_UNAME => sys_uname(args[0]),
|
||||
SYS_READLINK => sys_readlink(args[0], args[1], args[2]),
|
||||
SYS_GETUID => sys_getuid(),
|
||||
|
@ -14,7 +14,7 @@ pub fn sys_wait4(wait_pid: u64, exit_status_ptr: u64, wait_options: u64) -> Sysc
|
||||
debug!("pid = {}", wait_pid as isize);
|
||||
debug!("exit_status_ptr = {}", exit_status_ptr);
|
||||
debug!("wait_options: {:?}", wait_options);
|
||||
let process_filter = ProcessFilter::from_wait_pid(wait_pid as _);
|
||||
let process_filter = ProcessFilter::from_id(wait_pid as _);
|
||||
let (return_pid, exit_code) = wait_child_exit(process_filter, wait_options);
|
||||
if return_pid != 0 && exit_status_ptr != 0 {
|
||||
write_val_to_user(exit_status_ptr as _, &exit_code);
|
||||
|
Loading…
x
Reference in New Issue
Block a user