WIP: Signal handling
This commit is contained in:
@@ -46,8 +46,13 @@
|
||||
/// Size of user stack
|
||||
pub const USER_STACK_SIZE: usize = 1024 * 1024; // 1 MB
|
||||
|
||||
/// Offset to user sigstack
|
||||
pub const USER_SIGSTACK_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE;
|
||||
/// Size of user sigstack
|
||||
pub const USER_SIGSTACK_SIZE: usize = 256 * 1024; // 256 KB
|
||||
|
||||
/// Offset to user TLS
|
||||
pub const USER_TLS_OFFSET: usize = USER_STACK_OFFSET + PML4_SIZE;
|
||||
pub const USER_TLS_OFFSET: usize = USER_SIGSTACK_OFFSET + PML4_SIZE;
|
||||
|
||||
/// Offset to user temporary image (used when cloning)
|
||||
pub const USER_TMP_OFFSET: usize = USER_TLS_OFFSET + PML4_SIZE;
|
||||
@@ -61,8 +66,11 @@
|
||||
/// Offset to user temporary stack (used when cloning)
|
||||
pub const USER_TMP_STACK_OFFSET: usize = USER_TMP_GRANT_OFFSET + PML4_SIZE;
|
||||
|
||||
/// Offset to user temporary sigstack (used when cloning)
|
||||
pub const USER_TMP_SIGSTACK_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE;
|
||||
|
||||
/// Offset to user temporary tls (used when cloning)
|
||||
pub const USER_TMP_TLS_OFFSET: usize = USER_TMP_STACK_OFFSET + PML4_SIZE;
|
||||
pub const USER_TMP_TLS_OFFSET: usize = USER_TMP_SIGSTACK_OFFSET + PML4_SIZE;
|
||||
|
||||
/// Offset for usage in other temporary pages
|
||||
pub const USER_TMP_MISC_OFFSET: usize = USER_TMP_TLS_OFFSET + PML4_SIZE;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use alloc::arc::Arc;
|
||||
use alloc::boxed::Box;
|
||||
use collections::{BTreeMap, Vec, VecDeque};
|
||||
use core::mem;
|
||||
use spin::Mutex;
|
||||
|
||||
use context::arch;
|
||||
@@ -8,7 +9,8 @@ use context::file::File;
|
||||
use context::memory::{Grant, Memory, SharedMemory, Tls};
|
||||
use device;
|
||||
use scheme::{SchemeNamespace, FileHandle};
|
||||
use syscall::data::Event;
|
||||
use syscall::data::{Event, SigAction};
|
||||
use syscall::flag::SIG_DFL;
|
||||
use sync::{WaitMap, WaitQueue};
|
||||
|
||||
/// Unique identifier for a context (i.e. `pid`).
|
||||
@@ -69,6 +71,8 @@ pub struct Context {
|
||||
pub heap: Option<SharedMemory>,
|
||||
/// User stack
|
||||
pub stack: Option<Memory>,
|
||||
/// User signal stack
|
||||
pub sigstack: Option<Memory>,
|
||||
/// User Thread local storage
|
||||
pub tls: Option<Tls>,
|
||||
/// User grants
|
||||
@@ -83,8 +87,8 @@ pub struct Context {
|
||||
pub env: Arc<Mutex<BTreeMap<Box<[u8]>, Arc<Mutex<Vec<u8>>>>>>,
|
||||
/// The open files in the scheme
|
||||
pub files: Arc<Mutex<Vec<Option<File>>>>,
|
||||
/// Singal handlers
|
||||
pub handlers: Arc<Mutex<BTreeMap<u8, usize>>>,
|
||||
/// Singal actions
|
||||
pub actions: Arc<Mutex<Vec<SigAction>>>,
|
||||
}
|
||||
|
||||
impl Context {
|
||||
@@ -111,6 +115,7 @@ impl Context {
|
||||
image: Vec::new(),
|
||||
heap: None,
|
||||
stack: None,
|
||||
sigstack: None,
|
||||
tls: None,
|
||||
grants: Arc::new(Mutex::new(Vec::new())),
|
||||
name: Arc::new(Mutex::new(Vec::new())),
|
||||
@@ -118,7 +123,12 @@ impl Context {
|
||||
events: Arc::new(WaitQueue::new()),
|
||||
env: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
files: Arc::new(Mutex::new(Vec::new())),
|
||||
handlers: Arc::new(Mutex::new(BTreeMap::new())),
|
||||
actions: Arc::new(Mutex::new(vec![SigAction {
|
||||
sa_handler: unsafe { mem::transmute(SIG_DFL) },
|
||||
sa_mask: [0; 2],
|
||||
sa_flags: 0,
|
||||
sa_restorer: unsafe { mem::transmute(0usize) },
|
||||
}; 128])),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
use core::mem;
|
||||
use core::sync::atomic::Ordering;
|
||||
use context::{arch, contexts, Context, Status, CONTEXT_ID};
|
||||
use interrupt::irq::PIT_TICKS;
|
||||
use start::usermode;
|
||||
use syscall::flag::{SIG_DFL, SIG_IGN};
|
||||
|
||||
use gdt;
|
||||
use interrupt;
|
||||
use interrupt::irq::PIT_TICKS;
|
||||
use syscall;
|
||||
use time;
|
||||
|
||||
@@ -118,19 +121,35 @@ pub unsafe fn switch() -> bool {
|
||||
}
|
||||
|
||||
extern "C" fn signal_handler(sig: usize) {
|
||||
let handler = {
|
||||
let action = {
|
||||
let contexts = contexts();
|
||||
let context_lock = contexts.current().expect("context::signal_handler not inside of context");
|
||||
let context = context_lock.read();
|
||||
let handlers = context.handlers.lock();
|
||||
handlers.get(&(sig as u8)).map_or(0, |sig| *sig)
|
||||
let actions = context.actions.lock();
|
||||
actions[sig]
|
||||
};
|
||||
|
||||
println!("Signal handler: {}, {:X}", sig, handler);
|
||||
println!("Signal handler: {:X}, {:?}", sig, action);
|
||||
|
||||
if handler == 0 {
|
||||
let handler = action.sa_handler as usize;
|
||||
let restorer = action.sa_restorer as usize;
|
||||
if handler == SIG_DFL {
|
||||
println!("Exit {:X}", sig);
|
||||
syscall::exit(sig);
|
||||
} else if handler == SIG_IGN {
|
||||
println!("Ignore");
|
||||
} else {
|
||||
// TODO: Call handler
|
||||
println!("Call {:X}", handler);
|
||||
|
||||
unsafe {
|
||||
let mut sp = ::USER_SIGSTACK_OFFSET + ::USER_SIGSTACK_SIZE - 256;
|
||||
|
||||
sp = (sp / 16) * 16;
|
||||
|
||||
sp -= mem::size_of::<usize>();
|
||||
*(sp as *mut usize) = restorer;
|
||||
|
||||
usermode(handler, sp, sig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -72,6 +72,9 @@ pub fn resource() -> Result<Vec<u8>> {
|
||||
if let Some(ref stack) = context.stack {
|
||||
memory += stack.size();
|
||||
}
|
||||
if let Some(ref sigstack) = context.sigstack {
|
||||
memory += sigstack.size();
|
||||
}
|
||||
|
||||
let memory_string = if memory >= 1024 * 1024 * 1024 {
|
||||
format!("{} GB", memory / 1024 / 1024 / 1024)
|
||||
|
||||
33
src/start.rs
33
src/start.rs
@@ -156,25 +156,26 @@ pub unsafe extern fn kstart_ap(cpu_id: usize, bsp_table: usize, stack_start: usi
|
||||
kmain_ap(cpu_id);
|
||||
}
|
||||
|
||||
pub unsafe fn usermode(ip: usize, sp: usize) -> ! {
|
||||
pub unsafe fn usermode(ip: usize, sp: usize, arg: usize) -> ! {
|
||||
// Go to usermode
|
||||
asm!("mov ds, ax
|
||||
mov es, ax
|
||||
mov fs, bx
|
||||
mov gs, ax
|
||||
push rax
|
||||
push rcx
|
||||
push rdx
|
||||
push rsi
|
||||
push rdi
|
||||
asm!("mov ds, r10d
|
||||
mov es, r10d
|
||||
mov fs, r11d
|
||||
mov gs, r10d
|
||||
push r10
|
||||
push r12
|
||||
push r13
|
||||
push r14
|
||||
push r15
|
||||
iretq"
|
||||
: // No output because it never returns
|
||||
: "{rax}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
|
||||
"{rbx}"(gdt::GDT_USER_TLS << 3 | 3), // TLS segment
|
||||
"{rcx}"(sp), // Stack pointer
|
||||
"{rdx}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag
|
||||
"{rsi}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
|
||||
"{rdi}"(ip) // IP
|
||||
: "{r10}"(gdt::GDT_USER_DATA << 3 | 3), // Data segment
|
||||
"{r11}"(gdt::GDT_USER_TLS << 3 | 3), // TLS segment
|
||||
"{r12}"(sp), // Stack pointer
|
||||
"{r13}"(3 << 12 | 1 << 9), // Flags - Set IOPL and interrupt enable flag
|
||||
"{r14}"(gdt::GDT_USER_CODE << 3 | 3), // Code segment
|
||||
"{r15}"(ip) // IP
|
||||
"{rdi}"(arg) // Argument
|
||||
: // No clobers because it never returns
|
||||
: "intel", "volatile");
|
||||
unreachable!();
|
||||
|
||||
@@ -12,7 +12,7 @@ pub use self::process::*;
|
||||
pub use self::time::*;
|
||||
pub use self::validate::*;
|
||||
|
||||
use self::data::TimeSpec;
|
||||
use self::data::{SigAction, TimeSpec};
|
||||
use self::error::{Error, Result, ENOSYS};
|
||||
use self::number::*;
|
||||
|
||||
@@ -70,7 +70,14 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
|
||||
},
|
||||
_ => match a {
|
||||
SYS_YIELD => sched_yield(),
|
||||
SYS_NANOSLEEP => nanosleep(validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?, validate_slice_mut(c as *mut TimeSpec, 1).ok().map(|rem| &mut rem[0])),
|
||||
SYS_NANOSLEEP => nanosleep(
|
||||
validate_slice(b as *const TimeSpec, 1).map(|req| &req[0])?,
|
||||
if c == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(validate_slice_mut(c as *mut TimeSpec, 1).map(|rem| &mut rem[0])?)
|
||||
}
|
||||
),
|
||||
SYS_CLOCK_GETTIME => clock_gettime(b, validate_slice_mut(c as *mut TimeSpec, 1).map(|time| &mut time[0])?),
|
||||
SYS_FUTEX => futex(validate_slice_mut(b as *mut i32, 1).map(|uaddr| &mut uaddr[0])?, c, d as i32, e, f as *mut i32),
|
||||
SYS_BRK => brk(b),
|
||||
@@ -80,7 +87,6 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
|
||||
SYS_EXIT => exit((b & 0xFF) << 8),
|
||||
SYS_KILL => kill(ContextId::from(b), c),
|
||||
SYS_WAITPID => waitpid(ContextId::from(b), c, d).map(ContextId::into),
|
||||
SYS_SIGNAL => signal(b, c),
|
||||
SYS_CHDIR => chdir(validate_slice(b as *const u8, c)?),
|
||||
SYS_EXECVE => exec(validate_slice(b as *const u8, c)?, validate_slice(d as *const [usize; 2], e)?),
|
||||
SYS_IOPL => iopl(b, stack),
|
||||
@@ -95,6 +101,19 @@ pub extern fn syscall(a: usize, b: usize, c: usize, d: usize, e: usize, f: usize
|
||||
SYS_SETREUID => setreuid(b as u32, c as u32),
|
||||
SYS_SETRENS => setrens(SchemeNamespace::from(b), SchemeNamespace::from(c)),
|
||||
SYS_SETREGID => setregid(b as u32, c as u32),
|
||||
SYS_SIGACTION => sigaction(
|
||||
b,
|
||||
if c == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(validate_slice(c as *const SigAction, 1).map(|act| &act[0])?)
|
||||
},
|
||||
if d == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(validate_slice_mut(d as *mut SigAction, 1).map(|oldact| &mut oldact[0])?)
|
||||
}
|
||||
),
|
||||
SYS_PIPE2 => pipe2(validate_slice_mut(b as *mut usize, 2)?, c),
|
||||
SYS_PHYSALLOC => physalloc(b),
|
||||
SYS_PHYSFREE => physfree(b, c),
|
||||
|
||||
@@ -18,7 +18,7 @@ use context::ContextId;
|
||||
use elf::{self, program_header};
|
||||
use scheme::{self, FileHandle};
|
||||
use syscall;
|
||||
use syscall::data::Stat;
|
||||
use syscall::data::{SigAction, Stat};
|
||||
use syscall::error::*;
|
||||
use syscall::flag::{CLONE_VFORK, CLONE_VM, CLONE_FS, CLONE_FILES, CLONE_SIGHAND, O_CLOEXEC, SIG_DFL, WNOHANG};
|
||||
use syscall::validate::{validate_slice, validate_slice_mut};
|
||||
@@ -79,13 +79,14 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
let mut image = vec![];
|
||||
let mut heap_option = None;
|
||||
let mut stack_option = None;
|
||||
let mut sigstack_option = None;
|
||||
let mut tls_option = None;
|
||||
let grants;
|
||||
let name;
|
||||
let cwd;
|
||||
let env;
|
||||
let files;
|
||||
let handlers;
|
||||
let actions;
|
||||
|
||||
// Copy from old process
|
||||
{
|
||||
@@ -195,6 +196,24 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
stack_option = Some(new_stack);
|
||||
}
|
||||
|
||||
if let Some(ref sigstack) = context.sigstack {
|
||||
let mut new_sigstack = context::memory::Memory::new(
|
||||
VirtualAddress::new(::USER_TMP_SIGSTACK_OFFSET),
|
||||
sigstack.size(),
|
||||
entry::PRESENT | entry::NO_EXECUTE | entry::WRITABLE,
|
||||
false
|
||||
);
|
||||
|
||||
unsafe {
|
||||
intrinsics::copy(sigstack.start_address().get() as *const u8,
|
||||
new_sigstack.start_address().get() as *mut u8,
|
||||
sigstack.size());
|
||||
}
|
||||
|
||||
new_sigstack.remap(sigstack.flags());
|
||||
sigstack_option = Some(new_sigstack);
|
||||
}
|
||||
|
||||
if let Some(ref tls) = context.tls {
|
||||
let mut new_tls = context::memory::Tls {
|
||||
master: tls.master,
|
||||
@@ -252,9 +271,9 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
}
|
||||
|
||||
if flags & CLONE_SIGHAND == CLONE_SIGHAND {
|
||||
handlers = context.handlers.clone();
|
||||
actions = context.actions.clone();
|
||||
} else {
|
||||
handlers = Arc::new(Mutex::new(context.handlers.lock().clone()));
|
||||
actions = Arc::new(Mutex::new(context.actions.lock().clone()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -441,6 +460,12 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
context.stack = Some(stack);
|
||||
}
|
||||
|
||||
// Setup user sigstack
|
||||
if let Some(mut sigstack) = sigstack_option {
|
||||
sigstack.move_to(VirtualAddress::new(::USER_SIGSTACK_OFFSET), &mut new_table, &mut temporary_page);
|
||||
context.sigstack = Some(sigstack);
|
||||
}
|
||||
|
||||
// Setup user TLS
|
||||
if let Some(mut tls) = tls_option {
|
||||
tls.mem.move_to(VirtualAddress::new(::USER_TLS_OFFSET), &mut new_table, &mut temporary_page);
|
||||
@@ -455,7 +480,7 @@ pub fn clone(flags: usize, stack_base: usize) -> Result<ContextId> {
|
||||
|
||||
context.files = files;
|
||||
|
||||
context.handlers = handlers;
|
||||
context.actions = actions;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -470,12 +495,14 @@ fn empty(context: &mut context::Context, reaping: bool) {
|
||||
assert!(context.image.is_empty());
|
||||
assert!(context.heap.is_none());
|
||||
assert!(context.stack.is_none());
|
||||
assert!(context.sigstack.is_none());
|
||||
assert!(context.tls.is_none());
|
||||
} else {
|
||||
// Unmap previous image, heap, grants, stack, and tls
|
||||
context.image.clear();
|
||||
drop(context.heap.take());
|
||||
drop(context.stack.take());
|
||||
drop(context.sigstack.take());
|
||||
drop(context.tls.take());
|
||||
}
|
||||
|
||||
@@ -673,6 +700,14 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||
true
|
||||
));
|
||||
|
||||
// Map stack
|
||||
context.sigstack = Some(context::memory::Memory::new(
|
||||
VirtualAddress::new(::USER_SIGSTACK_OFFSET),
|
||||
::USER_SIGSTACK_SIZE,
|
||||
entry::NO_EXECUTE | entry::WRITABLE | entry::USER_ACCESSIBLE,
|
||||
true
|
||||
));
|
||||
|
||||
// Map TLS
|
||||
if let Some((master, file_size, size)) = tls_option {
|
||||
let tls = context::memory::Tls {
|
||||
@@ -737,7 +772,12 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||
let files = Arc::new(Mutex::new(context.files.lock().clone()));
|
||||
context.files = files.clone();
|
||||
|
||||
context.handlers = Arc::new(Mutex::new(BTreeMap::new()));
|
||||
context.actions = Arc::new(Mutex::new(vec![SigAction {
|
||||
sa_handler: unsafe { mem::transmute(SIG_DFL) },
|
||||
sa_mask: [0; 2],
|
||||
sa_flags: 0,
|
||||
sa_restorer: unsafe { mem::transmute(0usize) },
|
||||
}; 128]));
|
||||
|
||||
let vfork = context.vfork;
|
||||
context.vfork = false;
|
||||
@@ -819,7 +859,7 @@ pub fn exec(path: &[u8], arg_ptrs: &[[usize; 2]]) -> Result<usize> {
|
||||
}
|
||||
|
||||
// Go to usermode
|
||||
unsafe { usermode(entry, sp); }
|
||||
unsafe { usermode(entry, sp, 0); }
|
||||
}
|
||||
|
||||
pub fn exit(status: usize) -> ! {
|
||||
@@ -971,18 +1011,22 @@ pub fn kill(pid: ContextId, sig: usize) -> Result<usize> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn signal(sig: usize, handler: usize) -> Result<usize> {
|
||||
pub fn sigaction(sig: usize, act_opt: Option<&SigAction>, oldact_opt: Option<&mut SigAction>) -> Result<usize> {
|
||||
if sig > 0 && sig <= 0x7F {
|
||||
let contexts = context::contexts();
|
||||
let context_lock = contexts.current().ok_or(Error::new(ESRCH))?;
|
||||
let context = context_lock.read();
|
||||
let mut handlers = context.handlers.lock();
|
||||
let previous = if handler == SIG_DFL {
|
||||
handlers.remove(&(sig as u8))
|
||||
} else {
|
||||
handlers.insert(sig as u8, handler)
|
||||
};
|
||||
Ok(previous.unwrap_or(0))
|
||||
let mut actions = context.actions.lock();
|
||||
|
||||
if let Some(oldact) = oldact_opt {
|
||||
*oldact = actions[sig];
|
||||
}
|
||||
|
||||
if let Some(act) = act_opt {
|
||||
actions[sig] = *act;
|
||||
}
|
||||
|
||||
Ok(0)
|
||||
} else {
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user