aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-08-19 17:48:00 -0600
committerFenrir <[email protected]>2018-08-19 17:56:18 -0600
commit5d28bfcfd6086c3328837de9695099ea39048d0d (patch)
treea514fde042ff2a504a03305bfe0894ff8cd8d47e /ctr-std/src/sys
parentUpdate for latest nightly 2018-06-09 (#70) (diff)
downloadctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.tar.xz
ctru-rs-5d28bfcfd6086c3328837de9695099ea39048d0d.zip
Update for nightly-2018-08-18
Diffstat (limited to 'ctr-std/src/sys')
-rw-r--r--ctr-std/src/sys/cloudabi/abi/cloudabi.rs18
-rw-r--r--ctr-std/src/sys/cloudabi/backtrace.rs18
-rw-r--r--ctr-std/src/sys/cloudabi/thread.rs2
-rw-r--r--ctr-std/src/sys/horizon/net.rs13
-rw-r--r--ctr-std/src/sys/mod.rs3
-rw-r--r--ctr-std/src/sys/redox/args.rs16
-rw-r--r--ctr-std/src/sys/redox/backtrace/tracing.rs18
-rw-r--r--ctr-std/src/sys/redox/ext/mod.rs1
-rw-r--r--ctr-std/src/sys/redox/ext/net.rs769
-rw-r--r--ctr-std/src/sys/redox/fd.rs5
-rw-r--r--ctr-std/src/sys/redox/net/mod.rs4
-rw-r--r--ctr-std/src/sys/redox/net/netc.rs2
-rw-r--r--ctr-std/src/sys/redox/net/udp.rs2
-rw-r--r--ctr-std/src/sys/redox/os.rs3
-rw-r--r--ctr-std/src/sys/redox/process.rs15
-rw-r--r--ctr-std/src/sys/redox/thread.rs2
-rw-r--r--ctr-std/src/sys/unix/args.rs19
-rw-r--r--ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs18
-rw-r--r--ctr-std/src/sys/unix/condvar.rs13
-rw-r--r--ctr-std/src/sys/unix/env.rs11
-rw-r--r--ctr-std/src/sys/unix/ext/fs.rs127
-rw-r--r--ctr-std/src/sys/unix/ext/mod.rs1
-rw-r--r--ctr-std/src/sys/unix/ext/net.rs6
-rw-r--r--ctr-std/src/sys/unix/fast_thread_local.rs7
-rw-r--r--ctr-std/src/sys/unix/fs.rs56
-rw-r--r--ctr-std/src/sys/unix/mod.rs1
-rw-r--r--ctr-std/src/sys/unix/mutex.rs9
-rw-r--r--ctr-std/src/sys/unix/os.rs39
-rw-r--r--ctr-std/src/sys/unix/process/process_common.rs6
-rw-r--r--ctr-std/src/sys/unix/rand.rs29
-rw-r--r--ctr-std/src/sys/unix/thread.rs5
-rw-r--r--ctr-std/src/sys/unix/time.rs4
-rw-r--r--ctr-std/src/sys/wasm/os.rs2
-rw-r--r--ctr-std/src/sys/wasm/thread.rs2
-rw-r--r--ctr-std/src/sys/windows/backtrace/mod.rs297
-rw-r--r--ctr-std/src/sys/windows/backtrace/printing/mod.rs14
-rw-r--r--ctr-std/src/sys/windows/backtrace/printing/msvc.rs196
-rw-r--r--ctr-std/src/sys/windows/c.rs82
-rw-r--r--ctr-std/src/sys/windows/ext/ffi.rs3
-rw-r--r--ctr-std/src/sys/windows/ext/mod.rs1
-rw-r--r--ctr-std/src/sys/windows/mod.rs10
-rw-r--r--ctr-std/src/sys/windows/process.rs8
-rw-r--r--ctr-std/src/sys/windows/thread.rs5
43 files changed, 1578 insertions, 284 deletions
diff --git a/ctr-std/src/sys/cloudabi/abi/cloudabi.rs b/ctr-std/src/sys/cloudabi/abi/cloudabi.rs
index 2909db5..cd9a5ad 100644
--- a/ctr-std/src/sys/cloudabi/abi/cloudabi.rs
+++ b/ctr-std/src/sys/cloudabi/abi/cloudabi.rs
@@ -121,6 +121,7 @@ include!("bitflags.rs");
/// File or memory access pattern advisory information.
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum advice {
/// The application expects that it will not access the
/// specified data in the near future.
@@ -140,12 +141,12 @@ pub enum advice {
/// The application expects to access the specified data
/// in the near future.
WILLNEED = 6,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
}
/// Enumeration describing the kind of value stored in [`auxv`](struct.auxv.html).
#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum auxtype {
/// Base address of the binary argument data provided to
/// [`proc_exec()`](fn.proc_exec.html).
@@ -210,12 +211,12 @@ pub enum auxtype {
SYSINFO_EHDR = 262,
/// Thread ID of the initial thread of the process.
TID = 261,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u32,
}
/// Identifiers for clocks.
#[repr(u32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum clockid {
/// The system-wide monotonic clock, which is defined as a
/// clock measuring real time, whose value cannot be
@@ -232,7 +233,6 @@ pub enum clockid {
REALTIME = 3,
/// The CPU-time clock associated with the current thread.
THREAD_CPUTIME_ID = 4,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u32,
}
/// A userspace condition variable.
@@ -267,6 +267,7 @@ pub const DIRCOOKIE_START: dircookie = dircookie(0);
/// exclusively or merely provided for alignment with POSIX.
#[repr(u16)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum errno {
/// No error occurred. System call completed successfully.
SUCCESS = 0,
@@ -422,7 +423,6 @@ pub enum errno {
XDEV = 75,
/// Extension: Capabilities insufficient.
NOTCAPABLE = 76,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u16,
}
bitflags! {
@@ -438,6 +438,7 @@ bitflags! {
/// Type of a subscription to an event or its occurrence.
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum eventtype {
/// The time value of clock [`subscription.union.clock.clock_id`](struct.subscription_clock.html#structfield.clock_id)
/// has reached timestamp [`subscription.union.clock.timeout`](struct.subscription_clock.html#structfield.timeout).
@@ -463,7 +464,6 @@ pub enum eventtype {
/// The process associated with process descriptor
/// [`subscription.union.proc_terminate.fd`](struct.subscription_proc_terminate.html#structfield.fd) has terminated.
PROC_TERMINATE = 7,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
}
/// Exit code generated by a process when exiting.
@@ -530,6 +530,7 @@ pub type filesize = u64;
/// The type of a file descriptor or file.
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum filetype {
/// The type of the file descriptor or file is unknown or
/// is different from any of the other types specified.
@@ -558,7 +559,6 @@ pub enum filetype {
SOCKET_STREAM = 130,
/// The file refers to a symbolic link inode.
SYMBOLIC_LINK = 144,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
}
bitflags! {
@@ -847,12 +847,12 @@ bitflags! {
/// memory.
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum scope {
/// The object is stored in private memory.
PRIVATE = 4,
/// The object is stored in shared memory.
SHARED = 8,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
}
bitflags! {
@@ -878,6 +878,7 @@ bitflags! {
/// Signal condition.
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum signal {
/// Process abort signal.
///
@@ -983,7 +984,6 @@ pub enum signal {
///
/// Action: Terminates the process.
XFSZ = 26,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
}
bitflags! {
@@ -1049,6 +1049,7 @@ pub type userdata = u64;
/// should be set.
#[repr(u8)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
+#[non_exhaustive]
pub enum whence {
/// Seek relative to current position.
CUR = 1,
@@ -1056,7 +1057,6 @@ pub enum whence {
END = 2,
/// Seek relative to start-of-file.
SET = 3,
- #[doc(hidden)] _NonExhaustive = -1 as isize as u8,
}
/// Auxiliary vector entry.
diff --git a/ctr-std/src/sys/cloudabi/backtrace.rs b/ctr-std/src/sys/cloudabi/backtrace.rs
index 1b97018..2c43b59 100644
--- a/ctr-std/src/sys/cloudabi/backtrace.rs
+++ b/ctr-std/src/sys/cloudabi/backtrace.rs
@@ -64,6 +64,10 @@ extern "C" fn trace_fn(
arg: *mut libc::c_void,
) -> uw::_Unwind_Reason_Code {
let cx = unsafe { &mut *(arg as *mut Context) };
+ if cx.idx >= cx.frames.len() {
+ return uw::_URC_NORMAL_STOP;
+ }
+
let mut ip_before_insn = 0;
let mut ip = unsafe { uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void };
if !ip.is_null() && ip_before_insn == 0 {
@@ -73,14 +77,12 @@ extern "C" fn trace_fn(
}
let symaddr = unsafe { uw::_Unwind_FindEnclosingFunction(ip) };
- if cx.idx < cx.frames.len() {
- cx.frames[cx.idx] = Frame {
- symbol_addr: symaddr as *mut u8,
- exact_position: ip as *mut u8,
- inline_context: 0,
- };
- cx.idx += 1;
- }
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr as *mut u8,
+ exact_position: ip as *mut u8,
+ inline_context: 0,
+ };
+ cx.idx += 1;
uw::_URC_NO_REASON
}
diff --git a/ctr-std/src/sys/cloudabi/thread.rs b/ctr-std/src/sys/cloudabi/thread.rs
index 5d66936..8cca47e 100644
--- a/ctr-std/src/sys/cloudabi/thread.rs
+++ b/ctr-std/src/sys/cloudabi/thread.rs
@@ -32,7 +32,7 @@ unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
impl Thread {
- pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> {
+ pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> {
let p = box p;
let mut native: libc::pthread_t = mem::zeroed();
let mut attr: libc::pthread_attr_t = mem::zeroed();
diff --git a/ctr-std/src/sys/horizon/net.rs b/ctr-std/src/sys/horizon/net.rs
index b6af433..14c58eb 100644
--- a/ctr-std/src/sys/horizon/net.rs
+++ b/ctr-std/src/sys/horizon/net.rs
@@ -148,7 +148,9 @@ impl Socket {
let mut pollfd = libc::pollfd {
fd: self.0.raw(),
- events: libc::POLLOUT,
+ // supposed to be `libc::POLLOUT`, but the value in the `libc` crate is currently
+ // incorrect for the 3DS
+ events: 0x10,
revents: 0,
};
@@ -184,9 +186,9 @@ impl Socket {
}
0 => {}
_ => {
- // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
- // for POLLHUP rather than read readiness
- if pollfd.revents & libc::POLLHUP != 0 {
+ // `libc::POLLHUP` should be 0x4, but the constant is currently defined
+ // incorrectly for 3DS. So we just specifiy it manually for now.
+ if pollfd.revents & 0x4 != 0 {
let e = self.take_error()?
.unwrap_or_else(|| {
io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
@@ -343,8 +345,7 @@ impl Socket {
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
- let mut nonblocking = nonblocking as libc::c_int;
- cvt(unsafe { libc::ioctl(*self.as_inner(), libc::FIONBIO as u32, &mut nonblocking) }).map(|_| ())
+ self.0.set_nonblocking(nonblocking)
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
diff --git a/ctr-std/src/sys/mod.rs b/ctr-std/src/sys/mod.rs
index d0ed80e..9aa6662 100644
--- a/ctr-std/src/sys/mod.rs
+++ b/ctr-std/src/sys/mod.rs
@@ -70,6 +70,7 @@ cfg_if! {
// (missing things in `libc` which is empty) so just omit everything
// with an empty module
#[unstable(issue = "0", feature = "std_internals")]
+ #[allow(missing_docs)]
pub mod unix_ext {}
} else {
// On other platforms like Windows document the bare bones of unix
@@ -83,11 +84,13 @@ cfg_if! {
cfg_if! {
if #[cfg(windows)] {
// On windows we'll just be documenting what's already available
+ #[allow(missing_docs)]
pub use self::ext as windows_ext;
} else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
// On CloudABI and wasm right now the shim below doesn't compile, so
// just omit it
#[unstable(issue = "0", feature = "std_internals")]
+ #[allow(missing_docs)]
pub mod windows_ext {}
} else {
// On all other platforms (aka linux/osx/etc) then pull in a "minimal"
diff --git a/ctr-std/src/sys/redox/args.rs b/ctr-std/src/sys/redox/args.rs
index 59ae2a7..556ed77 100644
--- a/ctr-std/src/sys/redox/args.rs
+++ b/ctr-std/src/sys/redox/args.rs
@@ -73,17 +73,15 @@ mod imp {
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
}).collect();
- LOCK.lock();
+ let _guard = LOCK.lock();
let ptr = get_global_ptr();
assert!((*ptr).is_none());
(*ptr) = Some(box args);
- LOCK.unlock();
}
pub unsafe fn cleanup() {
- LOCK.lock();
+ let _guard = LOCK.lock();
*get_global_ptr() = None;
- LOCK.unlock();
}
pub fn args() -> Args {
@@ -96,16 +94,14 @@ mod imp {
fn clone() -> Option<Vec<Vec<u8>>> {
unsafe {
- LOCK.lock();
+ let _guard = LOCK.lock();
let ptr = get_global_ptr();
- let ret = (*ptr).as_ref().map(|s| (**s).clone());
- LOCK.unlock();
- return ret
+ (*ptr).as_ref().map(|s| (**s).clone())
}
}
- fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
- unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
+ unsafe fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
+ mem::transmute(&GLOBAL_ARGS_PTR)
}
}
diff --git a/ctr-std/src/sys/redox/backtrace/tracing.rs b/ctr-std/src/sys/redox/backtrace/tracing.rs
index bb70ca3..c0414b7 100644
--- a/ctr-std/src/sys/redox/backtrace/tracing.rs
+++ b/ctr-std/src/sys/redox/backtrace/tracing.rs
@@ -68,6 +68,10 @@ pub fn unwind_backtrace(frames: &mut [Frame])
extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
let cx = unsafe { &mut *(arg as *mut Context) };
+ if cx.idx >= cx.frames.len() {
+ return uw::_URC_NORMAL_STOP;
+ }
+
let mut ip_before_insn = 0;
let mut ip = unsafe {
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
@@ -94,14 +98,12 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
};
- if cx.idx < cx.frames.len() {
- cx.frames[cx.idx] = Frame {
- symbol_addr: symaddr as *mut u8,
- exact_position: ip as *mut u8,
- inline_context: 0,
- };
- cx.idx += 1;
- }
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr as *mut u8,
+ exact_position: ip as *mut u8,
+ inline_context: 0,
+ };
+ cx.idx += 1;
uw::_URC_NO_REASON
}
diff --git a/ctr-std/src/sys/redox/ext/mod.rs b/ctr-std/src/sys/redox/ext/mod.rs
index 9fd8d6c..cb2c75a 100644
--- a/ctr-std/src/sys/redox/ext/mod.rs
+++ b/ctr-std/src/sys/redox/ext/mod.rs
@@ -33,6 +33,7 @@
pub mod ffi;
pub mod fs;
pub mod io;
+pub mod net;
pub mod process;
pub mod thread;
diff --git a/ctr-std/src/sys/redox/ext/net.rs b/ctr-std/src/sys/redox/ext/net.rs
new file mode 100644
index 0000000..2ab7770
--- /dev/null
+++ b/ctr-std/src/sys/redox/ext/net.rs
@@ -0,0 +1,769 @@
+// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+#![stable(feature = "unix_socket_redox", since = "1.29")]
+
+//! Unix-specific networking functionality
+
+use fmt;
+use io::{self, Error, ErrorKind, Initializer};
+use net::Shutdown;
+use os::unix::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+use path::Path;
+use time::Duration;
+use sys::{cvt, fd::FileDesc, syscall};
+
+/// An address associated with a Unix socket.
+///
+/// # Examples
+///
+/// ```
+/// use std::os::unix::net::UnixListener;
+///
+/// let socket = match UnixListener::bind("/tmp/sock") {
+/// Ok(sock) => sock,
+/// Err(e) => {
+/// println!("Couldn't bind: {:?}", e);
+/// return
+/// }
+/// };
+/// let addr = socket.local_addr().expect("Couldn't get local address");
+/// ```
+#[derive(Clone)]
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct SocketAddr(());
+
+impl SocketAddr {
+ /// Returns the contents of this address if it is a `pathname` address.
+ ///
+ /// # Examples
+ ///
+ /// With a pathname:
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ /// use std::path::Path;
+ ///
+ /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.as_pathname(), Some(Path::new("/tmp/sock")));
+ /// ```
+ ///
+ /// Without a pathname:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.as_pathname(), None);
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn as_pathname(&self) -> Option<&Path> {
+ None
+ }
+
+ /// Returns true if and only if the address is unnamed.
+ ///
+ /// # Examples
+ ///
+ /// A named address:
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let socket = UnixListener::bind("/tmp/sock").unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), false);
+ /// ```
+ ///
+ /// An unnamed address:
+ ///
+ /// ```
+ /// use std::os::unix::net::UnixDatagram;
+ ///
+ /// let socket = UnixDatagram::unbound().unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// assert_eq!(addr.is_unnamed(), true);
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn is_unnamed(&self) -> bool {
+ false
+ }
+}
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for SocketAddr {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ write!(fmt, "SocketAddr")
+ }
+}
+
+/// A Unix stream socket.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::os::unix::net::UnixStream;
+/// use std::io::prelude::*;
+///
+/// let mut stream = UnixStream::connect("/path/to/my/socket").unwrap();
+/// stream.write_all(b"hello world").unwrap();
+/// let mut response = String::new();
+/// stream.read_to_string(&mut response).unwrap();
+/// println!("{}", response);
+/// ```
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct UnixStream(FileDesc);
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for UnixStream {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixStream");
+ builder.field("fd", &self.0.raw());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ if let Ok(addr) = self.peer_addr() {
+ builder.field("peer", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixStream {
+ /// Connects to the socket named by `path`.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = match UnixStream::connect("/tmp/sock") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn connect<P: AsRef<Path>>(path: P) -> io::Result<UnixStream> {
+ if let Some(s) = path.as_ref().to_str() {
+ cvt(syscall::open(format!("chan:{}", s), syscall::O_CLOEXEC))
+ .map(FileDesc::new)
+ .map(UnixStream)
+ } else {
+ Err(Error::new(
+ ErrorKind::Other,
+ "UnixStream::connect: non-utf8 paths not supported on redox"
+ ))
+ }
+ }
+
+ /// Creates an unnamed pair of connected sockets.
+ ///
+ /// Returns two `UnixStream`s which are connected to each other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let (sock1, sock2) = match UnixStream::pair() {
+ /// Ok((sock1, sock2)) => (sock1, sock2),
+ /// Err(e) => {
+ /// println!("Couldn't create a pair of sockets: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn pair() -> io::Result<(UnixStream, UnixStream)> {
+ let server = cvt(syscall::open("chan:", syscall::O_CREAT | syscall::O_CLOEXEC))
+ .map(FileDesc::new)?;
+ let client = server.duplicate_path(b"connect")?;
+ let stream = server.duplicate_path(b"listen")?;
+ Ok((UnixStream(client), UnixStream(stream)))
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixStream` is a reference to the same stream that this
+ /// object references. Both handles will read and write the same stream of
+ /// data, and options set on one stream will be propagated to the other
+ /// stream.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let sock_copy = socket.try_clone().expect("Couldn't clone socket");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn try_clone(&self) -> io::Result<UnixStream> {
+ self.0.duplicate().map(UnixStream)
+ }
+
+ /// Returns the socket address of the local half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let addr = socket.local_addr().expect("Couldn't get local address");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::local_addr unimplemented on redox"))
+ }
+
+ /// Returns the socket address of the remote half of this connection.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let addr = socket.peer_addr().expect("Couldn't get peer address");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn peer_addr(&self) -> io::Result<SocketAddr> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::peer_addr unimplemented on redox"))
+ }
+
+ /// Sets the read timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`read`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+ /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// let result = socket.set_read_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn set_read_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::set_read_timeout unimplemented on redox"))
+ }
+
+ /// Sets the write timeout for the socket.
+ ///
+ /// If the provided value is [`None`], then [`write`] calls will block
+ /// indefinitely. An [`Err`] is returned if the zero [`Duration`] is
+ /// passed to this method.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`Err`]: ../../../../std/result/enum.Result.html#variant.Err
+ /// [`write`]: ../../../../std/io/trait.Write.html#tymethod.write
+ /// [`Duration`]: ../../../../std/time/struct.Duration.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+ /// ```
+ ///
+ /// An [`Err`] is returned if the zero [`Duration`] is passed to this
+ /// method:
+ ///
+ /// ```no_run
+ /// use std::io;
+ /// use std::net::UdpSocket;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UdpSocket::bind("127.0.0.1:34254").unwrap();
+ /// let result = socket.set_write_timeout(Some(Duration::new(0, 0)));
+ /// let err = result.unwrap_err();
+ /// assert_eq!(err.kind(), io::ErrorKind::InvalidInput)
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn set_write_timeout(&self, _timeout: Option<Duration>) -> io::Result<()> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::set_write_timeout unimplemented on redox"))
+ }
+
+ /// Returns the read timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_read_timeout(Some(Duration::new(1, 0))).expect("Couldn't set read timeout");
+ /// assert_eq!(socket.read_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::read_timeout unimplemented on redox"))
+ }
+
+ /// Returns the write timeout of this socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::time::Duration;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_write_timeout(Some(Duration::new(1, 0))).expect("Couldn't set write timeout");
+ /// assert_eq!(socket.write_timeout().unwrap(), Some(Duration::new(1, 0)));
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::write_timeout unimplemented on redox"))
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.set_nonblocking(true).expect("Couldn't set nonblocking");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// if let Ok(Some(err)) = socket.take_error() {
+ /// println!("Got error: {:?}", err);
+ /// }
+ /// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns None.
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ Ok(None)
+ }
+
+ /// Shuts down the read, write, or both halves of this connection.
+ ///
+ /// This function will cause all pending and future I/O calls on the
+ /// specified portions to immediately return with an appropriate value
+ /// (see the documentation of [`Shutdown`]).
+ ///
+ /// [`Shutdown`]: ../../../../std/net/enum.Shutdown.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixStream;
+ /// use std::net::Shutdown;
+ ///
+ /// let socket = UnixStream::connect("/tmp/sock").unwrap();
+ /// socket.shutdown(Shutdown::Both).expect("shutdown function failed");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn shutdown(&self, _how: Shutdown) -> io::Result<()> {
+ Err(Error::new(ErrorKind::Other, "UnixStream::shutdown unimplemented on redox"))
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl io::Read for UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ io::Read::read(&mut &*self, buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> io::Read for &'a UnixStream {
+ fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
+ self.0.read(buf)
+ }
+
+ #[inline]
+ unsafe fn initializer(&self) -> Initializer {
+ Initializer::nop()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl io::Write for UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ io::Write::write(&mut &*self, buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ io::Write::flush(&mut &*self)
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> io::Write for &'a UnixStream {
+ fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ fn flush(&mut self) -> io::Result<()> {
+ Ok(())
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl AsRawFd for UnixStream {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.raw()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl FromRawFd for UnixStream {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixStream {
+ UnixStream(FileDesc::new(fd))
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl IntoRawFd for UnixStream {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw()
+ }
+}
+
+/// A structure representing a Unix domain socket server.
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// // accept connections and process them, spawning a new thread for each one
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// /* connection succeeded */
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// /* connection failed */
+/// break;
+/// }
+/// }
+/// }
+/// ```
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct UnixListener(FileDesc);
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl fmt::Debug for UnixListener {
+ fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
+ let mut builder = fmt.debug_struct("UnixListener");
+ builder.field("fd", &self.0.raw());
+ if let Ok(addr) = self.local_addr() {
+ builder.field("local", &addr);
+ }
+ builder.finish()
+ }
+}
+
+impl UnixListener {
+ /// Creates a new `UnixListener` bound to the specified socket.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = match UnixListener::bind("/path/to/the/socket") {
+ /// Ok(sock) => sock,
+ /// Err(e) => {
+ /// println!("Couldn't connect: {:?}", e);
+ /// return
+ /// }
+ /// };
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn bind<P: AsRef<Path>>(path: P) -> io::Result<UnixListener> {
+ if let Some(s) = path.as_ref().to_str() {
+ cvt(syscall::open(format!("chan:{}", s), syscall::O_CREAT | syscall::O_CLOEXEC))
+ .map(FileDesc::new)
+ .map(UnixListener)
+ } else {
+ Err(Error::new(
+ ErrorKind::Other,
+ "UnixListener::bind: non-utf8 paths not supported on redox"
+ ))
+ }
+ }
+
+ /// Accepts a new incoming connection to this listener.
+ ///
+ /// This function will block the calling thread until a new Unix connection
+ /// is established. When established, the corresponding [`UnixStream`] and
+ /// the remote peer's address will be returned.
+ ///
+ /// [`UnixStream`]: ../../../../std/os/unix/net/struct.UnixStream.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// match listener.accept() {
+ /// Ok((socket, addr)) => println!("Got a client: {:?}", addr),
+ /// Err(e) => println!("accept function failed: {:?}", e),
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn accept(&self) -> io::Result<(UnixStream, SocketAddr)> {
+ self.0.duplicate_path(b"listen").map(|fd| (UnixStream(fd), SocketAddr(())))
+ }
+
+ /// Creates a new independently owned handle to the underlying socket.
+ ///
+ /// The returned `UnixListener` is a reference to the same socket that this
+ /// object references. Both handles can be used to accept incoming
+ /// connections and options set on one listener will affect the other.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let listener_copy = listener.try_clone().expect("try_clone failed");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn try_clone(&self) -> io::Result<UnixListener> {
+ self.0.duplicate().map(UnixListener)
+ }
+
+ /// Returns the local socket address of this listener.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// let addr = listener.local_addr().expect("Couldn't get local address");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn local_addr(&self) -> io::Result<SocketAddr> {
+ Err(Error::new(ErrorKind::Other, "UnixListener::local_addr unimplemented on redox"))
+ }
+
+ /// Moves the socket into or out of nonblocking mode.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// listener.set_nonblocking(true).expect("Couldn't set non blocking");
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ self.0.set_nonblocking(nonblocking)
+ }
+
+ /// Returns the value of the `SO_ERROR` option.
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::os::unix::net::UnixListener;
+ ///
+ /// let listener = UnixListener::bind("/tmp/sock").unwrap();
+ ///
+ /// if let Ok(Some(err)) = listener.take_error() {
+ /// println!("Got error: {:?}", err);
+ /// }
+ /// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns None.
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ Ok(None)
+ }
+
+ /// Returns an iterator over incoming connections.
+ ///
+ /// The iterator will never return [`None`] and will also not yield the
+ /// peer's [`SocketAddr`] structure.
+ ///
+ /// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+ /// [`SocketAddr`]: struct.SocketAddr.html
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// use std::thread;
+ /// use std::os::unix::net::{UnixStream, UnixListener};
+ ///
+ /// fn handle_client(stream: UnixStream) {
+ /// // ...
+ /// }
+ ///
+ /// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+ ///
+ /// for stream in listener.incoming() {
+ /// match stream {
+ /// Ok(stream) => {
+ /// thread::spawn(|| handle_client(stream));
+ /// }
+ /// Err(err) => {
+ /// break;
+ /// }
+ /// }
+ /// }
+ /// ```
+ #[stable(feature = "unix_socket_redox", since = "1.29")]
+ pub fn incoming<'a>(&'a self) -> Incoming<'a> {
+ Incoming { listener: self }
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl AsRawFd for UnixListener {
+ fn as_raw_fd(&self) -> RawFd {
+ self.0.raw()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl FromRawFd for UnixListener {
+ unsafe fn from_raw_fd(fd: RawFd) -> UnixListener {
+ UnixListener(FileDesc::new(fd))
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl IntoRawFd for UnixListener {
+ fn into_raw_fd(self) -> RawFd {
+ self.0.into_raw()
+ }
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> IntoIterator for &'a UnixListener {
+ type Item = io::Result<UnixStream>;
+ type IntoIter = Incoming<'a>;
+
+ fn into_iter(self) -> Incoming<'a> {
+ self.incoming()
+ }
+}
+
+/// An iterator over incoming connections to a [`UnixListener`].
+///
+/// It will never return [`None`].
+///
+/// [`None`]: ../../../../std/option/enum.Option.html#variant.None
+/// [`UnixListener`]: struct.UnixListener.html
+///
+/// # Examples
+///
+/// ```no_run
+/// use std::thread;
+/// use std::os::unix::net::{UnixStream, UnixListener};
+///
+/// fn handle_client(stream: UnixStream) {
+/// // ...
+/// }
+///
+/// let listener = UnixListener::bind("/path/to/the/socket").unwrap();
+///
+/// for stream in listener.incoming() {
+/// match stream {
+/// Ok(stream) => {
+/// thread::spawn(|| handle_client(stream));
+/// }
+/// Err(err) => {
+/// break;
+/// }
+/// }
+/// }
+/// ```
+#[derive(Debug)]
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+pub struct Incoming<'a> {
+ listener: &'a UnixListener,
+}
+
+#[stable(feature = "unix_socket_redox", since = "1.29")]
+impl<'a> Iterator for Incoming<'a> {
+ type Item = io::Result<UnixStream>;
+
+ fn next(&mut self) -> Option<io::Result<UnixStream>> {
+ Some(self.listener.accept().map(|s| s.0))
+ }
+
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ (usize::max_value(), None)
+ }
+}
diff --git a/ctr-std/src/sys/redox/fd.rs b/ctr-std/src/sys/redox/fd.rs
index ba7bbdc..e04e279 100644
--- a/ctr-std/src/sys/redox/fd.rs
+++ b/ctr-std/src/sys/redox/fd.rs
@@ -47,7 +47,10 @@ impl FileDesc {
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
- let new_fd = cvt(syscall::dup(self.fd, &[]))?;
+ self.duplicate_path(&[])
+ }
+ pub fn duplicate_path(&self, path: &[u8]) -> io::Result<FileDesc> {
+ let new_fd = cvt(syscall::dup(self.fd, path))?;
Ok(FileDesc::new(new_fd))
}
diff --git a/ctr-std/src/sys/redox/net/mod.rs b/ctr-std/src/sys/redox/net/mod.rs
index 0291d7f..67f2223 100644
--- a/ctr-std/src/sys/redox/net/mod.rs
+++ b/ctr-std/src/sys/redox/net/mod.rs
@@ -41,12 +41,12 @@ impl Iterator for LookupHost {
pub fn lookup_host(host: &str) -> Result<LookupHost> {
let mut ip_string = String::new();
File::open("/etc/net/ip")?.read_to_string(&mut ip_string)?;
- let ip: Vec<u8> = ip_string.trim().split(".").map(|part| part.parse::<u8>()
+ let ip: Vec<u8> = ip_string.trim().split('.').map(|part| part.parse::<u8>()
.unwrap_or(0)).collect();
let mut dns_string = String::new();
File::open("/etc/net/dns")?.read_to_string(&mut dns_string)?;
- let dns: Vec<u8> = dns_string.trim().split(".").map(|part| part.parse::<u8>()
+ let dns: Vec<u8> = dns_string.trim().split('.').map(|part| part.parse::<u8>()
.unwrap_or(0)).collect();
if ip.len() == 4 && dns.len() == 4 {
diff --git a/ctr-std/src/sys/redox/net/netc.rs b/ctr-std/src/sys/redox/net/netc.rs
index d443a4d..b6d9f45 100644
--- a/ctr-std/src/sys/redox/net/netc.rs
+++ b/ctr-std/src/sys/redox/net/netc.rs
@@ -24,10 +24,10 @@ pub struct in_addr {
}
#[derive(Copy, Clone)]
+#[repr(align(4))]
#[repr(C)]
pub struct in6_addr {
pub s6_addr: [u8; 16],
- __align: [u32; 0],
}
#[derive(Copy, Clone)]
diff --git a/ctr-std/src/sys/redox/net/udp.rs b/ctr-std/src/sys/redox/net/udp.rs
index 2ed67bd..22af020 100644
--- a/ctr-std/src/sys/redox/net/udp.rs
+++ b/ctr-std/src/sys/redox/net/udp.rs
@@ -58,7 +58,7 @@ impl UdpSocket {
pub fn recv(&self, buf: &mut [u8]) -> Result<usize> {
if let Some(addr) = *self.get_conn() {
- let from = self.0.dup(format!("{}", addr).as_bytes())?;
+ let from = self.0.dup(addr.to_string().as_bytes())?;
from.read(buf)
} else {
Err(Error::new(ErrorKind::Other, "UdpSocket::recv not connected"))
diff --git a/ctr-std/src/sys/redox/os.rs b/ctr-std/src/sys/redox/os.rs
index 480765b..5822216 100644
--- a/ctr-std/src/sys/redox/os.rs
+++ b/ctr-std/src/sys/redox/os.rs
@@ -30,9 +30,6 @@ use sys_common::mutex::Mutex;
use sys::{cvt, fd, syscall};
use vec;
-const TMPBUF_SZ: usize = 128;
-static ENV_LOCK: Mutex = Mutex::new();
-
extern {
#[link_name = "__errno_location"]
fn errno_location() -> *mut i32;
diff --git a/ctr-std/src/sys/redox/process.rs b/ctr-std/src/sys/redox/process.rs
index d0b94e1..2037616 100644
--- a/ctr-std/src/sys/redox/process.rs
+++ b/ctr-std/src/sys/redox/process.rs
@@ -13,6 +13,7 @@ use ffi::OsStr;
use os::unix::ffi::OsStrExt;
use fmt;
use io::{self, Error, ErrorKind};
+use iter;
use libc::{EXIT_SUCCESS, EXIT_FAILURE};
use path::{Path, PathBuf};
use sys::fd::FileDesc;
@@ -51,7 +52,7 @@ pub struct Command {
uid: Option<u32>,
gid: Option<u32>,
saw_nul: bool,
- closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
+ closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
stdin: Option<Stdio>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
@@ -122,7 +123,7 @@ impl Command {
}
pub fn before_exec(&mut self,
- f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
+ f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
self.closures.push(f);
}
@@ -296,11 +297,11 @@ impl Command {
t!(callback());
}
- let mut args: Vec<[usize; 2]> = Vec::new();
- args.push([self.program.as_ptr() as usize, self.program.len()]);
- for arg in self.args.iter() {
- args.push([arg.as_ptr() as usize, arg.len()]);
- }
+ let args: Vec<[usize; 2]> = iter::once(
+ [self.program.as_ptr() as usize, self.program.len()]
+ ).chain(
+ self.args.iter().map(|arg| [arg.as_ptr() as usize, arg.len()])
+ ).collect();
self.env.apply();
diff --git a/ctr-std/src/sys/redox/thread.rs b/ctr-std/src/sys/redox/thread.rs
index 110d46c..f417708 100644
--- a/ctr-std/src/sys/redox/thread.rs
+++ b/ctr-std/src/sys/redox/thread.rs
@@ -28,7 +28,7 @@ unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
impl Thread {
- pub unsafe fn new<'a>(_stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> {
+ pub unsafe fn new<'a>(_stack: usize, p: Box<dyn FnBox() + 'a>) -> io::Result<Thread> {
let p = box p;
let id = cvt(syscall::clone(syscall::CLONE_VM | syscall::CLONE_FS | syscall::CLONE_FILES))?;
diff --git a/ctr-std/src/sys/unix/args.rs b/ctr-std/src/sys/unix/args.rs
index e1c7ffc..c3c033d 100644
--- a/ctr-std/src/sys/unix/args.rs
+++ b/ctr-std/src/sys/unix/args.rs
@@ -66,7 +66,8 @@ impl DoubleEndedIterator for Args {
target_os = "emscripten",
target_os = "haiku",
target_os = "l4re",
- target_os = "fuchsia"))]
+ target_os = "fuchsia",
+ target_os = "hermit"))]
mod imp {
use os::unix::prelude::*;
use ptr;
@@ -79,20 +80,20 @@ mod imp {
static mut ARGC: isize = 0;
static mut ARGV: *const *const u8 = ptr::null();
+ // We never call `ENV_LOCK.init()`, so it is UB to attempt to
+ // acquire this mutex reentrantly!
static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
- LOCK.lock();
+ let _guard = LOCK.lock();
ARGC = argc;
ARGV = argv;
- LOCK.unlock();
}
pub unsafe fn cleanup() {
- LOCK.lock();
+ let _guard = LOCK.lock();
ARGC = 0;
ARGV = ptr::null();
- LOCK.unlock();
}
pub fn args() -> Args {
@@ -104,13 +105,11 @@ mod imp {
fn clone() -> Vec<OsString> {
unsafe {
- LOCK.lock();
- let ret = (0..ARGC).map(|i| {
+ let _guard = LOCK.lock();
+ (0..ARGC).map(|i| {
let cstr = CStr::from_ptr(*ARGV.offset(i) as *const libc::c_char);
OsStringExt::from_vec(cstr.to_bytes().to_vec())
- }).collect();
- LOCK.unlock();
- return ret
+ }).collect()
}
}
}
diff --git a/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs b/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs
index 1b92fc0..6e84156 100644
--- a/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs
+++ b/ctr-std/src/sys/unix/backtrace/tracing/gcc_s.rs
@@ -68,6 +68,10 @@ pub fn unwind_backtrace(frames: &mut [Frame])
extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
arg: *mut libc::c_void) -> uw::_Unwind_Reason_Code {
let cx = unsafe { &mut *(arg as *mut Context) };
+ if cx.idx >= cx.frames.len() {
+ return uw::_URC_NORMAL_STOP;
+ }
+
let mut ip_before_insn = 0;
let mut ip = unsafe {
uw::_Unwind_GetIPInfo(ctx, &mut ip_before_insn) as *mut libc::c_void
@@ -94,14 +98,12 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context,
unsafe { uw::_Unwind_FindEnclosingFunction(ip) }
};
- if cx.idx < cx.frames.len() {
- cx.frames[cx.idx] = Frame {
- symbol_addr: symaddr as *mut u8,
- exact_position: ip as *mut u8,
- inline_context: 0,
- };
- cx.idx += 1;
- }
+ cx.frames[cx.idx] = Frame {
+ symbol_addr: symaddr as *mut u8,
+ exact_position: ip as *mut u8,
+ inline_context: 0,
+ };
+ cx.idx += 1;
uw::_URC_NO_REASON
}
diff --git a/ctr-std/src/sys/unix/condvar.rs b/ctr-std/src/sys/unix/condvar.rs
index 4f878d8..2007da7 100644
--- a/ctr-std/src/sys/unix/condvar.rs
+++ b/ctr-std/src/sys/unix/condvar.rs
@@ -41,13 +41,15 @@ impl Condvar {
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "l4re",
- target_os = "android"))]
+ target_os = "android",
+ target_os = "hermit"))]
pub unsafe fn init(&mut self) {}
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "l4re",
- target_os = "android")))]
+ target_os = "android",
+ target_os = "hermit")))]
pub unsafe fn init(&mut self) {
use mem;
let mut attr: libc::pthread_condattr_t = mem::uninitialized();
@@ -83,7 +85,10 @@ impl Condvar {
// where we configure condition variable to use monotonic clock (instead of
// default system clock). This approach avoids all problems that result
// from changes made to the system time.
- #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))]
+ #[cfg(not(any(target_os = "macos",
+ target_os = "ios",
+ target_os = "android",
+ target_os = "hermit")))]
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
use mem;
@@ -113,7 +118,7 @@ impl Condvar {
// This implementation is modeled after libcxx's condition_variable
// https://github.com/llvm-mirror/libcxx/blob/release_35/src/condition_variable.cpp#L46
// https://github.com/llvm-mirror/libcxx/blob/release_35/include/__mutex_base#L367
- #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))]
+ #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android", target_os = "hermit"))]
pub unsafe fn wait_timeout(&self, mutex: &Mutex, mut dur: Duration) -> bool {
use ptr;
use time::Instant;
diff --git a/ctr-std/src/sys/unix/env.rs b/ctr-std/src/sys/unix/env.rs
index 00cf7ec..ad116c5 100644
--- a/ctr-std/src/sys/unix/env.rs
+++ b/ctr-std/src/sys/unix/env.rs
@@ -172,3 +172,14 @@ pub mod os {
pub const EXE_SUFFIX: &'static str = "";
pub const EXE_EXTENSION: &'static str = "";
}
+
+#[cfg(target_os = "hermit")]
+pub mod os {
+ pub const FAMILY: &'static str = "unix";
+ pub const OS: &'static str = "hermit";
+ pub const DLL_PREFIX: &'static str = "lib";
+ pub const DLL_SUFFIX: &'static str = ".so";
+ pub const DLL_EXTENSION: &'static str = "so";
+ pub const EXE_SUFFIX: &'static str = "";
+ pub const EXE_EXTENSION: &'static str = "";
+}
diff --git a/ctr-std/src/sys/unix/ext/fs.rs b/ctr-std/src/sys/unix/ext/fs.rs
index 4e98101..507e9d8 100644
--- a/ctr-std/src/sys/unix/ext/fs.rs
+++ b/ctr-std/src/sys/unix/ext/fs.rs
@@ -59,6 +59,78 @@ pub trait FileExt {
#[stable(feature = "file_offset", since = "1.15.0")]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
+ /// Reads the exact number of byte required to fill `buf` from the given offset.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`.
+ ///
+ /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact
+ /// [`read_at`]: #tymethod.read_at
+ ///
+ /// # Errors
+ ///
+ /// If this function encounters an error of the kind
+ /// [`ErrorKind::Interrupted`] then the error is ignored and the operation
+ /// will continue.
+ ///
+ /// If this function encounters an "end of file" before completely filling
+ /// the buffer, it returns an error of the kind [`ErrorKind::UnexpectedEof`].
+ /// The contents of `buf` are unspecified in this case.
+ ///
+ /// If any other read error is encountered then this function immediately
+ /// returns. The contents of `buf` are unspecified in this case.
+ ///
+ /// If this function returns an error, it is unspecified how many bytes it
+ /// has read, but it will never read more than would be necessary to
+ /// completely fill the buffer.
+ ///
+ /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(rw_exact_all_at)]
+ /// use std::io;
+ /// use std::fs::File;
+ /// use std::os::unix::prelude::FileExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let mut buf = [0u8; 8];
+ /// let file = File::open("foo.txt")?;
+ ///
+ /// // We now read exactly 8 bytes from the offset 10.
+ /// file.read_exact_at(&mut buf, 10)?;
+ /// println!("read {} bytes: {:?}", buf.len(), buf);
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "rw_exact_all_at", issue = "51984")]
+ fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.read_at(buf, offset) {
+ Ok(0) => break,
+ Ok(n) => {
+ let tmp = buf;
+ buf = &mut tmp[n..];
+ offset += n as u64;
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ if !buf.is_empty() {
+ Err(io::Error::new(io::ErrorKind::UnexpectedEof,
+ "failed to fill whole buffer"))
+ } else {
+ Ok(())
+ }
+ }
+
/// Writes a number of bytes starting from a given offset.
///
/// Returns the number of bytes written.
@@ -93,6 +165,61 @@ pub trait FileExt {
/// ```
#[stable(feature = "file_offset", since = "1.15.0")]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
+
+ /// Attempts to write an entire buffer starting from a given offset.
+ ///
+ /// The offset is relative to the start of the file and thus independent
+ /// from the current cursor.
+ ///
+ /// The current file cursor is not affected by this function.
+ ///
+ /// This method will continuously call [`write_at`] until there is no more data
+ /// to be written or an error of non-[`ErrorKind::Interrupted`] kind is
+ /// returned. This method will not return until the entire buffer has been
+ /// successfully written or such an error occurs. The first error that is
+ /// not of [`ErrorKind::Interrupted`] kind generated from this method will be
+ /// returned.
+ ///
+ /// # Errors
+ ///
+ /// This function will return the first error of
+ /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns.
+ ///
+ /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted
+ /// [`write_at`]: #tymethod.write_at
+ ///
+ /// # Examples
+ ///
+ /// ```no_run
+ /// #![feature(rw_exact_all_at)]
+ /// use std::fs::File;
+ /// use std::io;
+ /// use std::os::unix::prelude::FileExt;
+ ///
+ /// fn main() -> io::Result<()> {
+ /// let file = File::open("foo.txt")?;
+ ///
+ /// // We now write at the offset 10.
+ /// file.write_all_at(b"sushi", 10)?;
+ /// Ok(())
+ /// }
+ /// ```
+ #[unstable(feature = "rw_exact_all_at", issue = "51984")]
+ fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> {
+ while !buf.is_empty() {
+ match self.write_at(buf, offset) {
+ Ok(0) => return Err(io::Error::new(io::ErrorKind::WriteZero,
+ "failed to write whole buffer")),
+ Ok(n) => {
+ buf = &buf[n..];
+ offset += n as u64
+ }
+ Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {}
+ Err(e) => return Err(e),
+ }
+ }
+ Ok(())
+ }
}
#[stable(feature = "file_offset", since = "1.15.0")]
diff --git a/ctr-std/src/sys/unix/ext/mod.rs b/ctr-std/src/sys/unix/ext/mod.rs
index c221f7c..88e4237 100644
--- a/ctr-std/src/sys/unix/ext/mod.rs
+++ b/ctr-std/src/sys/unix/ext/mod.rs
@@ -35,6 +35,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))]
+#![allow(missing_docs)]
pub mod io;
pub mod ffi;
diff --git a/ctr-std/src/sys/unix/ext/net.rs b/ctr-std/src/sys/unix/ext/net.rs
index e277b1a..55f43cc 100644
--- a/ctr-std/src/sys/unix/ext/net.rs
+++ b/ctr-std/src/sys/unix/ext/net.rs
@@ -524,6 +524,9 @@ impl UnixStream {
/// println!("Got error: {:?}", err);
/// }
/// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns None.
#[stable(feature = "unix_socket", since = "1.10.0")]
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error()
@@ -846,6 +849,9 @@ impl UnixListener {
/// println!("Got error: {:?}", err);
/// }
/// ```
+ ///
+ /// # Platform specific
+ /// On Redox this always returns None.
#[stable(feature = "unix_socket", since = "1.10.0")]
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.0.take_error()
diff --git a/ctr-std/src/sys/unix/fast_thread_local.rs b/ctr-std/src/sys/unix/fast_thread_local.rs
index 6cdbe5d..c13a0fe 100644
--- a/ctr-std/src/sys/unix/fast_thread_local.rs
+++ b/ctr-std/src/sys/unix/fast_thread_local.rs
@@ -20,7 +20,7 @@
// fallback implementation to use as well.
//
// Due to rust-lang/rust#18804, make sure this is not generic!
-#[cfg(target_os = "linux")]
+#[cfg(any(target_os = "linux", target_os = "fuchsia", target_os = "hermit"))]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
use libc;
use mem;
@@ -55,11 +55,6 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
_tlv_atexit(dtor, t);
}
-// Just use the thread_local fallback implementation, at least until there's
-// a more direct implementation.
-#[cfg(target_os = "fuchsia")]
-pub use sys_common::thread_local::register_dtor_fallback as register_dtor;
-
pub fn requires_move_before_drop() -> bool {
// The macOS implementation of TLS apparently had an odd aspect to it
// where the pointer we have may be overwritten while this destructor
diff --git a/ctr-std/src/sys/unix/fs.rs b/ctr-std/src/sys/unix/fs.rs
index 7743403..7a89d98 100644
--- a/ctr-std/src/sys/unix/fs.rs
+++ b/ctr-std/src/sys/unix/fs.rs
@@ -25,10 +25,12 @@ use sys_common::{AsInner, FromInner};
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "l4re"))]
use libc::{stat64, fstat64, lstat64, off64_t, ftruncate64, lseek64, dirent64, readdir64_r, open64};
+#[cfg(any(target_os = "linux", target_os = "emscripten"))]
+use libc::fstatat64;
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
-use libc::{fstatat, dirfd};
+use libc::dirfd;
#[cfg(target_os = "android")]
-use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64,
+use libc::{stat as stat64, fstat as fstat64, fstatat as fstatat64, lstat as lstat64, lseek64,
dirent as dirent64, open as open64};
#[cfg(not(any(target_os = "linux",
target_os = "emscripten",
@@ -57,7 +59,10 @@ struct InnerReadDir {
}
#[derive(Clone)]
-pub struct ReadDir(Arc<InnerReadDir>);
+pub struct ReadDir {
+ inner: Arc<InnerReadDir>,
+ end_of_stream: bool,
+}
struct Dir(*mut libc::DIR);
@@ -213,7 +218,7 @@ impl fmt::Debug for ReadDir {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
// This will only be called from std::fs::ReadDir, which will add a "ReadDir()" frame.
// Thus the result will be e g 'ReadDir("/home")'
- fmt::Debug::fmt(&*self.0.root, f)
+ fmt::Debug::fmt(&*self.inner.root, f)
}
}
@@ -229,7 +234,7 @@ impl Iterator for ReadDir {
// is safe to use in threaded applications and it is generally preferred
// over the readdir_r(3C) function.
super::os::set_errno(0);
- let entry_ptr = libc::readdir(self.0.dirp.0);
+ let entry_ptr = libc::readdir(self.inner.dirp.0);
if entry_ptr.is_null() {
// NULL can mean either the end is reached or an error occurred.
// So we had to clear errno beforehand to check for an error now.
@@ -257,6 +262,10 @@ impl Iterator for ReadDir {
#[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ if self.end_of_stream {
+ return None;
+ }
+
unsafe {
let mut ret = DirEntry {
entry: mem::zeroed(),
@@ -264,7 +273,14 @@ impl Iterator for ReadDir {
};
let mut entry_ptr = ptr::null_mut();
loop {
- if readdir64_r(self.0.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
+ if readdir64_r(self.inner.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
+ if entry_ptr.is_null() {
+ // We encountered an error (which will be returned in this iteration), but
+ // we also reached the end of the directory stream. The `end_of_stream`
+ // flag is enabled to make sure that we return `None` in the next iteration
+ // (instead of looping forever)
+ self.end_of_stream = true;
+ }
return Some(Err(Error::last_os_error()))
}
if entry_ptr.is_null() {
@@ -287,7 +303,7 @@ impl Drop for Dir {
impl DirEntry {
pub fn path(&self) -> PathBuf {
- self.dir.0.root.join(OsStr::from_bytes(self.name_bytes()))
+ self.dir.inner.root.join(OsStr::from_bytes(self.name_bytes()))
}
pub fn file_name(&self) -> OsString {
@@ -296,13 +312,10 @@ impl DirEntry {
#[cfg(any(target_os = "linux", target_os = "emscripten", target_os = "android"))]
pub fn metadata(&self) -> io::Result<FileAttr> {
- let fd = cvt(unsafe {dirfd(self.dir.0.dirp.0)})?;
+ let fd = cvt(unsafe {dirfd(self.dir.inner.dirp.0)})?;
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
- fstatat(fd,
- self.entry.d_name.as_ptr(),
- &mut stat as *mut _ as *mut _,
- libc::AT_SYMLINK_NOFOLLOW)
+ fstatat64(fd, self.entry.d_name.as_ptr(), &mut stat, libc::AT_SYMLINK_NOFOLLOW)
})?;
Ok(FileAttr { stat: stat })
}
@@ -312,12 +325,12 @@ impl DirEntry {
lstat(&self.path())
}
- #[cfg(any(target_os = "solaris", target_os = "haiku"))]
+ #[cfg(any(target_os = "solaris", target_os = "haiku", target_os = "hermit"))]
pub fn file_type(&self) -> io::Result<FileType> {
lstat(&self.path()).map(|m| m.file_type())
}
- #[cfg(not(any(target_os = "solaris", target_os = "haiku")))]
+ #[cfg(not(any(target_os = "solaris", target_os = "haiku", target_os = "hermit")))]
pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type {
libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@@ -339,7 +352,8 @@ impl DirEntry {
target_os = "solaris",
target_os = "haiku",
target_os = "l4re",
- target_os = "fuchsia"))]
+ target_os = "fuchsia",
+ target_os = "hermit"))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
}
@@ -370,7 +384,8 @@ impl DirEntry {
target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
- target_os = "haiku"))]
+ target_os = "haiku",
+ target_os = "hermit"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
CStr::from_ptr(self.entry.d_name.as_ptr()).to_bytes()
@@ -692,7 +707,10 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
Err(Error::last_os_error())
} else {
let inner = InnerReadDir { dirp: Dir(ptr), root };
- Ok(ReadDir(Arc::new(inner)))
+ Ok(ReadDir{
+ inner: Arc::new(inner),
+ end_of_stream: false,
+ })
}
}
}
@@ -787,7 +805,7 @@ pub fn stat(p: &Path) -> io::Result<FileAttr> {
let p = cstr(p)?;
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
- stat64(p.as_ptr(), &mut stat as *mut _ as *mut _)
+ stat64(p.as_ptr(), &mut stat)
})?;
Ok(FileAttr { stat: stat })
}
@@ -796,7 +814,7 @@ pub fn lstat(p: &Path) -> io::Result<FileAttr> {
let p = cstr(p)?;
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
- lstat64(p.as_ptr(), &mut stat as *mut _ as *mut _)
+ lstat64(p.as_ptr(), &mut stat)
})?;
Ok(FileAttr { stat: stat })
}
diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs
index c1298e5..c738003 100644
--- a/ctr-std/src/sys/unix/mod.rs
+++ b/ctr-std/src/sys/unix/mod.rs
@@ -28,6 +28,7 @@ use libc;
#[cfg(all(not(dox), target_os = "emscripten"))] pub use os::emscripten as platform;
#[cfg(all(not(dox), target_os = "fuchsia"))] pub use os::fuchsia as platform;
#[cfg(all(not(dox), target_os = "l4re"))] pub use os::linux as platform;
+#[cfg(all(not(dox), target_os = "hermit"))] pub use os::hermit as platform;
pub use self::rand::hashmap_random_keys;
pub use libc::strlen;
diff --git a/ctr-std/src/sys/unix/mutex.rs b/ctr-std/src/sys/unix/mutex.rs
index 52cf3f9..1d447de 100644
--- a/ctr-std/src/sys/unix/mutex.rs
+++ b/ctr-std/src/sys/unix/mutex.rs
@@ -25,8 +25,10 @@ unsafe impl Sync for Mutex {}
#[allow(dead_code)] // sys isn't exported yet
impl Mutex {
pub const fn new() -> Mutex {
- // Might be moved and address is changing it is better to avoid
- // initialization of potentially opaque OS data before it landed
+ // Might be moved to a different address, so it is better to avoid
+ // initialization of potentially opaque OS data before it landed.
+ // Be very careful using this newly constructed `Mutex`, reentrant
+ // locking is undefined behavior until `init` is called!
Mutex { inner: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER) }
}
#[inline]
@@ -49,9 +51,6 @@ impl Mutex {
// references, we instead create the mutex with type
// PTHREAD_MUTEX_NORMAL which is guaranteed to deadlock if we try to
// re-lock it from the same thread, thus avoiding undefined behavior.
- //
- // We can't do anything for StaticMutex, but that type is deprecated
- // anyways.
let mut attr: libc::pthread_mutexattr_t = mem::uninitialized();
let r = libc::pthread_mutexattr_init(&mut attr);
debug_assert_eq!(r, 0);
diff --git a/ctr-std/src/sys/unix/os.rs b/ctr-std/src/sys/unix/os.rs
index 4c86fdd..f8f0bbd 100644
--- a/ctr-std/src/sys/unix/os.rs
+++ b/ctr-std/src/sys/unix/os.rs
@@ -33,6 +33,8 @@ use sys::fd;
use vec;
const TMPBUF_SZ: usize = 128;
+// We never call `ENV_LOCK.init()`, so it is UB to attempt to
+// acquire this mutex reentrantly!
static ENV_LOCK: Mutex = Mutex::new();
@@ -47,6 +49,7 @@ extern {
target_os = "netbsd",
target_os = "openbsd",
target_os = "android",
+ target_os = "hermit",
target_env = "newlib"),
link_name = "__errno")]
#[cfg_attr(target_os = "solaris", link_name = "___errno")]
@@ -376,7 +379,7 @@ pub fn current_exe() -> io::Result<PathBuf> {
}
}
-#[cfg(any(target_os = "fuchsia", target_os = "l4re"))]
+#[cfg(any(target_os = "fuchsia", target_os = "l4re", target_os = "hermit"))]
pub fn current_exe() -> io::Result<PathBuf> {
use io::ErrorKind;
Err(io::Error::new(ErrorKind::Other, "Not yet implemented!"))
@@ -409,26 +412,19 @@ pub unsafe fn environ() -> *mut *const *const c_char {
/// environment variables of the current process.
pub fn env() -> Env {
unsafe {
- ENV_LOCK.lock();
+ let _guard = ENV_LOCK.lock();
let mut environ = *environ();
- if environ == ptr::null() {
- ENV_LOCK.unlock();
- panic!("os::env() failure getting env string from OS: {}",
- io::Error::last_os_error());
- }
let mut result = Vec::new();
- while *environ != ptr::null() {
+ while environ != ptr::null() && *environ != ptr::null() {
if let Some(key_value) = parse(CStr::from_ptr(*environ).to_bytes()) {
result.push(key_value);
}
environ = environ.offset(1);
}
- let ret = Env {
+ return Env {
iter: result.into_iter(),
_dont_send_or_sync_me: PhantomData,
- };
- ENV_LOCK.unlock();
- return ret
+ }
}
fn parse(input: &[u8]) -> Option<(OsString, OsString)> {
@@ -452,15 +448,14 @@ pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> {
// always None as well
let k = CString::new(k.as_bytes())?;
unsafe {
- ENV_LOCK.lock();
+ let _guard = ENV_LOCK.lock();
let s = libc::getenv(k.as_ptr()) as *const libc::c_char;
let ret = if s.is_null() {
None
} else {
Some(OsStringExt::from_vec(CStr::from_ptr(s).to_bytes().to_vec()))
};
- ENV_LOCK.unlock();
- return Ok(ret)
+ Ok(ret)
}
}
@@ -469,10 +464,8 @@ pub fn setenv(k: &OsStr, v: &OsStr) -> io::Result<()> {
let v = CString::new(v.as_bytes())?;
unsafe {
- ENV_LOCK.lock();
- let ret = cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ());
- ENV_LOCK.unlock();
- return ret
+ let _guard = ENV_LOCK.lock();
+ cvt(libc::setenv(k.as_ptr(), v.as_ptr(), 1)).map(|_| ())
}
}
@@ -480,10 +473,8 @@ pub fn unsetenv(n: &OsStr) -> io::Result<()> {
let nbuf = CString::new(n.as_bytes())?;
unsafe {
- ENV_LOCK.lock();
- let ret = cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ());
- ENV_LOCK.unlock();
- return ret
+ let _guard = ENV_LOCK.lock();
+ cvt(libc::unsetenv(nbuf.as_ptr())).map(|_| ())
}
}
@@ -572,7 +563,7 @@ fn glibc_version_cstr() -> Option<&'static CStr> {
// ignoring any extra dot-separated parts. Otherwise return None.
#[cfg(target_env = "gnu")]
fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
- let mut parsed_ints = version.split(".").map(str::parse::<usize>).fuse();
+ let mut parsed_ints = version.split('.').map(str::parse::<usize>).fuse();
match (parsed_ints.next(), parsed_ints.next()) {
(Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)),
_ => None
diff --git a/ctr-std/src/sys/unix/process/process_common.rs b/ctr-std/src/sys/unix/process/process_common.rs
index 6396bb3..77f125f 100644
--- a/ctr-std/src/sys/unix/process/process_common.rs
+++ b/ctr-std/src/sys/unix/process/process_common.rs
@@ -52,7 +52,7 @@ pub struct Command {
uid: Option<uid_t>,
gid: Option<gid_t>,
saw_nul: bool,
- closures: Vec<Box<FnMut() -> io::Result<()> + Send + Sync>>,
+ closures: Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>>,
stdin: Option<Stdio>,
stdout: Option<Stdio>,
stderr: Option<Stdio>,
@@ -155,12 +155,12 @@ impl Command {
self.gid
}
- pub fn get_closures(&mut self) -> &mut Vec<Box<FnMut() -> io::Result<()> + Send + Sync>> {
+ pub fn get_closures(&mut self) -> &mut Vec<Box<dyn FnMut() -> io::Result<()> + Send + Sync>> {
&mut self.closures
}
pub fn before_exec(&mut self,
- f: Box<FnMut() -> io::Result<()> + Send + Sync>) {
+ f: Box<dyn FnMut() -> io::Result<()> + Send + Sync>) {
self.closures.push(f);
}
diff --git a/ctr-std/src/sys/unix/rand.rs b/ctr-std/src/sys/unix/rand.rs
index caa1894..01c0ada 100644
--- a/ctr-std/src/sys/unix/rand.rs
+++ b/ctr-std/src/sys/unix/rand.rs
@@ -183,35 +183,10 @@ mod imp {
mod imp {
#[link(name = "zircon")]
extern {
- fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32;
- }
-
- fn getrandom(buf: &mut [u8]) -> Result<usize, i32> {
- unsafe {
- let mut actual = 0;
- let status = zx_cprng_draw(buf.as_mut_ptr(), buf.len(), &mut actual);
- if status == 0 {
- Ok(actual)
- } else {
- Err(status)
- }
- }
+ fn zx_cprng_draw(buffer: *mut u8, len: usize);
}
pub fn fill_bytes(v: &mut [u8]) {
- let mut buf = v;
- while !buf.is_empty() {
- let ret = getrandom(buf);
- match ret {
- Err(err) => {
- panic!("kernel zx_cprng_draw call failed! (returned {}, buf.len() {})",
- err, buf.len())
- }
- Ok(actual) => {
- let move_buf = buf;
- buf = &mut move_buf[(actual as usize)..];
- }
- }
- }
+ unsafe { zx_cprng_draw(v.as_mut_ptr(), v.len()) }
}
}
diff --git a/ctr-std/src/sys/unix/thread.rs b/ctr-std/src/sys/unix/thread.rs
index 7fdecc9..f3a45d2 100644
--- a/ctr-std/src/sys/unix/thread.rs
+++ b/ctr-std/src/sys/unix/thread.rs
@@ -49,7 +49,7 @@ unsafe fn pthread_attr_setstacksize(_attr: *mut libc::pthread_attr_t,
}
impl Thread {
- pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
+ pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>)
-> io::Result<Thread> {
let p = box p;
let mut native: libc::pthread_t = mem::zeroed();
@@ -138,7 +138,8 @@ impl Thread {
target_os = "solaris",
target_os = "haiku",
target_os = "l4re",
- target_os = "emscripten"))]
+ target_os = "emscripten",
+ target_os = "hermit"))]
pub fn set_name(_name: &CStr) {
// Newlib, Illumos, Haiku, and Emscripten have no way to set a thread name.
}
diff --git a/ctr-std/src/sys/unix/time.rs b/ctr-std/src/sys/unix/time.rs
index 89786eb..0b1fb72 100644
--- a/ctr-std/src/sys/unix/time.rs
+++ b/ctr-std/src/sys/unix/time.rs
@@ -345,9 +345,9 @@ mod inner {
}
}
- #[cfg(not(target_os = "dragonfly"))]
+ #[cfg(not(any(target_os = "dragonfly", target_os = "hermit")))]
pub type clock_t = libc::c_int;
- #[cfg(target_os = "dragonfly")]
+ #[cfg(any(target_os = "dragonfly", target_os = "hermit"))]
pub type clock_t = libc::c_ulong;
fn now(clock: clock_t) -> Timespec {
diff --git a/ctr-std/src/sys/wasm/os.rs b/ctr-std/src/sys/wasm/os.rs
index 23ca175..0cb991e 100644
--- a/ctr-std/src/sys/wasm/os.rs
+++ b/ctr-std/src/sys/wasm/os.rs
@@ -21,7 +21,7 @@ pub fn errno() -> i32 {
}
pub fn error_string(_errno: i32) -> String {
- format!("operation successful")
+ "operation successful".to_string()
}
pub fn getcwd() -> io::Result<PathBuf> {
diff --git a/ctr-std/src/sys/wasm/thread.rs b/ctr-std/src/sys/wasm/thread.rs
index 728e678..8173a62 100644
--- a/ctr-std/src/sys/wasm/thread.rs
+++ b/ctr-std/src/sys/wasm/thread.rs
@@ -19,7 +19,7 @@ pub struct Thread(Void);
pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
impl Thread {
- pub unsafe fn new<'a>(_stack: usize, _p: Box<FnBox() + 'a>)
+ pub unsafe fn new<'a>(_stack: usize, _p: Box<dyn FnBox() + 'a>)
-> io::Result<Thread>
{
unsupported()
diff --git a/ctr-std/src/sys/windows/backtrace/mod.rs b/ctr-std/src/sys/windows/backtrace/mod.rs
index 82498ad..f64cae8 100644
--- a/ctr-std/src/sys/windows/backtrace/mod.rs
+++ b/ctr-std/src/sys/windows/backtrace/mod.rs
@@ -46,110 +46,281 @@ mod printing;
#[path = "backtrace_gnu.rs"]
pub mod gnu;
-pub use self::printing::{resolve_symname, foreach_symbol_fileline};
+pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+use self::printing::{load_printing_fns_64, load_printing_fns_ex};
-pub fn unwind_backtrace(frames: &mut [Frame])
- -> io::Result<(usize, BacktraceContext)>
-{
+pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
let dbghelp = DynamicLibrary::open("dbghelp.dll")?;
// Fetch the symbols necessary from dbghelp.dll
let SymInitialize = sym!(dbghelp, "SymInitialize", SymInitializeFn)?;
let SymCleanup = sym!(dbghelp, "SymCleanup", SymCleanupFn)?;
- let StackWalkEx = sym!(dbghelp, "StackWalkEx", StackWalkExFn)?;
+
+ // StackWalkEx might not be present and we'll fall back to StackWalk64
+ let sw_var = match sym!(dbghelp, "StackWalkEx", StackWalkExFn) {
+ Ok(StackWalkEx) => {
+ StackWalkVariant::StackWalkEx(StackWalkEx, load_printing_fns_ex(&dbghelp)?)
+ }
+ Err(e) => match sym!(dbghelp, "StackWalk64", StackWalk64Fn) {
+ Ok(StackWalk64) => {
+ StackWalkVariant::StackWalk64(StackWalk64, load_printing_fns_64(&dbghelp)?)
+ }
+ Err(..) => return Err(e),
+ },
+ };
// Allocate necessary structures for doing the stack walk
let process = unsafe { c::GetCurrentProcess() };
- let thread = unsafe { c::GetCurrentThread() };
- let mut context: c::CONTEXT = unsafe { mem::zeroed() };
- unsafe { c::RtlCaptureContext(&mut context) };
- let mut frame: c::STACKFRAME_EX = unsafe { mem::zeroed() };
- frame.StackFrameSize = mem::size_of_val(&frame) as c::DWORD;
- let image = init_frame(&mut frame, &context);
let backtrace_context = BacktraceContext {
handle: process,
SymCleanup,
+ StackWalkVariant: sw_var,
dbghelp,
};
// Initialize this process's symbols
let ret = unsafe { SymInitialize(process, ptr::null_mut(), c::TRUE) };
if ret != c::TRUE {
- return Ok((0, backtrace_context))
+ return Ok((0, backtrace_context));
}
// And now that we're done with all the setup, do the stack walking!
+ match backtrace_context.StackWalkVariant {
+ StackWalkVariant::StackWalkEx(StackWalkEx, _) => {
+ set_frames(StackWalkEx, frames).map(|i| (i, backtrace_context))
+ }
+
+ StackWalkVariant::StackWalk64(StackWalk64, _) => {
+ set_frames(StackWalk64, frames).map(|i| (i, backtrace_context))
+ }
+ }
+}
+
+fn set_frames<W: StackWalker>(StackWalk: W, frames: &mut [Frame]) -> io::Result<usize> {
+ let process = unsafe { c::GetCurrentProcess() };
+ let thread = unsafe { c::GetCurrentProcess() };
+ let mut context: c::CONTEXT = unsafe { mem::zeroed() };
+ unsafe { c::RtlCaptureContext(&mut context) };
+ let mut frame = W::Item::new();
+ let image = frame.init(&context);
+
let mut i = 0;
- unsafe {
- while i < frames.len() &&
- StackWalkEx(image, process, thread, &mut frame, &mut context,
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- ptr::null_mut(),
- 0) == c::TRUE
- {
- let addr = (frame.AddrPC.Offset - 1) as *const u8;
-
- frames[i] = Frame {
- symbol_addr: addr,
- exact_position: addr,
- inline_context: frame.InlineFrameContext,
- };
- i += 1;
+ while i < frames.len()
+ && StackWalk.walk(image, process, thread, &mut frame, &mut context) == c::TRUE
+ {
+ let addr = frame.get_addr();
+ frames[i] = Frame {
+ symbol_addr: addr,
+ exact_position: addr,
+ inline_context: 0,
+ };
+
+ i += 1
+ }
+ Ok(i)
+}
+
+type SymInitializeFn = unsafe extern "system" fn(c::HANDLE, *mut c_void, c::BOOL) -> c::BOOL;
+type SymCleanupFn = unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
+
+type StackWalkExFn = unsafe extern "system" fn(
+ c::DWORD,
+ c::HANDLE,
+ c::HANDLE,
+ *mut c::STACKFRAME_EX,
+ *mut c::CONTEXT,
+ *mut c_void,
+ *mut c_void,
+ *mut c_void,
+ *mut c_void,
+ c::DWORD,
+) -> c::BOOL;
+
+type StackWalk64Fn = unsafe extern "system" fn(
+ c::DWORD,
+ c::HANDLE,
+ c::HANDLE,
+ *mut c::STACKFRAME64,
+ *mut c::CONTEXT,
+ *mut c_void,
+ *mut c_void,
+ *mut c_void,
+ *mut c_void,
+) -> c::BOOL;
+
+trait StackWalker {
+ type Item: StackFrame;
+
+ fn walk(&self, c::DWORD, c::HANDLE, c::HANDLE, &mut Self::Item, &mut c::CONTEXT) -> c::BOOL;
+}
+
+impl StackWalker for StackWalkExFn {
+ type Item = c::STACKFRAME_EX;
+ fn walk(
+ &self,
+ image: c::DWORD,
+ process: c::HANDLE,
+ thread: c::HANDLE,
+ frame: &mut Self::Item,
+ context: &mut c::CONTEXT,
+ ) -> c::BOOL {
+ unsafe {
+ self(
+ image,
+ process,
+ thread,
+ frame,
+ context,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ 0,
+ )
+ }
+ }
+}
+
+impl StackWalker for StackWalk64Fn {
+ type Item = c::STACKFRAME64;
+ fn walk(
+ &self,
+ image: c::DWORD,
+ process: c::HANDLE,
+ thread: c::HANDLE,
+ frame: &mut Self::Item,
+ context: &mut c::CONTEXT,
+ ) -> c::BOOL {
+ unsafe {
+ self(
+ image,
+ process,
+ thread,
+ frame,
+ context,
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ ptr::null_mut(),
+ )
}
}
+}
+
+trait StackFrame {
+ fn new() -> Self;
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD;
+ fn get_addr(&self) -> *const u8;
+}
+
+impl StackFrame for c::STACKFRAME_EX {
+ fn new() -> c::STACKFRAME_EX {
+ unsafe { mem::zeroed() }
+ }
+
+ #[cfg(target_arch = "x86")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Eip as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Esp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Ebp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_I386
+ }
+
+ #[cfg(target_arch = "x86_64")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Rip as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Rsp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Rbp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_AMD64
+ }
+
+ #[cfg(target_arch = "aarch64")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Pc as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Sp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Fp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_ARM64
+ }
- Ok((i, backtrace_context))
+ fn get_addr(&self) -> *const u8 {
+ (self.AddrPC.Offset - 1) as *const u8
+ }
}
-type SymInitializeFn =
- unsafe extern "system" fn(c::HANDLE, *mut c_void,
- c::BOOL) -> c::BOOL;
-type SymCleanupFn =
- unsafe extern "system" fn(c::HANDLE) -> c::BOOL;
-
-type StackWalkExFn =
- unsafe extern "system" fn(c::DWORD, c::HANDLE, c::HANDLE,
- *mut c::STACKFRAME_EX, *mut c::CONTEXT,
- *mut c_void, *mut c_void,
- *mut c_void, *mut c_void, c::DWORD) -> c::BOOL;
-
-#[cfg(target_arch = "x86")]
-fn init_frame(frame: &mut c::STACKFRAME_EX,
- ctx: &c::CONTEXT) -> c::DWORD {
- frame.AddrPC.Offset = ctx.Eip as u64;
- frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
- frame.AddrStack.Offset = ctx.Esp as u64;
- frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
- frame.AddrFrame.Offset = ctx.Ebp as u64;
- frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
- c::IMAGE_FILE_MACHINE_I386
+impl StackFrame for c::STACKFRAME64 {
+ fn new() -> c::STACKFRAME64 {
+ unsafe { mem::zeroed() }
+ }
+
+ #[cfg(target_arch = "x86")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Eip as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Esp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Ebp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_I386
+ }
+
+ #[cfg(target_arch = "x86_64")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Rip as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Rsp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Rbp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_AMD64
+ }
+
+ #[cfg(target_arch = "aarch64")]
+ fn init(&mut self, ctx: &c::CONTEXT) -> c::DWORD {
+ self.AddrPC.Offset = ctx.Pc as u64;
+ self.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrStack.Offset = ctx.Sp as u64;
+ self.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ self.AddrFrame.Offset = ctx.Fp as u64;
+ self.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
+ c::IMAGE_FILE_MACHINE_ARM64
+ }
+
+ fn get_addr(&self) -> *const u8 {
+ (self.AddrPC.Offset - 1) as *const u8
+ }
}
-#[cfg(target_arch = "x86_64")]
-fn init_frame(frame: &mut c::STACKFRAME_EX,
- ctx: &c::CONTEXT) -> c::DWORD {
- frame.AddrPC.Offset = ctx.Rip as u64;
- frame.AddrPC.Mode = c::ADDRESS_MODE::AddrModeFlat;
- frame.AddrStack.Offset = ctx.Rsp as u64;
- frame.AddrStack.Mode = c::ADDRESS_MODE::AddrModeFlat;
- frame.AddrFrame.Offset = ctx.Rbp as u64;
- frame.AddrFrame.Mode = c::ADDRESS_MODE::AddrModeFlat;
- c::IMAGE_FILE_MACHINE_AMD64
+enum StackWalkVariant {
+ StackWalkEx(StackWalkExFn, printing::PrintingFnsEx),
+ StackWalk64(StackWalk64Fn, printing::PrintingFns64),
}
pub struct BacktraceContext {
handle: c::HANDLE,
SymCleanup: SymCleanupFn,
// Only used in printing for msvc and not gnu
+ // The gnu version is effectively a ZST dummy.
+ #[allow(dead_code)]
+ StackWalkVariant: StackWalkVariant,
+ // keeping DynamycLibrary loaded until its functions no longer needed
#[allow(dead_code)]
dbghelp: DynamicLibrary,
}
impl Drop for BacktraceContext {
fn drop(&mut self) {
- unsafe { (self.SymCleanup)(self.handle); }
+ unsafe {
+ (self.SymCleanup)(self.handle);
+ }
}
}
diff --git a/ctr-std/src/sys/windows/backtrace/printing/mod.rs b/ctr-std/src/sys/windows/backtrace/printing/mod.rs
index 3e566f6..251d502 100644
--- a/ctr-std/src/sys/windows/backtrace/printing/mod.rs
+++ b/ctr-std/src/sys/windows/backtrace/printing/mod.rs
@@ -15,6 +15,20 @@ mod printing;
#[cfg(target_env = "gnu")]
mod printing {
pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};
+
+ // dummy functions to mirror those present in msvc version.
+ use sys::dynamic_lib::DynamicLibrary;
+ use io;
+ pub struct PrintingFnsEx {}
+ pub struct PrintingFns64 {}
+ pub fn load_printing_fns_ex(_: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
+ Ok(PrintingFnsEx{})
+ }
+ pub fn load_printing_fns_64(_: &DynamicLibrary) -> io::Result<PrintingFns64> {
+ Ok(PrintingFns64{})
+ }
}
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
+pub use self::printing::{load_printing_fns_ex, load_printing_fns_64,
+ PrintingFnsEx, PrintingFns64};
diff --git a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs b/ctr-std/src/sys/windows/backtrace/printing/msvc.rs
index 967df1c..c8b946b 100644
--- a/ctr-std/src/sys/windows/backtrace/printing/msvc.rs
+++ b/ctr-std/src/sys/windows/backtrace/printing/msvc.rs
@@ -10,29 +10,108 @@
use ffi::CStr;
use io;
-use libc::{c_ulong, c_char};
+use libc::{c_char, c_ulong};
use mem;
-use sys::c;
use sys::backtrace::BacktraceContext;
+use sys::backtrace::StackWalkVariant;
+use sys::c;
+use sys::dynamic_lib::DynamicLibrary;
use sys_common::backtrace::Frame;
+// Structs holding printing functions and loaders for them
+// Two versions depending on whether dbghelp.dll has StackWalkEx or not
+// (the former being in newer Windows versions, the older being in Win7 and before)
+pub struct PrintingFnsEx {
+ resolve_symname: SymFromInlineContextFn,
+ sym_get_line: SymGetLineFromInlineContextFn,
+}
+pub struct PrintingFns64 {
+ resolve_symname: SymFromAddrFn,
+ sym_get_line: SymGetLineFromAddr64Fn,
+}
+
+pub fn load_printing_fns_ex(dbghelp: &DynamicLibrary) -> io::Result<PrintingFnsEx> {
+ Ok(PrintingFnsEx {
+ resolve_symname: sym!(dbghelp, "SymFromInlineContext", SymFromInlineContextFn)?,
+ sym_get_line: sym!(
+ dbghelp,
+ "SymGetLineFromInlineContext",
+ SymGetLineFromInlineContextFn
+ )?,
+ })
+}
+pub fn load_printing_fns_64(dbghelp: &DynamicLibrary) -> io::Result<PrintingFns64> {
+ Ok(PrintingFns64 {
+ resolve_symname: sym!(dbghelp, "SymFromAddr", SymFromAddrFn)?,
+ sym_get_line: sym!(dbghelp, "SymGetLineFromAddr64", SymGetLineFromAddr64Fn)?,
+ })
+}
+
+type SymFromAddrFn =
+ unsafe extern "system" fn(c::HANDLE, u64, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
type SymFromInlineContextFn =
- unsafe extern "system" fn(c::HANDLE, u64, c::ULONG,
- *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
-type SymGetLineFromInlineContextFn =
- unsafe extern "system" fn(c::HANDLE, u64, c::ULONG,
- u64, *mut c::DWORD, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+ unsafe extern "system" fn(c::HANDLE, u64, c::ULONG, *mut u64, *mut c::SYMBOL_INFO) -> c::BOOL;
+
+type SymGetLineFromAddr64Fn =
+ unsafe extern "system" fn(c::HANDLE, u64, *mut u32, *mut c::IMAGEHLP_LINE64) -> c::BOOL;
+type SymGetLineFromInlineContextFn = unsafe extern "system" fn(
+ c::HANDLE,
+ u64,
+ c::ULONG,
+ u64,
+ *mut c::DWORD,
+ *mut c::IMAGEHLP_LINE64,
+) -> c::BOOL;
/// Converts a pointer to symbol to its string value.
-pub fn resolve_symname<F>(frame: Frame,
- callback: F,
- context: &BacktraceContext) -> io::Result<()>
- where F: FnOnce(Option<&str>) -> io::Result<()>
+pub fn resolve_symname<F>(frame: Frame, callback: F, context: &BacktraceContext) -> io::Result<()>
+where
+ F: FnOnce(Option<&str>) -> io::Result<()>,
{
- let SymFromInlineContext = sym!(&context.dbghelp,
- "SymFromInlineContext",
- SymFromInlineContextFn)?;
+ match context.StackWalkVariant {
+ StackWalkVariant::StackWalkEx(_, ref fns) => resolve_symname_internal(
+ |process: c::HANDLE,
+ symbol_address: u64,
+ inline_context: c::ULONG,
+ info: *mut c::SYMBOL_INFO| unsafe {
+ let mut displacement = 0u64;
+ (fns.resolve_symname)(
+ process,
+ symbol_address,
+ inline_context,
+ &mut displacement,
+ info,
+ )
+ },
+ frame,
+ callback,
+ context,
+ ),
+ StackWalkVariant::StackWalk64(_, ref fns) => resolve_symname_internal(
+ |process: c::HANDLE,
+ symbol_address: u64,
+ _inline_context: c::ULONG,
+ info: *mut c::SYMBOL_INFO| unsafe {
+ let mut displacement = 0u64;
+ (fns.resolve_symname)(process, symbol_address, &mut displacement, info)
+ },
+ frame,
+ callback,
+ context,
+ ),
+ }
+}
+fn resolve_symname_internal<F, R>(
+ mut symbol_resolver: R,
+ frame: Frame,
+ callback: F,
+ context: &BacktraceContext,
+) -> io::Result<()>
+where
+ F: FnOnce(Option<&str>) -> io::Result<()>,
+ R: FnMut(c::HANDLE, u64, c::ULONG, *mut c::SYMBOL_INFO) -> c::BOOL,
+{
unsafe {
let mut info: c::SYMBOL_INFO = mem::zeroed();
info.MaxNameLen = c::MAX_SYM_NAME as c_ulong;
@@ -41,14 +120,13 @@ pub fn resolve_symname<F>(frame: Frame,
// due to struct alignment.
info.SizeOfStruct = 88;
- let mut displacement = 0u64;
- let ret = SymFromInlineContext(context.handle,
- frame.symbol_addr as u64,
- frame.inline_context,
- &mut displacement,
- &mut info);
- let valid_range = if ret == c::TRUE &&
- frame.symbol_addr as usize >= info.Address as usize {
+ let ret = symbol_resolver(
+ context.handle,
+ frame.symbol_addr as u64,
+ frame.inline_context,
+ &mut info,
+ );
+ let valid_range = if ret == c::TRUE && frame.symbol_addr as usize >= info.Address as usize {
if info.Size != 0 {
(frame.symbol_addr as usize) < info.Address as usize + info.Size as usize
} else {
@@ -67,30 +145,72 @@ pub fn resolve_symname<F>(frame: Frame,
}
}
-pub fn foreach_symbol_fileline<F>(frame: Frame,
- mut f: F,
- context: &BacktraceContext)
- -> io::Result<bool>
- where F: FnMut(&[u8], u32) -> io::Result<()>
+pub fn foreach_symbol_fileline<F>(
+ frame: Frame,
+ callback: F,
+ context: &BacktraceContext,
+) -> io::Result<bool>
+where
+ F: FnMut(&[u8], u32) -> io::Result<()>,
{
- let SymGetLineFromInlineContext = sym!(&context.dbghelp,
- "SymGetLineFromInlineContext",
- SymGetLineFromInlineContextFn)?;
+ match context.StackWalkVariant {
+ StackWalkVariant::StackWalkEx(_, ref fns) => foreach_symbol_fileline_iternal(
+ |process: c::HANDLE,
+ frame_address: u64,
+ inline_context: c::ULONG,
+ line: *mut c::IMAGEHLP_LINE64| unsafe {
+ let mut displacement = 0u32;
+ (fns.sym_get_line)(
+ process,
+ frame_address,
+ inline_context,
+ 0,
+ &mut displacement,
+ line,
+ )
+ },
+ frame,
+ callback,
+ context,
+ ),
+ StackWalkVariant::StackWalk64(_, ref fns) => foreach_symbol_fileline_iternal(
+ |process: c::HANDLE,
+ frame_address: u64,
+ _inline_context: c::ULONG,
+ line: *mut c::IMAGEHLP_LINE64| unsafe {
+ let mut displacement = 0u32;
+ (fns.sym_get_line)(process, frame_address, &mut displacement, line)
+ },
+ frame,
+ callback,
+ context,
+ ),
+ }
+}
+fn foreach_symbol_fileline_iternal<F, G>(
+ mut line_getter: G,
+ frame: Frame,
+ mut callback: F,
+ context: &BacktraceContext,
+) -> io::Result<bool>
+where
+ F: FnMut(&[u8], u32) -> io::Result<()>,
+ G: FnMut(c::HANDLE, u64, c::ULONG, *mut c::IMAGEHLP_LINE64) -> c::BOOL,
+{
unsafe {
let mut line: c::IMAGEHLP_LINE64 = mem::zeroed();
line.SizeOfStruct = ::mem::size_of::<c::IMAGEHLP_LINE64>() as u32;
- let mut displacement = 0u32;
- let ret = SymGetLineFromInlineContext(context.handle,
- frame.exact_position as u64,
- frame.inline_context,
- 0,
- &mut displacement,
- &mut line);
+ let ret = line_getter(
+ context.handle,
+ frame.exact_position as u64,
+ frame.inline_context,
+ &mut line,
+ );
if ret == c::TRUE {
let name = CStr::from_ptr(line.Filename).to_bytes();
- f(name, line.LineNumber as u32)?;
+ callback(name, line.LineNumber as u32)?;
}
Ok(false)
}
diff --git a/ctr-std/src/sys/windows/c.rs b/ctr-std/src/sys/windows/c.rs
index 6d929f2..e514a56 100644
--- a/ctr-std/src/sys/windows/c.rs
+++ b/ctr-std/src/sys/windows/c.rs
@@ -280,6 +280,9 @@ pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c;
#[cfg(target_arch = "x86_64")]
#[cfg(feature = "backtrace")]
pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664;
+#[cfg(target_arch = "aarch64")]
+#[cfg(feature = "backtrace")]
+pub const IMAGE_FILE_MACHINE_ARM64: DWORD = 0xAA64;
pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0;
pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd;
@@ -296,6 +299,8 @@ pub const PIPE_READMODE_BYTE: DWORD = 0x00000000;
pub const FD_SETSIZE: usize = 64;
+pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000;
+
#[repr(C)]
#[cfg(not(target_pointer_width = "64"))]
pub struct WSADATA {
@@ -637,6 +642,22 @@ pub struct STACKFRAME_EX {
#[repr(C)]
#[cfg(feature = "backtrace")]
+pub struct STACKFRAME64 {
+ pub AddrPC: ADDRESS64,
+ pub AddrReturn: ADDRESS64,
+ pub AddrFrame: ADDRESS64,
+ pub AddrStack: ADDRESS64,
+ pub AddrBStore: ADDRESS64,
+ pub FuncTableEntry: *mut c_void,
+ pub Params: [u64; 4],
+ pub Far: BOOL,
+ pub Virtual: BOOL,
+ pub Reserved: [u64; 3],
+ pub KdHelp: KDHELP64,
+}
+
+#[repr(C)]
+#[cfg(feature = "backtrace")]
pub struct KDHELP64 {
pub Thread: u64,
pub ThCallbackStack: DWORD,
@@ -773,9 +794,68 @@ pub struct FLOATING_SAVE_AREA {
// will not appear in the final documentation. This should be also defined for
// other architectures supported by Windows such as ARM, and for historical
// interest, maybe MIPS and PowerPC as well.
-#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86"))))]
+#[cfg(all(dox, not(any(target_arch = "x86_64", target_arch = "x86", target_arch = "aarch64"))))]
pub enum CONTEXT {}
+#[cfg(target_arch = "aarch64")]
+pub const ARM64_MAX_BREAKPOINTS: usize = 8;
+
+#[cfg(target_arch = "aarch64")]
+pub const ARM64_MAX_WATCHPOINTS: usize = 2;
+
+#[cfg(target_arch = "aarch64")]
+#[repr(C)]
+pub struct ARM64_NT_NEON128 {
+ pub D: [f64; 2],
+}
+
+#[cfg(target_arch = "aarch64")]
+#[repr(C, align(16))]
+pub struct CONTEXT {
+ pub ContextFlags: DWORD,
+ pub Cpsr: DWORD,
+ pub X0: u64,
+ pub X1: u64,
+ pub X2: u64,
+ pub X3: u64,
+ pub X4: u64,
+ pub X5: u64,
+ pub X6: u64,
+ pub X7: u64,
+ pub X8: u64,
+ pub X9: u64,
+ pub X10: u64,
+ pub X11: u64,
+ pub X12: u64,
+ pub X13: u64,
+ pub X14: u64,
+ pub X15: u64,
+ pub X16: u64,
+ pub X17: u64,
+ pub X18: u64,
+ pub X19: u64,
+ pub X20: u64,
+ pub X21: u64,
+ pub X22: u64,
+ pub X23: u64,
+ pub X24: u64,
+ pub X25: u64,
+ pub X26: u64,
+ pub X27: u64,
+ pub X28: u64,
+ pub Fp: u64,
+ pub Lr: u64,
+ pub Sp: u64,
+ pub Pc: u64,
+ pub V: [ARM64_NT_NEON128; 32],
+ pub Fpcr: DWORD,
+ pub Fpsr: DWORD,
+ pub Bcr: [DWORD; ARM64_MAX_BREAKPOINTS],
+ pub Bvr: [DWORD; ARM64_MAX_BREAKPOINTS],
+ pub Wcr: [DWORD; ARM64_MAX_WATCHPOINTS],
+ pub Wvr: [DWORD; ARM64_MAX_WATCHPOINTS],
+}
+
#[repr(C)]
pub struct SOCKADDR_STORAGE_LH {
pub ss_family: ADDRESS_FAMILY,
diff --git a/ctr-std/src/sys/windows/ext/ffi.rs b/ctr-std/src/sys/windows/ext/ffi.rs
index 98d4355..bae0d02 100644
--- a/ctr-std/src/sys/windows/ext/ffi.rs
+++ b/ctr-std/src/sys/windows/ext/ffi.rs
@@ -31,7 +31,7 @@
//!
//! If Rust code *does* need to look into those strings, it can
//! convert them to valid UTF-8, possibly lossily, by substituting
-//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is
+//! invalid sequences with [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD], as is
//! conventionally done in other Rust APIs that deal with string
//! encodings.
//!
@@ -65,6 +65,7 @@
//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide
//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide
//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect
+//! [U+FFFD]: ../../../char/constant.REPLACEMENT_CHARACTER.html
#![stable(feature = "rust1", since = "1.0.0")]
diff --git a/ctr-std/src/sys/windows/ext/mod.rs b/ctr-std/src/sys/windows/ext/mod.rs
index 4b458d2..1f10609 100644
--- a/ctr-std/src/sys/windows/ext/mod.rs
+++ b/ctr-std/src/sys/windows/ext/mod.rs
@@ -18,6 +18,7 @@
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(windows))]
+#![allow(missing_docs)]
pub mod ffi;
pub mod fs;
diff --git a/ctr-std/src/sys/windows/mod.rs b/ctr-std/src/sys/windows/mod.rs
index 0d12ecf..ccf79de 100644
--- a/ctr-std/src/sys/windows/mod.rs
+++ b/ctr-std/src/sys/windows/mod.rs
@@ -266,8 +266,12 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD {
// handlers.
//
// https://msdn.microsoft.com/en-us/library/dn774154.aspx
-#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+#[allow(unreachable_code)]
pub unsafe fn abort_internal() -> ! {
- asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
- ::intrinsics::unreachable();
+ #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
+ {
+ asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT
+ ::intrinsics::unreachable();
+ }
+ ::intrinsics::abort();
}
diff --git a/ctr-std/src/sys/windows/process.rs b/ctr-std/src/sys/windows/process.rs
index be442f4..4974a8d 100644
--- a/ctr-std/src/sys/windows/process.rs
+++ b/ctr-std/src/sys/windows/process.rs
@@ -487,9 +487,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
} else {
if x == '"' as u16 {
// Add n+1 backslashes to total 2n+1 before internal '"'.
- for _ in 0..(backslashes+1) {
- cmd.push('\\' as u16);
- }
+ cmd.extend((0..(backslashes + 1)).map(|_| '\\' as u16));
}
backslashes = 0;
}
@@ -498,9 +496,7 @@ fn make_command_line(prog: &OsStr, args: &[OsString]) -> io::Result<Vec<u16>> {
if quote {
// Add n backslashes to total 2n before ending '"'.
- for _ in 0..backslashes {
- cmd.push('\\' as u16);
- }
+ cmd.extend((0..backslashes).map(|_| '\\' as u16));
cmd.push('"' as u16);
}
Ok(())
diff --git a/ctr-std/src/sys/windows/thread.rs b/ctr-std/src/sys/windows/thread.rs
index b6f6330..85588cc 100644
--- a/ctr-std/src/sys/windows/thread.rs
+++ b/ctr-std/src/sys/windows/thread.rs
@@ -28,7 +28,7 @@ pub struct Thread {
}
impl Thread {
- pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>)
+ pub unsafe fn new<'a>(stack: usize, p: Box<dyn FnBox() + 'a>)
-> io::Result<Thread> {
let p = box p;
@@ -42,7 +42,8 @@ impl Thread {
let stack_size = (stack + 0xfffe) & (!0xfffe);
let ret = c::CreateThread(ptr::null_mut(), stack_size,
thread_start, &*p as *const _ as *mut _,
- 0, ptr::null_mut());
+ c::STACK_SIZE_PARAM_IS_A_RESERVATION,
+ ptr::null_mut());
return if ret as usize == 0 {
Err(io::Error::last_os_error())