Skip to content
Snippets Groups Projects
Verified Commit 98ac085c authored by Jacob Lorentzon's avatar Jacob Lorentzon
Browse files

Add sigprocmask stub to rt.

parent e1d3bf47
No related branches found
No related tags found
1 merge request!480Refactor redox runtime and impl signals in userspace
...@@ -370,6 +370,7 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7" ...@@ -370,6 +370,7 @@ checksum = "64072665120942deff5fd5425d6c1811b854f4939e7f1c01ce755f64432bbea7"
name = "redox-rt" name = "redox-rt"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"bitflags",
"goblin", "goblin",
"plain", "plain",
"redox_syscall", "redox_syscall",
......
...@@ -9,6 +9,7 @@ description = "Libc-independent runtime for Redox" ...@@ -9,6 +9,7 @@ description = "Libc-independent runtime for Redox"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
redox_syscall = "0.5.1" bitflags = "2"
goblin = { version = "0.7", default-features = false, features = ["elf32", "elf64", "endian_fd"] } goblin = { version = "0.7", default-features = false, features = ["elf32", "elf64", "endian_fd"] }
plain = "0.2" plain = "0.2"
redox_syscall = "0.5.1"
...@@ -31,4 +31,5 @@ pub mod proc; ...@@ -31,4 +31,5 @@ pub mod proc;
pub mod auxv_defs; pub mod auxv_defs;
pub mod signal; pub mod signal;
pub mod sync;
pub mod thread; pub mod thread;
...@@ -709,8 +709,7 @@ pub fn create_set_addr_space_buf( ...@@ -709,8 +709,7 @@ pub fn create_set_addr_space_buf(
/// descriptors from other schemes are reobtained with `dup`, and grants referencing such file /// descriptors from other schemes are reobtained with `dup`, and grants referencing such file
/// descriptors are reobtained through `fmap`. Other mappings are kept but duplicated using CoW. /// descriptors are reobtained through `fmap`. Other mappings are kept but duplicated using CoW.
pub fn fork_impl() -> Result<usize> { pub fn fork_impl() -> Result<usize> {
let mut old_mask = 0_u64; let mut old_mask = crate::signal::get_sigmask()?;
crate::signal::set_sigmask(None, Some(&mut old_mask))?;
let pid = unsafe { Error::demux(__relibc_internal_fork_wrapper())? }; let pid = unsafe { Error::demux(__relibc_internal_fork_wrapper())? };
if pid == 0 { if pid == 0 {
......
use core::cell::Cell; use core::cell::Cell;
use core::ffi::c_int; use core::ffi::c_int;
use core::sync::atomic::{AtomicU64, Ordering};
use syscall::{Result, Sigcontrol}; use syscall::{Result, Sigcontrol, SIGCHLD, SIGCONT, SIGURG, SIGWINCH};
use crate::arch::*; use crate::arch::*;
use crate::sync::Mutex;
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0); static CPUID_EAX1_ECX: core::sync::atomic::AtomicU32 = core::sync::atomic::AtomicU32::new(0);
...@@ -24,28 +26,6 @@ pub fn sighandler_function() -> usize { ...@@ -24,28 +26,6 @@ pub fn sighandler_function() -> usize {
} }
} }
pub fn setup_sighandler(control: &Sigcontrol) {
#[cfg(target_arch = "x86_64")]
{
let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx;
CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed);
}
let data = syscall::SetSighandlerData {
user_handler: sighandler_function(),
excp_handler: 0, // TODO
word_addr: control as *const Sigcontrol as usize,
};
let fd = syscall::open(
"thisproc:current/sighandler",
syscall::O_WRONLY | syscall::O_CLOEXEC,
)
.expect("failed to open thisproc:current/sighandler");
syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler");
let _ = syscall::close(fd);
}
#[repr(C)] #[repr(C)]
pub struct SigStack { pub struct SigStack {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
...@@ -72,19 +52,61 @@ unsafe extern "fastcall" fn inner_fastcall(stack: usize) { ...@@ -72,19 +52,61 @@ unsafe extern "fastcall" fn inner_fastcall(stack: usize) {
inner(&mut *(stack as *mut SigStack)) inner(&mut *(stack as *mut SigStack))
} }
pub fn get_sigmask() -> Result<u64> {
let mut mask = 0;
modify_sigmask(Some(&mut mask), Option::<fn(u32, bool) -> u32>::None)?;
Ok(mask)
}
pub fn set_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> { pub fn set_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> {
todo!() modify_sigmask(old, new.map(move |newmask| move |_, upper| if upper { newmask >> 32 } else { newmask } as u32))
} }
pub fn or_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> { pub fn or_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> {
todo!() // Parsing nightmare...
modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask | if upper { newmask >> 32 } else { newmask } as u32))
} }
pub fn andn_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> { pub fn andn_sigmask(new: Option<u64>, old: Option<&mut u64>) -> Result<()> {
todo!() modify_sigmask(old, new.map(move |newmask| move |oldmask, upper| oldmask & !if upper { newmask >> 32 } else { newmask } as u32))
}
fn modify_sigmask(old: Option<&mut u64>, op: Option<impl FnMut(u32, bool) -> u32>) -> Result<()> {
let _guard = tmp_disable_signals();
let ctl = current_sigctl();
let mut words = ctl.word.each_ref().map(|w| w.load(Ordering::Relaxed));
if let Some(old) = old {
*old = combine_mask(words);
}
let Some(mut op) = op else {
return Ok(());
};
let mut can_raise = 0;
let mut cant_raise = 0;
for i in 0..2 {
while let Err(changed) = ctl.word[i].compare_exchange(words[i], ((words[i] >> 32) << 32) | u64::from(op(words[i] as u32, i == 1)), Ordering::Relaxed, Ordering::Relaxed) {
// If kernel observed a signal being unblocked and pending simultaneously, it will have
// set a flag causing it to check for the INHIBIT_SIGNALS flag every time the context
// is switched to. To avoid race conditions, we should NOT auto-raise those signals in
// userspace as a result of unblocking it. The kernel will instead take care of that later.
can_raise |= (changed & (changed >> 32)) << (32 * i);
cant_raise |= (changed & !(changed >> 32)) << (32 * i);
words[i] = changed;
}
}
// TODO: Prioritize cant_raise realtime signals?
Ok(())
} }
extern "C" { extern "C" {
pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol; pub fn __relibc_internal_get_sigcontrol_addr() -> &'static Sigcontrol;
} }
fn current_sigctl() -> &'static Sigcontrol {
unsafe { __relibc_internal_get_sigcontrol_addr() }
}
pub struct TmpDisableSignalsGuard { _inner: () } pub struct TmpDisableSignalsGuard { _inner: () }
...@@ -114,3 +136,83 @@ impl Drop for TmpDisableSignalsGuard { ...@@ -114,3 +136,83 @@ impl Drop for TmpDisableSignalsGuard {
} }
} }
} }
#[derive(Clone, Copy)]
struct SignalAction {
handler: SignalHandler,
flags: SigactionFlags,
mask: u64,
}
bitflags::bitflags! {
#[derive(Clone, Copy)]
struct SigactionFlags: u32 {
const SA_RESETHAND = 1;
}
}
fn default_term_handler(sig: c_int) {
syscall::exit((sig as usize) << 8);
}
fn default_core_handler(sig: c_int) {
syscall::exit((sig as usize) << 8);
}
fn default_ign_handler(_: c_int) {
}
fn stop_handler_sentinel(_: c_int) {
}
#[derive(Clone, Copy)]
union SignalHandler {
sa_handler: Option<extern "C" fn(c_int)>,
sa_sigaction: Option<unsafe extern "C" fn(c_int, *const (), *mut ())>,
}
struct TheDefault {
actions: [SignalAction; 64],
ignmask: u64,
}
static SIGACTIONS: Mutex<[SignalAction; 64]> = Mutex::new([SignalAction {
handler: SignalHandler { sa_handler: None },
flags: SigactionFlags::empty(),
mask: 0,
}; 64]);
static IGNMASK: AtomicU64 = AtomicU64::new(sig_bit(SIGCHLD) | sig_bit(SIGURG) | sig_bit(SIGWINCH) | sig_bit(SIGCONT));
fn expand_mask(mask: u64) -> [u64; 2] {
[mask & 0xffff_ffff, mask >> 32]
}
fn combine_mask([lo, hi]: [u64; 2]) -> u64 {
lo | ((hi & 0xffff_ffff) << 32)
}
const fn sig_bit(sig: usize) -> u64 {
//assert_ne!(sig, 32);
//assert_ne!(sig, 0);
1 << (sig - 1)
}
pub fn setup_sighandler(control: &Sigcontrol) {
{
let mut sigactions = SIGACTIONS.lock();
}
#[cfg(target_arch = "x86_64")]
{
let cpuid_eax1_ecx = unsafe { core::arch::x86_64::__cpuid(1) }.ecx;
CPUID_EAX1_ECX.store(cpuid_eax1_ecx, core::sync::atomic::Ordering::Relaxed);
}
let data = syscall::SetSighandlerData {
user_handler: sighandler_function(),
excp_handler: 0, // TODO
word_addr: control as *const Sigcontrol as usize,
};
let fd = syscall::open(
"thisproc:current/sighandler",
syscall::O_WRONLY | syscall::O_CLOEXEC,
)
.expect("failed to open thisproc:current/sighandler");
syscall::write(fd, &data).expect("failed to write to thisproc:current/sighandler");
let _ = syscall::close(fd);
}
// TODO: Share code for simple futex-based mutex between relibc's Mutex<()> and this.
use core::cell::UnsafeCell;
use core::ops::{Deref, DerefMut};
use core::sync::atomic::AtomicU32;
pub struct Mutex<T> {
pub lockword: AtomicU32,
pub inner: UnsafeCell<T>,
}
const UNLOCKED: u32 = 0;
const LOCKED: u32 = 1;
const WAITING: u32 = 2;
unsafe impl<T: Send> Send for Mutex<T> {}
unsafe impl<T: Send> Sync for Mutex<T> {}
impl<T> Mutex<T> {
pub const fn new(t: T) -> Self {
Self {
lockword: AtomicU32::new(0),
inner: UnsafeCell::new(t),
}
}
pub fn lock(&self) -> MutexGuard<'_, T> {
MutexGuard { lock: self }
}
}
pub struct MutexGuard<'l, T> {
lock: &'l Mutex<T>,
}
impl<T> Deref for MutexGuard<'_, T> {
type Target = T;
fn deref(&self) -> &T {
unsafe { &*self.lock.inner.get() }
}
}
impl<T> DerefMut for MutexGuard<'_, T> {
fn deref_mut(&mut self) -> &mut T {
unsafe { &mut *self.lock.inner.get() }
}
}
impl<T> Drop for MutexGuard<'_, T> {
fn drop(&mut self) {
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment