浏览代码

Basic signal support

jD91mZM2 6 年之前
父节点
当前提交
ecd8aca6d6

+ 6 - 0
include/bits/signal.h

@@ -0,0 +1,6 @@
+#define SIG_ERR -1ULL
+
+#define NSIG 64
+
+// darn cbindgen
+typedef unsigned long sigset_t[NSIG / (8 * sizeof(unsigned long))];

+ 2 - 2
include/sys/types.h

@@ -25,9 +25,9 @@ typedef long ssize_t;
 
 typedef long time_t;
 
-typedef int useconds_t;
+typedef unsigned int useconds_t;
 
-typedef long suseconds_t;
+typedef int suseconds_t;
 
 typedef long clock_t;
 

+ 19 - 2
src/platform/src/lib.rs

@@ -1,7 +1,7 @@
 #![no_std]
 #![allow(non_camel_case_types)]
 #![feature(alloc, allocator_api, const_vec_new)]
-//TODO #![feature(thread_local)]
+#![cfg_attr(target_os = "redox", feature(thread_local))]
 
 #[cfg_attr(target_os = "redox", macro_use)]
 extern crate alloc;
@@ -36,7 +36,7 @@ mod sys;
 pub mod types;
 
 use alloc::Vec;
-use core::{fmt, ptr};
+use core::{fmt, mem, ptr};
 
 use types::*;
 
@@ -49,16 +49,33 @@ pub const SOCK_DGRAM: c_int = 2;
 pub const SOCK_NONBLOCK: c_int = 0o4000;
 pub const SOCK_CLOEXEC: c_int = 0o2000000;
 
+pub const SIG_BLOCK: c_int = 0;
+pub const SIG_UNBLOCK: c_int = 1;
+pub const SIG_SETMASK: c_int = 2;
+
 pub type in_addr_t = [u8; 4];
 pub type in_port_t = u16;
 pub type sa_family_t = u16;
 pub type socklen_t = u32;
 
+#[repr(C)]
 pub struct sockaddr {
     pub sa_family: sa_family_t,
     pub data: [c_char; 14],
 }
 
+#[repr(C)]
+pub struct sigaction {
+    pub sa_handler: extern "C" fn(c_int),
+    pub sa_flags: c_ulong,
+    pub sa_restorer: unsafe extern "C" fn(),
+    pub sa_mask: sigset_t
+}
+
+const NSIG: usize = 64;
+
+pub type sigset_t = [c_ulong; NSIG / (8 * mem::size_of::<c_ulong>())];
+
 //TODO #[thread_local]
 #[allow(non_upper_case_globals)]
 #[no_mangle]

+ 19 - 0
src/platform/src/linux/mod.rs

@@ -259,6 +259,17 @@ pub fn pipe(fildes: &mut [c_int]) -> c_int {
     e(unsafe { syscall!(PIPE2, fildes.as_mut_ptr(), 0) }) as c_int
 }
 
+pub fn raise(sig: c_int) -> c_int {
+    let tid = e(unsafe { syscall!(GETTID) }) as pid_t;
+    let ret = if tid == !0 {
+        -1
+    } else {
+        e(unsafe { syscall!(TKILL, tid, sig) }) as c_int
+    };
+
+    ret
+}
+
 pub fn read(fildes: c_int, buf: &mut [u8]) -> ssize_t {
     e(unsafe { syscall!(READ, fildes, buf.as_mut_ptr(), buf.len()) }) as ssize_t
 }
@@ -338,6 +349,14 @@ pub fn shutdown(socket: c_int, how: c_int) -> c_int {
     e(unsafe { syscall!(SHUTDOWN, socket, how) }) as c_int
 }
 
+pub unsafe fn sigaction(sig: c_int, act: *const sigaction, oact: *mut sigaction) -> c_int {
+    e(syscall!(RT_SIGACTION, sig, act, oact, mem::size_of::<sigset_t>())) as c_int
+}
+
+pub fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int {
+    e(unsafe { syscall!(RT_SIGPROCMASK, how, set, oset, mem::size_of::<sigset_t>()) }) as c_int
+}
+
 pub fn stat(file: *const c_char, buf: *mut stat) -> c_int {
     e(unsafe { syscall!(NEWFSTATAT, AT_FDCWD, file, buf, 0) }) as c_int
 }

+ 56 - 0
src/platform/src/redox/mod.rs

@@ -12,6 +12,15 @@ use syscall::{self, Result};
 use types::*;
 use *;
 
+#[thread_local]
+static mut SIG_HANDLER: Option<extern "C" fn(c_int)> = None;
+
+extern "C" fn sig_handler(sig: usize) {
+    if let Some(ref callback) = unsafe { SIG_HANDLER } {
+        callback(sig as c_int);
+    }
+}
+
 #[repr(C)]
 struct SockData {
     port: in_port_t,
@@ -483,6 +492,10 @@ pub fn pipe(fds: &mut [c_int]) -> c_int {
     res as c_int
 }
 
+pub fn raise(sig: c_int) -> c_int {
+    kill(getpid(), sig)
+}
+
 pub fn read(fd: c_int, buf: &mut [u8]) -> ssize_t {
     e(syscall::read(fd as usize, buf)) as ssize_t
 }
@@ -585,6 +598,49 @@ pub fn shutdown(socket: c_int, how: c_int) -> c_int {
     -1
 }
 
+pub unsafe fn sigaction(sig: c_int, act: *const sigaction, oact: *mut sigaction) -> c_int {
+    if !oact.is_null() {
+        // Assumes the last sigaction() call was made by relibc and not a different one
+        if let Some(callback) = SIG_HANDLER {
+            (*oact).sa_handler = callback;
+        }
+    }
+    let act = if act.is_null() {
+        None
+    } else {
+        SIG_HANDLER = Some((*act).sa_handler);
+        let m = (*act).sa_mask;
+        Some(syscall::SigAction {
+            sa_handler: sig_handler,
+            sa_mask: [m[0] as u64, 0],
+            sa_flags: (*act).sa_flags as usize
+        })
+    };
+    let mut old = syscall::SigAction::default();
+    let ret = e(syscall::sigaction(
+        sig as usize,
+        act.as_ref(),
+        if oact.is_null() { None } else { Some(&mut old) }
+    )) as c_int;
+    if !oact.is_null() {
+        let m = old.sa_mask;
+        (*oact).sa_mask = [m[0] as c_ulong];
+        (*oact).sa_flags = old.sa_flags as c_ulong;
+    }
+    ret
+}
+
+pub fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int {
+    let _ = write!(
+        ::FileWriter(2),
+        "unimplemented: sigprocmask({}, {:p}, {:p})",
+        how,
+        set,
+        oset
+    );
+    -1
+}
+
 pub fn stat(path: *const c_char, buf: *mut stat) -> c_int {
     let path = unsafe { c_str(path) };
     match syscall::open(path, O_RDONLY) {

+ 2 - 2
src/platform/src/types.rs

@@ -61,8 +61,8 @@ pub type nlink_t = usize;
 pub type blksize_t = isize;
 pub type blkcnt_t = u64;
 
-pub type useconds_t = i32;
-pub type suseconds_t = i64;
+pub type useconds_t = c_uint;
+pub type suseconds_t = c_int;
 
 pub type clock_t = i64;
 pub type clockid_t = i32;

+ 1 - 1
src/signal/cbindgen.toml

@@ -1,4 +1,4 @@
-sys_includes = ["stdint.h", "sys/types.h"]
+sys_includes = ["stdint.h", "sys/types.h", "bits/signal.h"]
 include_guard = "_SIGNAL_H"
 style = "Tag"
 language = "C"

+ 56 - 20
src/signal/src/lib.rs

@@ -1,7 +1,9 @@
 //! signal implementation for Redox, following http://pubs.opengroup.org/onlinepubs/7908799/xsh/signal.h.html
 
 #![no_std]
+#![feature(asm, const_fn, core_intrinsics, global_asm)]
 
+#[macro_use]
 extern crate platform;
 
 #[cfg(target_os = "linux")]
@@ -12,22 +14,29 @@ pub mod sys;
 #[path = "redox.rs"]
 pub mod sys;
 
+const SIG_ERR: usize = !0;
+
 pub const SIG_BLOCK: c_int = 0;
 pub const SIG_UNBLOCK: c_int = 1;
 pub const SIG_SETMASK: c_int = 2;
 
-pub use sys::*;
-
-use platform::types::*;
-
+// Need both here and in platform because cbindgen :(
 #[repr(C)]
+#[derive(Clone)]
 pub struct sigaction {
-    pub sa_handler: extern "C" fn(usize),
-    pub sa_mask: sigset_t,
-    pub sa_flags: usize,
+    pub sa_handler: extern "C" fn(c_int),
+    pub sa_flags: c_ulong,
+    pub sa_restorer: unsafe extern "C" fn(),
+    pub sa_mask: sigset_t
 }
 
-pub type sigset_t = sys_sigset_t;
+const NSIG: usize = 64;
+
+pub use sys::*;
+
+use core::{mem, ptr};
+use platform::types::*;
+use platform::sigset_t;
 
 #[no_mangle]
 pub extern "C" fn kill(pid: pid_t, sig: c_int) -> c_int {
@@ -39,14 +48,22 @@ pub extern "C" fn killpg(pgrp: pid_t, sig: c_int) -> c_int {
     platform::killpg(pgrp, sig)
 }
 
-// #[no_mangle]
+#[no_mangle]
 pub extern "C" fn raise(sig: c_int) -> c_int {
-    unimplemented!();
+    platform::raise(sig)
 }
 
-// #[no_mangle]
-pub extern "C" fn sigaction(sig: c_int, act: *const sigaction, oact: *const sigaction) -> c_int {
-    unimplemented!();
+#[no_mangle]
+pub unsafe extern "C" fn sigaction(sig: c_int, act: *const sigaction, oact: *mut sigaction) -> c_int {
+    let mut _sigaction = None;
+    let ptr = if !act.is_null() {
+        _sigaction = Some((*act).clone());
+        _sigaction.as_mut().unwrap().sa_flags |= SA_RESTORER as c_ulong;
+        _sigaction.as_mut().unwrap() as *mut _ as *mut platform::sigaction
+    } else {
+        ptr::null_mut()
+    };
+    platform::sigaction(sig, ptr, oact as *mut platform::sigaction)
 }
 
 // #[no_mangle]
@@ -64,9 +81,12 @@ pub extern "C" fn sigemptyset(set: *mut sigset_t) -> c_int {
     unimplemented!();
 }
 
-// #[no_mangle]
+#[no_mangle]
 pub extern "C" fn sigfillset(set: *mut sigset_t) -> c_int {
-    unimplemented!();
+    for i in unsafe { &mut (*set) } {
+        *i = c_ulong::max_value();
+    }
+    0
 }
 
 // #[no_mangle]
@@ -89,9 +109,25 @@ pub extern "C" fn sigismember(set: *const sigset_t, signo: c_int) -> c_int {
     unimplemented!();
 }
 
-// #[no_mangle]
-pub extern "C" fn signal(sig: c_int, func: fn(c_int)) -> fn(c_int) {
-    unimplemented!();
+extern "C" {
+    // Defined in assembly inside platform/x/mod.rs
+    fn __restore_rt();
+}
+
+#[no_mangle]
+pub extern "C" fn signal(sig: c_int, func: extern "C" fn(c_int)) -> extern "C" fn(c_int) {
+    let sa = sigaction {
+        sa_handler: func,
+        sa_flags: SA_RESTART as c_ulong,
+        sa_restorer: __restore_rt,
+        sa_mask: sigset_t::default()
+    };
+    let mut old_sa = unsafe { mem::uninitialized() };
+    if unsafe { sigaction(sig, &sa, &mut old_sa) } < 0 {
+        mem::forget(old_sa);
+        return unsafe { mem::transmute(SIG_ERR) };
+    }
+    old_sa.sa_handler
 }
 
 // #[no_mangle]
@@ -104,9 +140,9 @@ pub extern "C" fn sigpending(set: *mut sigset_t) -> c_int {
     unimplemented!();
 }
 
-// #[no_mangle]
+#[no_mangle]
 pub extern "C" fn sigprocmask(how: c_int, set: *const sigset_t, oset: *mut sigset_t) -> c_int {
-    unimplemented!();
+    platform::sigprocmask(how, set, oset)
 }
 
 // #[no_mangle]

+ 15 - 4
src/signal/src/linux.rs

@@ -1,7 +1,18 @@
-#[repr(C)]
-pub struct sys_sigset_t {
-    pub bits: [u64; 16],
-}
+// Needs to be defined in assembly because it can't have a function prologue
+#[cfg(target_arch = "x86_64")]
+global_asm!("
+    .global __restore_rt
+    __restore_rt:
+        mov $15, %rax # <- rax is register, 15 is RT_SIGRETURN
+        syscall
+");
+#[cfg(target_arch = "aarch64")]
+global_asm!("
+    .global __restore_rt
+    __restore_rt:
+        mov x8, #139 # <- x8 is register, 139 is RT_SIGRETURN
+        svc 0
+");
 
 pub const SIGHUP: usize = 1;
 pub const SIGINT: usize = 2;

+ 15 - 4
src/signal/src/redox.rs

@@ -1,7 +1,18 @@
-#[repr(C)]
-pub struct sys_sigset_t {
-    pub bits: [u64; 2],
-}
+// Needs to be defined in assembly because it can't have a function prologue
+#[cfg(target_arch = "x86_64")]
+global_asm!("
+    .global __restore_rt
+    __restore_rt:
+        mov $119, %rax # <- rax is register, 119 is SIGRETURN
+        int $0x80
+");
+#[cfg(target_arch = "aarch64")]
+global_asm!("
+    .global __restore_rt
+    __restore_rt:
+        mov x8, #119 # <- x8 is register, 119 is SIGRETURN
+        svc 0
+");
 
 pub const SIGHUP: usize = 1;
 pub const SIGINT: usize = 2;

+ 2 - 2
src/unistd/src/lib.rs

@@ -449,8 +449,8 @@ pub extern "C" fn unlink(path: *const c_char) -> c_int {
 #[no_mangle]
 pub extern "C" fn usleep(useconds: useconds_t) -> c_int {
     let rqtp = timespec {
-        tv_sec: 0,
-        tv_nsec: (useconds * 1000).into(),
+        tv_sec: (useconds / 1_000_000) as i64,
+        tv_nsec: ((useconds % 1000) * 1000) as i64,
     };
     let rmtp = ptr::null_mut();
     platform::nanosleep(&rqtp, rmtp)

+ 1 - 0
tests/.gitignore

@@ -11,6 +11,7 @@ fcntl/fcntl
 locale
 math
 setjmp
+signal
 stdio/all
 stdio/freopen
 stdio/fwrite

+ 1 - 0
tests/Makefile

@@ -10,6 +10,7 @@ EXPECT_BINS=\
 	locale \
 	math \
 	setjmp \
+	signal \
 	stdio/all \
 	stdio/freopen \
 	stdio/fwrite \

+ 0 - 0
tests/expected/signal.stderr


+ 3 - 0
tests/expected/signal.stdout

@@ -0,0 +1,3 @@
+Raising...
+Signal handler called!
+Raised.

+ 24 - 0
tests/signal.c

@@ -0,0 +1,24 @@
+#include <signal.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <errno.h>
+
+void handler(int sig) {
+    puts("Signal handler called!");
+}
+
+int main() {
+    if (((size_t) signal(SIGUSR1, &handler)) == SIG_ERR) {
+        puts("Signal error!");
+        printf("%d\n", errno);
+        return 1;
+    }
+
+    puts("Raising...");
+    if (raise(SIGUSR1)) {
+        puts("Raise error!");
+        printf("%d\n", errno);
+        return 1;
+    }
+    puts("Raised.");
+}