diff --git a/include/bits/signal.h b/include/bits/signal.h new file mode 100644 index 0000000000000000000000000000000000000000..8812ba7932e2425c02f4bb79d8b654e90e6a74fb --- /dev/null +++ b/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))]; diff --git a/include/sys/types.h b/include/sys/types.h index 3a466d2b2a4e3f79a79604ddfd89521ca65842ed..d901d6e99d084f90fa54a35aed2b7de111a65d09 100644 --- a/include/sys/types.h +++ b/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; diff --git a/src/platform/src/lib.rs b/src/platform/src/lib.rs index f218e8dd09b66b89e0738445ae4f83fb07ec89cb..e1119e82061c4eaeee880c7fc85fce3f1fc42a63 100644 --- a/src/platform/src/lib.rs +++ b/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] diff --git a/src/platform/src/linux/mod.rs b/src/platform/src/linux/mod.rs index 79f9b60c98c86ced267185ec7f9c05885e60f269..187ea1929c86872d240f555ef047d3494f9a512d 100644 --- a/src/platform/src/linux/mod.rs +++ b/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 } diff --git a/src/platform/src/redox/mod.rs b/src/platform/src/redox/mod.rs index 30ec0d426f5b84cc7ba22217d6844d1294d76650..8ac654c377790a5f67664f9fb9918b9b3797a507 100644 --- a/src/platform/src/redox/mod.rs +++ b/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) { diff --git a/src/platform/src/types.rs b/src/platform/src/types.rs index 61b1fea30dee89c0496232c9275a1f3205a288c1..e77751123e7c845abcaf413bacbce5012c3019ba 100644 --- a/src/platform/src/types.rs +++ b/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; diff --git a/src/signal/cbindgen.toml b/src/signal/cbindgen.toml index 89d34bbcc2b75b2454cba89c97965887e1573a93..53986d3423cb6f046a4740d7269425f8683a144a 100644 --- a/src/signal/cbindgen.toml +++ b/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" diff --git a/src/signal/src/lib.rs b/src/signal/src/lib.rs index 1cb52aca0fc069f707416752d0b9008dcca3ad79..833181a0b34a457e98a6427c62b20ee218258bda 100644 --- a/src/signal/src/lib.rs +++ b/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] diff --git a/src/signal/src/linux.rs b/src/signal/src/linux.rs index 628e81339038ddd8b29deba55c59664224f86db1..8f6b11f2090acbdd381089cf6d74f8e5d83a868a 100644 --- a/src/signal/src/linux.rs +++ b/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; diff --git a/src/signal/src/redox.rs b/src/signal/src/redox.rs index b5108b5a62a249a9e8ace1a4b4100c87728b59ce..f5ae96b6ccfad9ff0d4cc52432aab3f73c91a213 100644 --- a/src/signal/src/redox.rs +++ b/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; diff --git a/src/unistd/src/lib.rs b/src/unistd/src/lib.rs index 1a1c081a1e9a0e10f43058e3f50fa2a596a7b047..6350031fbd58fc3bf2e7f30f18c9109b32724b57 100644 --- a/src/unistd/src/lib.rs +++ b/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) diff --git a/tests/.gitignore b/tests/.gitignore index 3559f9e1a539a05c2554db73e34c8646b02ed8aa..e14391eda1130d5f1b4b445a94e535822fae6f7a 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -11,6 +11,7 @@ fcntl/fcntl locale math setjmp +signal stdio/all stdio/freopen stdio/fwrite diff --git a/tests/Makefile b/tests/Makefile index 8878777da19cf56253bb7852d84b49dc4694990e..c631eeb959e7d82aa5d297d81be59096a8810c16 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -10,6 +10,7 @@ EXPECT_BINS=\ locale \ math \ setjmp \ + signal \ stdio/all \ stdio/freopen \ stdio/fwrite \ diff --git a/tests/expected/signal.stderr b/tests/expected/signal.stderr new file mode 100644 index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 diff --git a/tests/expected/signal.stdout b/tests/expected/signal.stdout new file mode 100644 index 0000000000000000000000000000000000000000..7d184e34c823485133f02e17a6993d8067578e78 --- /dev/null +++ b/tests/expected/signal.stdout @@ -0,0 +1,3 @@ +Raising... +Signal handler called! +Raised. diff --git a/tests/signal.c b/tests/signal.c new file mode 100644 index 0000000000000000000000000000000000000000..1b2f66fc20ca511a519306801b59ca81af48cdcb --- /dev/null +++ b/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."); +}