Implement SA_RESTART for read and write.
This commit is contained in:
@@ -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))]
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -31,6 +31,7 @@ EXPECT_NAMES=\
|
||||
setjmp \
|
||||
sigaction \
|
||||
signal \
|
||||
sa_restart \
|
||||
stdio/all \
|
||||
stdio/buffer \
|
||||
stdio/fgets \
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Reference in New Issue
Block a user