diff options
author | Wesley Moore <wes@wezm.net> | 2017-07-19 07:42:02 +1000 |
---|---|---|
committer | Wesley Moore <wes@wezm.net> | 2017-08-05 15:04:39 +1000 |
commit | 0874cfa059b4a30168c52f470108ee7ca88ea273 (patch) | |
tree | ec2b1dff491a00a3a274b84f7528da5740ae945b /src | |
parent | 836c06d3dc1f57a894be1e68e8514367e42e0917 (diff) | |
download | nix-0874cfa059b4a30168c52f470108ee7ca88ea273.zip |
Add OpenBSD compatibility to signals
Diffstat (limited to 'src')
-rw-r--r-- | src/sys/signal.rs | 193 |
1 files changed, 103 insertions, 90 deletions
diff --git a/src/sys/signal.rs b/src/sys/signal.rs index f885af92..d7e9d91d 100644 --- a/src/sys/signal.rs +++ b/src/sys/signal.rs @@ -3,13 +3,14 @@ use libc; use {Errno, Error, Result}; -use std::fmt; -use std::fmt::Debug; use std::mem; #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] use std::os::unix::io::RawFd; use std::ptr; +#[cfg(not(target_os = "openbsd"))] +pub use self::sigevent::*; + // Currently there is only one definition of c_int in libc, as well as only one // type for signal constants. // We would prefer to use the libc::c_int alias in the repr attribute. Unfortunately @@ -488,102 +489,114 @@ pub enum SigevNotify { si_value: libc::intptr_t }, } -/// Used to request asynchronous notification of the completion of certain -/// events, such as POSIX AIO and timers. -#[repr(C)] -pub struct SigEvent { - sigevent: libc::sigevent -} +#[cfg(not(target_os = "openbsd"))] +mod sigevent { + use libc; + use std::mem; + use std::ptr; + use std::fmt::{self, Debug}; + use super::SigevNotify; + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + use super::type_of_thread_id; + + /// Used to request asynchronous notification of the completion of certain + /// events, such as POSIX AIO and timers. + #[repr(C)] + pub struct SigEvent { + sigevent: libc::sigevent + } + + impl SigEvent { + /// **Note:** this constructor does not allow the user to set the + /// `sigev_notify_kevent_flags` field. That's considered ok because on FreeBSD + /// at least those flags don't do anything useful. That field is part of a + /// union that shares space with the more genuinely useful fields. + /// + /// **Note:** This constructor also doesn't allow the caller to set the + /// `sigev_notify_function` or `sigev_notify_attributes` fields, which are + /// required for `SIGEV_THREAD`. That's considered ok because on no operating + /// system is `SIGEV_THREAD` the most efficient way to deliver AIO + /// notification. FreeBSD and DragonFly BSD programs should prefer `SIGEV_KEVENT`. + /// Linux, Solaris, and portable programs should prefer `SIGEV_THREAD_ID` or + /// `SIGEV_SIGNAL`. That field is part of a union that shares space with the + /// more genuinely useful `sigev_notify_thread_id` + pub fn new(sigev_notify: SigevNotify) -> SigEvent { + let mut sev = unsafe { mem::zeroed::<libc::sigevent>()}; + sev.sigev_notify = match sigev_notify { + SigevNotify::SigevNone => libc::SIGEV_NONE, + SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL, + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT, + #[cfg(target_os = "freebsd")] + SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, + #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] + SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, + #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] + SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined + }; + sev.sigev_signo = match sigev_notify { + SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int, + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + SigevNotify::SigevKevent{ kq, ..} => kq, + #[cfg(any(target_os = "linux", target_os = "freebsd"))] + SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int, + _ => 0 + }; + sev.sigev_value.sival_ptr = match sigev_notify { + SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(), + SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void, + #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] + SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void, + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void, + }; + SigEvent::set_tid(&mut sev, &sigev_notify); + SigEvent{sigevent: sev} + } -impl SigEvent { - // Note: this constructor does not allow the user to set the - // sigev_notify_kevent_flags field. That's considered ok because on FreeBSD - // at least those flags don't do anything useful. That field is part of a - // union that shares space with the more genuinely useful - // Note: This constructor also doesn't allow the caller to set the - // sigev_notify_function or sigev_notify_attributes fields, which are - // required for SIGEV_THREAD. That's considered ok because on no operating - // system is SIGEV_THREAD the most efficient way to deliver AIO - // notification. FreeBSD and Dragonfly programs should prefer SIGEV_KEVENT. - // Linux, Solaris, and portable programs should prefer SIGEV_THREAD_ID or - // SIGEV_SIGNAL. That field is part of a union that shares space with the - // more genuinely useful sigev_notify_thread_id - pub fn new(sigev_notify: SigevNotify) -> SigEvent { - let mut sev = unsafe { mem::zeroed::<libc::sigevent>()}; - sev.sigev_notify = match sigev_notify { - SigevNotify::SigevNone => libc::SIGEV_NONE, - SigevNotify::SigevSignal{..} => libc::SIGEV_SIGNAL, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{..} => libc::SIGEV_KEVENT, - #[cfg(target_os = "freebsd")] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(all(target_os = "linux", target_env = "gnu", not(target_arch = "mips")))] - SigevNotify::SigevThreadId{..} => libc::SIGEV_THREAD_ID, - #[cfg(any(all(target_os = "linux", target_env = "musl"), target_arch = "mips"))] - SigevNotify::SigevThreadId{..} => 4 // No SIGEV_THREAD_ID defined - }; - sev.sigev_signo = match sigev_notify { - SigevNotify::SigevSignal{ signal, .. } => signal as libc::c_int, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{ kq, ..} => kq, - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - SigevNotify::SigevThreadId{ signal, .. } => signal as libc::c_int, - _ => 0 - }; - sev.sigev_value.sival_ptr = match sigev_notify { - SigevNotify::SigevNone => ptr::null_mut::<libc::c_void>(), - SigevNotify::SigevSignal{ si_value, .. } => si_value as *mut libc::c_void, - #[cfg(any(target_os = "dragonfly", target_os = "freebsd"))] - SigevNotify::SigevKevent{ udata, .. } => udata as *mut libc::c_void, - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - SigevNotify::SigevThreadId{ si_value, .. } => si_value as *mut libc::c_void, - }; - SigEvent::set_tid(&mut sev, &sigev_notify); - SigEvent{sigevent: sev} - } + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) { + sev.sigev_notify_thread_id = match sigev_notify { + &SigevNotify::SigevThreadId { thread_id, .. } => thread_id, + _ => 0 as type_of_thread_id + }; + } - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - fn set_tid(sev: &mut libc::sigevent, sigev_notify: &SigevNotify) { - sev.sigev_notify_thread_id = match sigev_notify { - &SigevNotify::SigevThreadId { thread_id, .. } => thread_id, - _ => 0 as type_of_thread_id - }; - } + #[cfg(not(any(target_os = "freebsd", target_os = "linux")))] + fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { + } - #[cfg(not(any(target_os = "freebsd", target_os = "linux")))] - fn set_tid(_sev: &mut libc::sigevent, _sigev_notify: &SigevNotify) { + pub fn sigevent(&self) -> libc::sigevent { + self.sigevent + } } - pub fn sigevent(&self) -> libc::sigevent { - self.sigevent - } -} + impl Debug for SigEvent { + #[cfg(any(target_os = "freebsd", target_os = "linux"))] + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("SigEvent") + .field("sigev_notify", &self.sigevent.sigev_notify) + .field("sigev_signo", &self.sigevent.sigev_signo) + .field("sigev_value", &self.sigevent.sigev_value.sival_ptr) + .field("sigev_notify_thread_id", + &self.sigevent.sigev_notify_thread_id) + .finish() + } -impl Debug for SigEvent { - #[cfg(any(target_os = "linux", target_os = "freebsd"))] - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("SigEvent") - .field("sigev_notify", &self.sigevent.sigev_notify) - .field("sigev_signo", &self.sigevent.sigev_signo) - .field("sigev_value", &self.sigevent.sigev_value.sival_ptr) - .field("sigev_notify_thread_id", - &self.sigevent.sigev_notify_thread_id) - .finish() - } - - #[cfg(not(any(target_os = "linux", target_os = "freebsd")))] - fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { - fmt.debug_struct("SigEvent") - .field("sigev_notify", &self.sigevent.sigev_notify) - .field("sigev_signo", &self.sigevent.sigev_signo) - .field("sigev_value", &self.sigevent.sigev_value.sival_ptr) - .finish() + #[cfg(not(any(target_os = "freebsd", target_os = "linux")))] + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + fmt.debug_struct("SigEvent") + .field("sigev_notify", &self.sigevent.sigev_notify) + .field("sigev_signo", &self.sigevent.sigev_signo) + .field("sigev_value", &self.sigevent.sigev_value.sival_ptr) + .finish() + } } -} -impl<'a> From<&'a libc::sigevent> for SigEvent { - fn from(sigevent: &libc::sigevent) -> Self { - SigEvent{ sigevent: sigevent.clone() } + impl<'a> From<&'a libc::sigevent> for SigEvent { + fn from(sigevent: &libc::sigevent) -> Self { + SigEvent{ sigevent: sigevent.clone() } + } } } |