From bd002d9e47623fe46a7dac548cbdd4ccc7ef825e Mon Sep 17 00:00:00 2001 From: Kotauskas Date: Fri, 5 Mar 2021 13:41:44 +0300 Subject: [PATCH] Made signals optional --- Cargo.toml | 29 +++++++++----- src/os/unix/imports.rs | 9 +++++ src/os/unix/mod.rs | 6 ++- src/os/unix/signal.rs | 40 +++++++++---------- src/os/windows/imports.rs | 71 ++++++++++++++++++++++++++++++++++ src/os/windows/mod.rs | 32 +++++---------- src/os/windows/named_pipe.rs | 67 +++----------------------------- src/os/windows/signal.rs | 35 ++++++++--------- src/os/windows/unnamed_pipe.rs | 30 +++----------- 9 files changed, 157 insertions(+), 162 deletions(-) create mode 100644 src/os/windows/imports.rs diff --git a/Cargo.toml b/Cargo.toml index 4d69857d..d902f0e0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -15,23 +15,32 @@ keywords = ["ipc", "shared_memory", "pipe", "unix_domain_socket"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -libc = {version = "0.2", features = ["extra_traits"]} -thiserror = "1.0" -spinning = "0.1" -intmap = "0.7" -lazy_static = "1.4" -blocking = {version = "1.0", optional = true} -futures = {version = "0.3", optional = true} +libc = { version = "0.2", features = ["extra_traits"] } +thiserror = { version = "1.0", optional = true } +spinning = { version = "0.1", optional = true } +intmap = { version = "0.7", optional = true } +once_cell = { version = "1.7", optional = true } +blocking = { version = "1.0", optional = true } +futures = { version = "0.3", optional = true } cfg-if = "1.0" [dev_dependencies] -tokio = {version = "1.0", features = ["rt", "macros", "rt-multi-thread"]} +tokio = { version = "1.0", features = ["rt", "macros", "rt-multi-thread"] } [target.'cfg(windows)'.dependencies] -winapi = {version = "0.3", features = ["std", "winbase", "winerror", "processthreadsapi", "fileapi", "handleapi", "namedpipeapi"]} +winapi = { version = "0.3", features = [ + "std", + "winbase", + "winerror", + "processthreadsapi", + "fileapi", + "handleapi", + "namedpipeapi", +] } [features] -default = [] +default = ["signals", "nonblocking"] +signals = ["thiserror", "spinning", "intmap", "once_cell"] nonblocking = ["blocking", "futures"] doc_cfg = [] diff --git a/src/os/unix/imports.rs b/src/os/unix/imports.rs index ba5703c4..e2fb5131 100644 --- a/src/os/unix/imports.rs +++ b/src/os/unix/imports.rs @@ -104,3 +104,12 @@ cfg_if! { pub(super) type FdOps = (); } } + +cfg_if! { + if #[cfg(feature = "signals")] { + pub use intmap::IntMap; + pub use once_cell::sync::Lazy; + pub use spinning::{RwLock, RwLockUpgradableReadGuard}; + pub use thiserror::Error; + } +} diff --git a/src/os/unix/mod.rs b/src/os/unix/mod.rs index ac16a500..19d05623 100644 --- a/src/os/unix/mod.rs +++ b/src/os/unix/mod.rs @@ -10,11 +10,13 @@ //! //! Unix domain sockets are not available on ARM Newlib, but are supported on all other Unix-like systems. +mod imports; + pub mod fifo_file; +#[cfg(any(doc, feature = "signals"))] +#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "signals")))] pub mod signal; -mod imports; - #[cfg(any( target_os = "linux", target_os = "android", diff --git a/src/os/unix/signal.rs b/src/os/unix/signal.rs index 22d75e7c..d187887c 100644 --- a/src/os/unix/signal.rs +++ b/src/os/unix/signal.rs @@ -138,9 +138,6 @@ #![cfg_attr(not(unix), allow(unused_imports))] use cfg_if::cfg_if; -use intmap::IntMap; -use lazy_static::lazy_static; -use spinning::{RwLock, RwLockUpgradableReadGuard}; use std::{ convert::{TryFrom, TryInto}, error::Error, @@ -149,7 +146,6 @@ use std::{ mem::zeroed, panic, process, }; -use thiserror::Error; use super::imports::*; @@ -200,11 +196,11 @@ pub const fn is_valid_rtsignal(rtsignal: u32) -> bool { } /// The first field is the current method of handling a specific signal, the second one is the flags which were set for it. +#[cfg(all(unix, feature = "signals"))] type HandlerAndFlags = (SignalHandler, i32); -#[cfg(unix)] -lazy_static! { - static ref HANDLERS: RwLock> = RwLock::new(IntMap::new()); -} + +#[cfg(all(unix, feature = "signals"))] +static HANDLERS: Lazy>> = Lazy::new(|| RwLock::new(IntMap::new())); /// Installs the specified handler for the specified standard signal, using the default values for the flags. /// @@ -213,7 +209,7 @@ lazy_static! { /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(unix)] { +/// # #[cfg(all(unix, feature = "signals"))] { /// use interprocess::os::unix::signal::{self, SignalType, SignalHandler}; /// /// let handler = unsafe { @@ -250,7 +246,7 @@ pub fn set_handler(signal_type: SignalType, handler: SignalHandler) -> Result<() /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(unix)] { +/// # #[cfg(all(unix, feature = "signals"))] { /// use interprocess::os::unix::signal::{self, SignalType, SignalHandler}; /// /// let handler = unsafe { @@ -291,7 +287,7 @@ pub unsafe fn set_unsafe_handler( /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(unix)] { +/// # #[cfg(all(unix, feature = "signals"))] { /// use interprocess::os::unix::signal::{self, SignalHandler}; /// /// let handler = unsafe { @@ -338,7 +334,7 @@ unsafe fn install_hook(signum: i32, hook: usize, flags: i32) -> io::Result<()> { /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(unix)] { +/// # #[cfg(all(unix, feature = "signals"))] { /// use interprocess::os::unix::signal::{self, SignalType, SignalHandler}; /// /// let handler = unsafe { @@ -579,11 +575,11 @@ impl HandlerOptions { /// The error produced when setting a signal handler fails. #[derive(Debug)] -#[cfg_attr(unix, derive(Error))] +#[cfg_attr(all(unix, feature = "signals"), derive(Error))] pub enum SetHandlerError { /// An unsafe signal was attempted to be handled using `set` instead of `set_unsafe`. #[cfg_attr( - unix, + all(unix, feature = "signals"), error("an unsafe signal was attempted to be handled using `set` instead of `set_unsafe`") )] UnsafeSignal, @@ -592,13 +588,13 @@ pub enum SetHandlerError { /// [`Kill`]: enum.SignalType.html#variant.Kill " " /// [`ForceSuspend`]: enum.SignalType.html#variant.ForceSuspend " " #[cfg_attr( - unix, + all(unix, feature = "signals"), error("the signal {:?} cannot be handled", .0), )] UnblockableSignal(SignalType), /// The specified real-time signal is not available on this OS. #[cfg_attr( - unix, + all(unix, feature = "signals"), error( "the real-time signal number {} is not available ({} is the highest possible)", .attempted, @@ -613,10 +609,10 @@ pub enum SetHandlerError { }, /// An unexpected OS error ocurred during signal handler setup. #[cfg_attr( - unix, + all(unix, feature = "signals"), error("{}", .0), )] - UnexpectedSystemCallFailure(#[cfg_attr(unix, from)] io::Error), + UnexpectedSystemCallFailure(#[cfg_attr(all(unix, feature = "signals"), from)] io::Error), } /// The actual hook which is passed to `sigaction` which dispatches signals according to the global handler map (the `HANDLERS` static). @@ -739,7 +735,7 @@ impl From for fn() { /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(unix)] { +/// # #[cfg(all(unix, feature = "signals"))] { /// use interprocess::os::unix::signal::{self, SignalType}; /// use std::process; /// @@ -768,7 +764,7 @@ pub fn send(signal: impl Into>, pid: impl Into) -> io::R /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(unix)] { +/// # #[cfg(all(unix, feature = "signals"))] { /// use interprocess::os::unix::signal::{self, SignalType}; /// use std::process; /// @@ -801,7 +797,7 @@ pub fn send_rt(signal: impl Into>, pid: impl Into) -> io::Resul /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(unix)] { +/// # #[cfg(all(unix, feature = "signals"))] { /// use interprocess::os::unix::signal::{self, SignalType}; /// use std::process; /// @@ -827,7 +823,7 @@ pub fn send_to_group(signal: impl Into>, pid: impl Into) /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(unix)] { +/// # #[cfg(all(unix, feature = "signals"))] { /// use interprocess::os::unix::signal::{self, SignalType}; /// use std::process; /// diff --git a/src/os/windows/imports.rs b/src/os/windows/imports.rs new file mode 100644 index 00000000..700ced69 --- /dev/null +++ b/src/os/windows/imports.rs @@ -0,0 +1,71 @@ +#![allow(unused_imports, dead_code, unused_macros, non_camel_case_types)] +use cfg_if::cfg_if; + +macro_rules! fake_consts { + ($ty:ty, $($name:ident = $val:expr),+ $(,)?) => ( + $( + pub const $name : $ty = $val; + )+ + ); +} + +cfg_if! { + if #[cfg(windows)] { + pub use winapi::{ + shared::{minwindef::{DWORD, LPVOID}, ntdef::HANDLE, winerror::ERROR_PIPE_CONNECTED}, + um::{ + winbase::{ + FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_ACCESS_DUPLEX, PIPE_ACCESS_INBOUND, + PIPE_ACCESS_OUTBOUND, PIPE_READMODE_BYTE, PIPE_READMODE_MESSAGE, + PIPE_TYPE_BYTE, PIPE_TYPE_MESSAGE, + }, + winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE}, + fileapi::{CreateFileW, OPEN_EXISTING, FlushFileBuffers, ReadFile, WriteFile}, + handleapi::{CloseHandle, DuplicateHandle, INVALID_HANDLE_VALUE}, + namedpipeapi::{ + ConnectNamedPipe, DisconnectNamedPipe, + PeekNamedPipe, + CreatePipe, CreateNamedPipeW, SetNamedPipeHandleState, + }, + winbase::{ + GetNamedPipeClientProcessId, GetNamedPipeClientSessionId, + GetNamedPipeServerProcessId, GetNamedPipeServerSessionId, + }, + minwinbase::SECURITY_ATTRIBUTES, + processthreadsapi::GetCurrentProcess, + }, + }; + pub use std::os::windows::{io::{AsRawHandle, FromRawHandle, IntoRawHandle}, ffi::OsStrExt}; + } else { + pub type HANDLE = *mut (); + pub trait AsRawHandle {} + pub trait IntoRawHandle {} + pub unsafe trait FromRawHandle {} + pub type DWORD = u32; + pub struct SECURITY_ATTRIBUTES {} + pub type LPVOID = *mut (); + + fake_consts! {u32, + PIPE_ACCESS_INBOUND = 0, PIPE_ACCESS_OUTBOUND = 1, PIPE_ACCESS_DUPLEX = 2, + PIPE_TYPE_BYTE = 1, PIPE_TYPE_MESSAGE = 2, + PIPE_READMODE_BYTE = 0, PIPE_READMODE_MESSAGE = 1, + } + } +} + +cfg_if! { + if #[cfg(all(windows, feature = "signals"))] { + pub use libc::{sighandler_t, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM}; + pub use intmap::IntMap; + pub use once_cell::sync::Lazy; + pub use spinning::{RwLock, RwLockUpgradableReadGuard}; + pub use thiserror::Error; + + // FIXME this is not yet in libc, remove when PR #1626 on rust-lang/libc gets merged + pub const SIG_DFL: sighandler_t = 0; + } else { + fake_consts! {i32, + SIGABRT = 100, SIGFPE = 101, SIGILL = 102, SIGINT = 103, SIGSEGV = 104, SIGTERM = 105, + } + } +} diff --git a/src/os/windows/mod.rs b/src/os/windows/mod.rs index a25f8f09..c1211e8c 100644 --- a/src/os/windows/mod.rs +++ b/src/os/windows/mod.rs @@ -1,6 +1,8 @@ //! Windows-specific functionality for various interprocess communication primitives, as well as Windows-specific ones. pub mod named_pipe; +#[cfg(any(doc, feature = "signals"))] +#[cfg_attr(feature = "doc_cfg", doc(cfg(feature = "signals")))] pub mod signal; pub mod unnamed_pipe; // TODO mailslots @@ -8,29 +10,9 @@ pub mod unnamed_pipe; #[cfg(windows)] pub(crate) mod local_socket; -#[cfg(windows)] -use winapi::{ - shared::{minwindef::DWORD, ntdef::HANDLE}, - um::{ - fileapi::{FlushFileBuffers, ReadFile, WriteFile}, - handleapi::{CloseHandle, DuplicateHandle, INVALID_HANDLE_VALUE}, - processthreadsapi::GetCurrentProcess, - }, -}; -#[cfg(not(windows))] -#[doc(hidden)] -pub type HANDLE = *mut (); -#[cfg(not(windows))] -#[doc(hidden)] -pub trait AsRawHandle {} -#[cfg(not(windows))] -#[doc(hidden)] -pub trait IntoRawHandle {} -#[cfg(not(windows))] -#[doc(hidden)] -pub unsafe trait FromRawHandle {} -#[cfg(windows)] -use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle}; +mod imports; +use imports::*; + use std::{io, mem, ptr}; /// Objects which own handles which can be shared with another processes. @@ -66,9 +48,13 @@ pub trait ShareHandle: AsRawHandle { } } } +#[cfg(windows)] impl ShareHandle for crate::unnamed_pipe::UnnamedPipeReader {} +#[cfg(windows)] impl ShareHandle for unnamed_pipe::UnnamedPipeReader {} +#[cfg(windows)] impl ShareHandle for crate::unnamed_pipe::UnnamedPipeWriter {} +#[cfg(windows)] impl ShareHandle for unnamed_pipe::UnnamedPipeWriter {} /// Newtype wrapper which defines file I/O operations on a `HANDLE` to a file. diff --git a/src/os/windows/named_pipe.rs b/src/os/windows/named_pipe.rs index d5f07410..58b4ada1 100644 --- a/src/os/windows/named_pipe.rs +++ b/src/os/windows/named_pipe.rs @@ -12,9 +12,8 @@ // TODO improve docs, add examples +use super::imports::*; use super::{AsRawHandle, FromRawHandle, IntoRawHandle}; -#[cfg(windows)] -use std::os::windows::ffi::OsStrExt; use std::{ borrow::Cow, convert::{TryFrom, TryInto}, @@ -30,40 +29,7 @@ use std::{ Arc, RwLock, }, }; -#[cfg(windows)] -use winapi::{ - shared::minwindef::DWORD, - um::{ - fileapi::{CreateFileW, OPEN_EXISTING}, - handleapi::INVALID_HANDLE_VALUE, - namedpipeapi::{CreateNamedPipeW, SetNamedPipeHandleState}, - winbase::{ - FILE_FLAG_FIRST_PIPE_INSTANCE, PIPE_ACCESS_DUPLEX, PIPE_ACCESS_INBOUND, - PIPE_ACCESS_OUTBOUND, PIPE_READMODE_BYTE, PIPE_READMODE_MESSAGE, PIPE_TYPE_BYTE, - PIPE_TYPE_MESSAGE, - }, - winnt::{FILE_SHARE_READ, FILE_SHARE_WRITE, GENERIC_READ, GENERIC_WRITE, HANDLE}, - }, -}; -#[cfg(not(windows))] -macro_rules! fake_consts { - ($($name:ident = $val:expr),+ $(,)?) => ( - $( - #[cfg(not(windows))] - const $name : u32 = $val; - )+ - ); -} -#[cfg(not(windows))] -fake_consts! { - PIPE_ACCESS_INBOUND = 0, PIPE_ACCESS_OUTBOUND = 1, PIPE_ACCESS_DUPLEX = 2, - PIPE_TYPE_BYTE = 1, PIPE_TYPE_MESSAGE = 2, - PIPE_READMODE_BYTE = 0, PIPE_READMODE_MESSAGE = 1, -} -#[cfg(not(windows))] -#[doc(hidden)] -pub type DWORD = u32; use crate::{PartialMsgWriteError, ReliableReadMsg, Sealed}; fn convert_path(osstr: &OsStr) -> Vec { @@ -210,11 +176,7 @@ unsafe fn set_nonblocking_for_stream( } mod pipe_listener_debug_impl { - #[cfg(windows)] - use super::AsRawHandle; - use super::{ - fmt, Arc, AtomicBool, Debug, Formatter, Ordering, PipeListener, PipeOps, PipeStream, RwLock, - }; + use super::*; /// Shim used to improve pipe instance formatting struct Instance<'a> { instance: &'a (PipeOps, AtomicBool), @@ -263,31 +225,12 @@ mod pipe_listener_debug_impl { } } -// SAFETY: all fields are Send and Sync except for the PhantomData -//unsafe impl Send for PipeListener {} -//unsafe impl Sync for PipeListener {} - use seal::*; mod seal { use super::super::FileHandleOps; - #[cfg(windows)] - use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle}; - use std::{io, ptr, sync::atomic::AtomicBool}; - #[cfg(windows)] - use winapi::{ - shared::{minwindef::DWORD, winerror::ERROR_PIPE_CONNECTED}, - um::{ - fileapi::ReadFile, - namedpipeapi::{ConnectNamedPipe, DisconnectNamedPipe, PeekNamedPipe}, - winbase::{ - GetNamedPipeClientProcessId, GetNamedPipeClientSessionId, - GetNamedPipeServerProcessId, GetNamedPipeServerSessionId, - }, - winnt::HANDLE, - }, - }; + use super::*; - pub trait NamedPipeStreamInternals: From> {} + pub trait NamedPipeStreamInternals: From> {} /// The actual implementation of a named pipe server or client. #[repr(transparent)] @@ -787,12 +730,14 @@ macro_rules! create_stream_type { Ok(()) } } + #[cfg(windows)] impl PipeStream for $ty { const ROLE: PipeStreamRole = $role; const WRITE_MODE: Option = $write_mode; const READ_MODE: Option = $read_mode; } impl Sealed for $ty {} + #[cfg(windows)] impl NamedPipeStreamInternals for $ty {} impl Drop for $ty { #[inline] diff --git a/src/os/windows/signal.rs b/src/os/windows/signal.rs index ed29d319..1c0d86a4 100644 --- a/src/os/windows/signal.rs +++ b/src/os/windows/signal.rs @@ -11,29 +11,20 @@ //! - atomic C functions, but only the ones which are lock-free (practically never used in Rust since it has its own atomics which use compiler intrinsics) //! - `atomic_is_lock_free` -// TODO unfinished - -use intmap::IntMap; -use lazy_static::lazy_static; -use libc::{sighandler_t, SIGABRT, SIGFPE, SIGILL, SIGINT, SIGSEGV, SIGTERM}; -use spinning::{RwLock, RwLockUpgradableReadGuard}; +use super::imports::*; use std::{ convert::{TryFrom, TryInto}, error::Error, fmt::{self, Formatter}, panic, process, }; -use thiserror::Error; - -// FIXME this is not yet in libc, remove when PR #1626 on rust-lang/libc gets merged -const SIG_DFL: sighandler_t = 0; /// Installs the specified handler for the specified signal. /// /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(windows)] { +/// # #[cfg(all(windows, feature = "signals"))] { /// use interprocess::os::windows::signal::{self, SignalType, SignalHandler}; /// /// let handler = unsafe { @@ -70,7 +61,7 @@ pub fn set_handler(signal_type: SignalType, handler: SignalHandler) -> Result<() /// # Example /// ```no_run /// # fn main() -> Result<(), Box> { -/// # #[cfg(windows)] { +/// # #[cfg(all(windows, feature = "signals"))] { /// use interprocess::os::windows::signal::{self, SignalType, SignalHandler}; /// /// let handler = unsafe { @@ -121,9 +112,8 @@ pub unsafe fn set_unsafe_handler( Ok(()) } -lazy_static! { - static ref HANDLERS: RwLock> = RwLock::new(IntMap::new()); -} +#[cfg(all(windows, feature = "signals"))] +static HANDLERS: Lazy>> = Lazy::new(|| RwLock::new(IntMap::new())); unsafe fn install_hook(signum: i32, hook: usize) -> Result<(), ()> { let success = { libc::signal(signum, hook) != libc::SIG_ERR as _ }; @@ -158,16 +148,23 @@ extern "C" fn signal_receiver(signum: i32) { } /// The error produced when setting a signal handler fails. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Error)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[cfg_attr(all(windows, feature = "signals"), derive(Error))] pub enum SetHandlerError { /// An unsafe signal was attempted to be handled using `set_handler` instead of `set_unsafe_handler`. - #[error( - "\ + #[cfg_attr( + all(windows, feature = "signals"), + error( + "\ an unsafe signal was attempted to be handled using `set_handler` instead of `set_unsafe_handler`" + ) )] UnsafeSignal, /// the C library call unexpectedly failed without error information. - #[error("the C library call unexpectedly failed without error information")] + #[cfg_attr( + all(windows, feature = "signals"), + error("the C library call unexpectedly failed without error information") + )] UnexpectedLibcCallFailure, } diff --git a/src/os/windows/unnamed_pipe.rs b/src/os/windows/unnamed_pipe.rs index c05a413a..f9f75201 100644 --- a/src/os/windows/unnamed_pipe.rs +++ b/src/os/windows/unnamed_pipe.rs @@ -6,36 +6,16 @@ // TODO add examples -#[cfg(windows)] -use std::os::windows::io::{AsRawHandle, FromRawHandle, IntoRawHandle}; +use super::imports::*; +use super::FileHandleOps; +use crate::unnamed_pipe::{UnnamedPipeReader as PubReader, UnnamedPipeWriter as PubWriter}; use std::{ fmt::{self, Debug, Formatter}, io::{self, Read, Write}, mem::{self, size_of, zeroed}, num::NonZeroUsize, + ptr, }; -#[cfg(windows)] -use winapi::{ - shared::{ - minwindef::LPVOID, - ntdef::{HANDLE, NULL}, - }, - um::{ - handleapi::INVALID_HANDLE_VALUE, minwinbase::SECURITY_ATTRIBUTES, namedpipeapi::CreatePipe, - }, -}; -#[cfg(not(windows))] -#[doc(hidden)] -#[allow(non_camel_case_types)] -pub struct SECURITY_ATTRIBUTES {} -#[cfg(not(windows))] -#[doc(hidden)] -pub type LPVOID = *mut (); -#[cfg(not(windows))] -#[doc(hidden)] -pub const NULL: LPVOID = 0 as _; -use super::FileHandleOps; -use crate::unnamed_pipe::{UnnamedPipeReader as PubReader, UnnamedPipeWriter as PubWriter}; /// Builder used to create unnamed pipes while supplying additional options. /// @@ -62,7 +42,7 @@ impl UnnamedPipeCreationOptions { pub const fn new() -> Self { Self { inheritable: true, - security_descriptor: NULL, + security_descriptor: ptr::null_mut(), buffer_size_hint: None, } }