Fix sigsuspend and add it to the sigqueue test.

This commit is contained in:
4lDO2
2024-08-04 23:02:04 +02:00
parent 9701e9c544
commit 2b7a1ea94b
6 changed files with 69 additions and 24 deletions
+27 -7
View File
@@ -673,10 +673,13 @@ pub fn currently_pending_blocked() -> u64 {
}
pub enum Unreachable {}
pub fn await_signal_async(set: u64) -> Result<Unreachable> {
let mut old = 0;
set_sigmask(Some(!set), Some(&mut old))?;
// TODO: RAII guard
pub fn await_signal_async(inner_allowset: u64) -> Result<Unreachable> {
let _guard = tmp_disable_signals();
let control = &unsafe { Tcb::current().unwrap() }.os_specific.control;
let old_allowset = get_allowset_raw(&control.word);
set_allowset_raw(&control.word, old_allowset, inner_allowset);
let res = syscall::nanosleep(
&TimeSpec {
tv_sec: i64::MAX,
@@ -684,12 +687,19 @@ pub fn await_signal_async(set: u64) -> Result<Unreachable> {
},
&mut TimeSpec::default(),
);
set_sigmask(Some(old), None)?;
set_allowset_raw(&control.word, inner_allowset, old_allowset);
if res == Err(Error::new(EINTR)) {
unsafe {
manually_enter_trampoline();
}
}
res?;
unreachable!()
}
// TODO: deadline-based API
pub fn await_signal_sync(inner_allowset: u64, timeout: &TimeSpec) -> Result<SiginfoAbi> {
pub fn await_signal_sync(inner_allowset: u64, timeout: Option<&TimeSpec>) -> Result<SiginfoAbi> {
let _guard = tmp_disable_signals();
let control = &unsafe { Tcb::current().unwrap() }.os_specific.control;
@@ -704,7 +714,17 @@ pub fn await_signal_sync(inner_allowset: u64, timeout: &TimeSpec) -> Result<Sigi
return Ok(info);
}
let res = syscall::nanosleep(&timeout, &mut TimeSpec::default());
let res = match timeout {
Some(t) => syscall::nanosleep(&t, &mut TimeSpec::default()),
None => syscall::nanosleep(
&TimeSpec {
tv_sec: i64::MAX,
tv_nsec: 0,
},
&mut TimeSpec::default(),
),
};
let thread_pending = set_allowset_raw(&control.word, inner_allowset, old_allowset);
let proc_pending = PROC_CONTROL_STRUCT.pending.load(Ordering::Acquire);
+9 -2
View File
@@ -380,13 +380,20 @@ pub unsafe extern "C" fn sigwait(set: *const sigset_t, sig: *mut c_int) -> c_int
#[no_mangle]
pub unsafe extern "C" fn sigtimedwait(
set: *const sigset_t,
sig: *mut siginfo, // https://github.com/mozilla/cbindgen/issues/621
// s/siginfo_t/siginfo due to https://github.com/mozilla/cbindgen/issues/621
sig: *mut siginfo,
// POSIX leaves behavior unspecified if this is NULL, but on both Linux and Redox, NULL is used
// to differentiate between sigtimedwait and sigwaitinfo internally
tp: *const timespec,
) -> c_int {
Sys::sigtimedwait(&*set, sig.as_mut(), &*tp)
Sys::sigtimedwait(&*set, sig.as_mut(), tp.as_ref())
.map(|()| 0)
.or_minus_one_errno()
}
#[no_mangle]
pub unsafe extern "C" fn sigwaitinfo(set: *const sigset_t, sig: *mut siginfo_t) -> c_int {
sigtimedwait(set, sig, core::ptr::null())
}
pub const _signal_strings: [&str; 32] = [
"Unknown signal\0",
+3 -3
View File
@@ -165,14 +165,14 @@ impl PalSignal for Sys {
fn sigtimedwait(
set: &sigset_t,
sig: Option<&mut siginfo_t>,
tp: &timespec,
tp: Option<&timespec>,
) -> Result<(), Errno> {
unsafe {
e_raw(syscall!(
RT_SIGTIMEDWAIT,
set as *const _,
sig.map_or_else(core::ptr::null_mut, |s| s as *mut _) as usize,
tp as *const _,
sig.map_or_else(core::ptr::null_mut, |s| s as *mut _),
tp.map_or_else(core::ptr::null, |t| t as *const _),
NSIG / 8
))
.map(|_| ())
+1 -1
View File
@@ -42,6 +42,6 @@ pub trait PalSignal: Pal {
fn sigtimedwait(
set: &sigset_t,
sig: Option<&mut siginfo_t>,
tp: &timespec,
tp: Option<&timespec>,
) -> Result<(), Errno>;
}
+4 -4
View File
@@ -274,14 +274,14 @@ impl PalSignal for Sys {
fn sigtimedwait(
set: &sigset_t,
info_out: Option<&mut siginfo_t>,
timeout: &timespec,
timeout: Option<&timespec>,
) -> Result<(), Errno> {
// TODO: deadline-based API
let timeout = syscall::TimeSpec {
let timeout = timeout.map(|timeout| syscall::TimeSpec {
tv_sec: timeout.tv_sec,
tv_nsec: timeout.tv_nsec as _,
};
let info = redox_rt::signal::await_signal_sync(*set, &timeout)?.into();
});
let info = redox_rt::signal::await_signal_sync(*set, timeout.as_ref())?.into();
if let Some(out) = info_out {
*out = info;
}
+25 -7
View File
@@ -24,11 +24,11 @@ void validate(int sig, const siginfo_t *info) {
}
void action(int sig, siginfo_t *info, void *context) {
num++;
(void)context;
assert(context != NULL);
validate(sig, info);
write(1, "action\n", 7);
num++;
}
int main(void) {
@@ -40,12 +40,6 @@ int main(void) {
parent = getpid();
assert(parent != 0);
int child = fork();
ERROR_IF(fork, child, == -1);
status = close(fds[child == 0 ? 0 : 1]);
ERROR_IF(close, status, == -1);
sigset_t set, mask;
status = sigfillset(&mask);
ERROR_IF(sigfillset, status, == -1);
@@ -67,6 +61,16 @@ int main(void) {
status = sigaddset(&set, THE_SIG);
ERROR_IF(sigaddset, status, == -1);
sigset_t empty_set;
status = sigemptyset(&empty_set);
ERROR_IF(sigemptyset, status, == -1);
int child = fork();
ERROR_IF(fork, child, == -1);
status = close(fds[child == 0 ? 0 : 1]);
ERROR_IF(close, status, == -1);
struct sigaction sa;
memcpy(&sa.sa_mask, &set, sizeof (sigset_t));
sa.sa_flags = SA_SIGINFO;
@@ -84,6 +88,20 @@ int main(void) {
validate(THE_SIG, &info);
assert(num == 0); // ensure no signal handler ran
num++;
// TODO: check status
status = sigsuspend(&empty_set);
if (status == -1) {
perror("error in sigsuspend");
puts("[EINTR] is usually expected");
}
assert(num == 2); // ensure signal handler ran
status = sigprocmask(SIG_SETMASK, &empty_set, NULL);
ERROR_IF(sigprocmask, status, == -1);
while (num < 31) {}
status = write(fds[1], "A", 1);