summaryrefslogtreecommitdiff
path: root/src/sys
diff options
context:
space:
mode:
authorMarcin Mielniczuk <marmistrz.dev@zoho.eu>2017-08-10 10:16:04 +0200
committerMarcin Mielniczuk <marmistrz.dev@zoho.eu>2017-08-10 10:16:04 +0200
commitd8968f4b677ae5dd10d5cacc4121354fd292c235 (patch)
tree7ec844c4fc41db902fb5fa6eda11d9420330984a /src/sys
parent0587977055a89673e1e34baab008e6b03831f15a (diff)
parent087aece15568b3e7cb6a351301e2afc83c746ca7 (diff)
downloadnix-d8968f4b677ae5dd10d5cacc4121354fd292c235.zip
Merge remote-tracking branch 'upstream/master' into ptrace-noreg
Diffstat (limited to 'src/sys')
-rw-r--r--src/sys/event.rs38
-rw-r--r--src/sys/signal.rs193
-rw-r--r--src/sys/socket/ffi.rs19
-rw-r--r--src/sys/socket/mod.rs37
-rw-r--r--src/sys/wait.rs19
5 files changed, 186 insertions, 120 deletions
diff --git a/src/sys/event.rs b/src/sys/event.rs
index 95b7619e..9215c654 100644
--- a/src/sys/event.rs
+++ b/src/sys/event.rs
@@ -18,17 +18,16 @@ pub struct KEvent {
kevent: libc::kevent,
}
-#[cfg(any(target_os = "openbsd", target_os = "freebsd",
- target_os = "dragonfly", target_os = "macos",
- target_os = "ios"))]
+#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "openbsd"))]
type type_of_udata = *mut libc::c_void;
-#[cfg(any(target_os = "openbsd", target_os = "freebsd",
- target_os = "dragonfly", target_os = "macos",
- target_os = "ios"))]
+#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos"))]
type type_of_data = libc::intptr_t;
#[cfg(any(target_os = "netbsd"))]
type type_of_udata = intptr_t;
-#[cfg(any(target_os = "netbsd"))]
+#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
type type_of_data = libc::int64_t;
#[cfg(not(target_os = "netbsd"))]
@@ -78,10 +77,11 @@ pub enum EventFilter {
EVFILT_TIMER = libc::EVFILT_TIMER,
}
-#[cfg(any(target_os = "macos", target_os = "ios",
- target_os = "freebsd", target_os = "dragonfly"))]
+#[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "openbsd"))]
pub type type_of_event_flag = u16;
-#[cfg(any(target_os = "netbsd", target_os = "openbsd"))]
+#[cfg(any(target_os = "netbsd"))]
pub type type_of_event_flag = u32;
libc_bitflags!{
pub flags EventFlag: type_of_event_flag {
@@ -89,6 +89,14 @@ libc_bitflags!{
EV_CLEAR,
EV_DELETE,
EV_DISABLE,
+ // No released version of OpenBSD supports EV_DISPATCH or EV_RECEIPT.
+ // These have been commited to the -current branch though and are
+ // expected to be part of the OpenBSD 6.2 release in Nov 2017.
+ // See: https://marc.info/?l=openbsd-tech&m=149621427511219&w=2
+ // https://github.com/rust-lang/libc/pull/613
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "netbsd"))]
EV_DISPATCH,
#[cfg(target_os = "freebsd")]
EV_DROP,
@@ -105,7 +113,9 @@ libc_bitflags!{
EV_OOBAND,
#[cfg(any(target_os = "macos", target_os = "ios"))]
EV_POLL,
- #[cfg(not(target_os = "openbsd"))]
+ #[cfg(any(target_os = "dragonfly", target_os = "freebsd",
+ target_os = "ios", target_os = "macos",
+ target_os = "netbsd"))]
EV_RECEIPT,
EV_SYSFLAGS,
}
@@ -315,13 +325,13 @@ fn test_struct_kevent() {
let expected = libc::kevent{ident: 0xdeadbeef,
filter: libc::EVFILT_READ,
- flags: libc::EV_DISPATCH | libc::EV_ADD,
+ flags: libc::EV_ONESHOT | libc::EV_ADD,
fflags: libc::NOTE_CHILD | libc::NOTE_EXIT,
data: 0x1337,
udata: udata as type_of_udata};
let actual = KEvent::new(0xdeadbeef,
EventFilter::EVFILT_READ,
- EV_DISPATCH | EV_ADD,
+ EV_ONESHOT | EV_ADD,
NOTE_CHILD | NOTE_EXIT,
0x1337,
udata);
@@ -329,7 +339,7 @@ fn test_struct_kevent() {
assert!(expected.filter == actual.filter() as type_of_event_filter);
assert!(expected.flags == actual.flags().bits());
assert!(expected.fflags == actual.fflags().bits());
- assert!(expected.data == actual.data());
+ assert!(expected.data == actual.data() as type_of_data);
assert!(expected.udata == actual.udata() as type_of_udata);
assert!(mem::size_of::<libc::kevent>() == mem::size_of::<KEvent>());
}
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() }
+ }
}
}
diff --git a/src/sys/socket/ffi.rs b/src/sys/socket/ffi.rs
index 55a47eb6..265a97c9 100644
--- a/src/sys/socket/ffi.rs
+++ b/src/sys/socket/ffi.rs
@@ -3,9 +3,12 @@
pub use libc::{socket, listen, bind, accept, connect, setsockopt, sendto, recvfrom, getsockname, getpeername, recv, send};
-use libc::{c_int, c_void, socklen_t, size_t, ssize_t};
+use libc::{c_int, c_void, socklen_t, ssize_t};
-#[cfg(target_os = "macos")]
+#[cfg(not(target_os = "macos"))]
+use libc::size_t;
+
+#[cfg(not(target_os = "linux"))]
use libc::c_uint;
use sys::uio::IoVec;
@@ -23,19 +26,27 @@ pub type type_of_cmsg_data = c_uint;
#[cfg(not(target_os = "macos"))]
pub type type_of_cmsg_data = size_t;
+#[cfg(target_os = "linux")]
+pub type type_of_msg_iovlen = size_t;
+
+#[cfg(not(target_os = "linux"))]
+pub type type_of_msg_iovlen = c_uint;
+
// Private because we don't expose any external functions that operate
// directly on this type; we just use it internally at FFI boundaries.
// Note that in some cases we store pointers in *const fields that the
// kernel will proceed to mutate, so users should be careful about the
// actual mutability of data pointed to by this structure.
+//
+// FIXME: Replace these structs with the ones defined in libc
#[repr(C)]
pub struct msghdr<'a> {
pub msg_name: *const c_void,
pub msg_namelen: socklen_t,
pub msg_iov: *const IoVec<&'a [u8]>,
- pub msg_iovlen: size_t,
+ pub msg_iovlen: type_of_msg_iovlen,
pub msg_control: *const c_void,
- pub msg_controllen: size_t,
+ pub msg_controllen: type_of_cmsg_len,
pub msg_flags: c_int,
}
diff --git a/src/sys/socket/mod.rs b/src/sys/socket/mod.rs
index 86129fcf..6ab1684a 100644
--- a/src/sys/socket/mod.rs
+++ b/src/sys/socket/mod.rs
@@ -168,7 +168,7 @@ unsafe fn copy_bytes<'a, 'b, T: ?Sized>(src: &T, dst: &'a mut &'b mut [u8]) {
}
-use self::ffi::{cmsghdr, msghdr, type_of_cmsg_len, type_of_cmsg_data};
+use self::ffi::{cmsghdr, msghdr, type_of_cmsg_data, type_of_msg_iovlen, type_of_cmsg_len};
/// A structure used to make room in a cmsghdr passed to recvmsg. The
/// size and alignment match that of a cmsghdr followed by a T, but the
@@ -204,11 +204,17 @@ impl<'a> RecvMsg<'a> {
/// Iterate over the valid control messages pointed to by this
/// msghdr.
pub fn cmsgs(&self) -> CmsgIterator {
- CmsgIterator(self.cmsg_buffer)
+ CmsgIterator {
+ buf: self.cmsg_buffer,
+ next: 0
+ }
}
}
-pub struct CmsgIterator<'a>(&'a [u8]);
+pub struct CmsgIterator<'a> {
+ buf: &'a [u8],
+ next: usize,
+}
impl<'a> Iterator for CmsgIterator<'a> {
type Item = ControlMessage<'a>;
@@ -217,12 +223,11 @@ impl<'a> Iterator for CmsgIterator<'a> {
// although we handle the invariants in slightly different places to
// get a better iterator interface.
fn next(&mut self) -> Option<ControlMessage<'a>> {
- let buf = self.0;
let sizeof_cmsghdr = mem::size_of::<cmsghdr>();
- if buf.len() < sizeof_cmsghdr {
+ if self.buf.len() < sizeof_cmsghdr {
return None;
}
- let cmsg: &cmsghdr = unsafe { mem::transmute(buf.as_ptr()) };
+ let cmsg: &cmsghdr = unsafe { mem::transmute(self.buf.as_ptr()) };
// This check is only in the glibc implementation of CMSG_NXTHDR
// (although it claims the kernel header checks this), but such
@@ -232,12 +237,20 @@ impl<'a> Iterator for CmsgIterator<'a> {
return None;
}
let len = cmsg_len - sizeof_cmsghdr;
+ let aligned_cmsg_len = if self.next == 0 {
+ // CMSG_FIRSTHDR
+ cmsg_len
+ } else {
+ // CMSG_NXTHDR
+ cmsg_align(cmsg_len)
+ };
// Advance our internal pointer.
- if cmsg_align(cmsg_len) > buf.len() {
+ if aligned_cmsg_len > self.buf.len() {
return None;
}
- self.0 = &buf[cmsg_align(cmsg_len)..];
+ self.buf = &self.buf[aligned_cmsg_len..];
+ self.next += 1;
match (cmsg.cmsg_level, cmsg.cmsg_type) {
(libc::SOL_SOCKET, libc::SCM_RIGHTS) => unsafe {
@@ -370,9 +383,9 @@ pub fn sendmsg<'a>(fd: RawFd, iov: &[IoVec<&'a [u8]>], cmsgs: &[ControlMessage<'
msg_name: name as *const c_void,
msg_namelen: namelen,
msg_iov: iov.as_ptr(),
- msg_iovlen: iov.len() as size_t,
+ msg_iovlen: iov.len() as type_of_msg_iovlen,
msg_control: cmsg_ptr,
- msg_controllen: capacity as size_t,
+ msg_controllen: capacity as type_of_cmsg_len,
msg_flags: 0,
};
let ret = unsafe { ffi::sendmsg(fd, &mhdr, flags.bits()) };
@@ -393,9 +406,9 @@ pub fn recvmsg<'a, T>(fd: RawFd, iov: &[IoVec<&mut [u8]>], cmsg_buffer: Option<&
msg_name: &mut address as *const _ as *const c_void,
msg_namelen: mem::size_of::<sockaddr_storage>() as socklen_t,
msg_iov: iov.as_ptr() as *const IoVec<&[u8]>, // safe cast to add const-ness
- msg_iovlen: iov.len() as size_t,
+ msg_iovlen: iov.len() as type_of_msg_iovlen,
msg_control: msg_control as *const c_void,
- msg_controllen: msg_controllen as size_t,
+ msg_controllen: msg_controllen as type_of_cmsg_len,
msg_flags: 0,
};
let ret = unsafe { ffi::recvmsg(fd, &mut mhdr, flags.bits()) };
diff --git a/src/sys/wait.rs b/src/sys/wait.rs
index f31f666d..b2ca3bd6 100644
--- a/src/sys/wait.rs
+++ b/src/sys/wait.rs
@@ -93,6 +93,25 @@ pub enum WaitStatus {
StillAlive
}
+impl WaitStatus {
+ /// Extracts the PID from the WaitStatus unless it equals StillAlive.
+ pub fn pid(&self) -> Option<Pid> {
+ use self::WaitStatus::*;
+ match *self {
+ Exited(p, _) => Some(p),
+ Signaled(p, _, _) => Some(p),
+ Stopped(p, _) => Some(p),
+ Continued(p) => Some(p),
+ StillAlive => None,
+
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ PtraceEvent(p, _, _) => Some(p),
+ #[cfg(any(target_os = "linux", target_os = "android"))]
+ PtraceSyscall(p) => Some(p),
+ }
+ }
+}
+
#[cfg(any(target_os = "linux",
target_os = "android"))]
mod status {