Implement SA_RESTART for read and write.

This commit is contained in:
4lDO2
2024-07-15 23:24:41 +02:00
parent 3cd21243ec
commit bcce7e18db
5 changed files with 64 additions and 1 deletions
+1
View File
@@ -26,6 +26,7 @@ pub struct SigArea {
pub altstack_bottom: usize,
pub disable_signals_depth: u64,
pub pctl: usize, // TODO: find out how to correctly reference that static
pub last_sig_was_restart: bool,
}
#[repr(C, align(16))]
+3 -1
View File
@@ -44,7 +44,6 @@ unsafe fn inner(stack: &mut SigStack) {
// asm counts from 0
stack.sig_num += 1;
arch_pre(stack, &mut *os.arch.get());
let sigaction = {
@@ -61,6 +60,7 @@ unsafe fn inner(stack: &mut SigStack) {
}
action
};
let shall_restart = sigaction.flags.contains(SigactionFlags::RESTART);
let handler = match sigaction.kind {
SigactionKind::Ignore => {
@@ -123,6 +123,8 @@ unsafe fn inner(stack: &mut SigStack) {
//let _ = syscall::write(1, alloc::format!("will return to {:x?}\n", stack.regs.eip).as_bytes());
(*os.arch.get()).last_sig_was_restart = shall_restart;
// And re-enable them again
control_flags.store(control_flags.load(Ordering::Relaxed) & !SigcontrolFlags::INHIBIT_DELIVERY.bits(), Ordering::Release);
core::sync::atomic::compiler_fence(Ordering::Acquire);
+6
View File
@@ -2,16 +2,22 @@ use syscall::error::{Result, Error, EINTR};
use crate::arch::manually_enter_trampoline;
use crate::signal::tmp_disable_signals;
use crate::Tcb;
#[inline]
fn wrapper(mut f: impl FnMut() -> Result<usize>) -> Result<usize> {
loop {
let _guard = tmp_disable_signals();
let rt_sigarea = unsafe { &Tcb::current().unwrap().os_specific };
let res = f();
if res == Err(Error::new(EINTR)) {
unsafe {
manually_enter_trampoline();
}
if unsafe { (*rt_sigarea.arch.get()).last_sig_was_restart } {
continue;
}
}
return res;
+1
View File
@@ -31,6 +31,7 @@ EXPECT_NAMES=\
setjmp \
sigaction \
signal \
sa_restart \
stdio/all \
stdio/buffer \
stdio/fgets \
+53
View File
@@ -0,0 +1,53 @@
#include <assert.h>
#include <signal.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include "test_helpers.h"
void action(int sig, siginfo_t *info, void *context) {
assert (sig == SIGUSR1);
(void)info;
(void)context;
char *msg = "Signal handler\n";
write(1, msg, strlen(msg));
_exit(0);
}
int main(void) {
int status;
struct sigaction act;
act.sa_sigaction = action;
act.sa_flags = SA_RESTART;
sigemptyset(&act.sa_mask);
status = sigaction(SIGUSR1, &act, NULL);
ERROR_IF(sigaction, status, == -1);
int fds[2];
status = pipe(fds);
ERROR_IF(pipe, status, == -1);
int parent = getpid();
status = fork();
ERROR_IF(fork, status, == -1);
if (status == 0) {
for (int i = 0; i < 1000; i++) {
status = kill(parent, SIGUSR1);
ERROR_IF(kill, status, == -1);
}
return 0;
}
char buffer[1];
status = read(fds[0], buffer, 1);
ERROR_IF(read, status, == -1);
return 1;
}