aboutsummaryrefslogtreecommitdiff
path: root/ctr-std/src/sys
diff options
context:
space:
mode:
authorFenrir <[email protected]>2018-01-21 14:06:28 -0700
committerFenrirWolf <[email protected]>2018-01-21 19:16:33 -0700
commit23be3f4885688e5e0011005e2295c75168854c0a (patch)
treedd0850f9c73c489e114a761d5c0757f3dbec3a65 /ctr-std/src/sys
parentUpdate CI for Rust nightly-2017-12-01 + other fixes (diff)
downloadctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.tar.xz
ctru-rs-23be3f4885688e5e0011005e2295c75168854c0a.zip
Recreate ctr-std from latest nightly
Diffstat (limited to 'ctr-std/src/sys')
-rw-r--r--ctr-std/src/sys/mod.rs67
-rw-r--r--ctr-std/src/sys/unix/args.rs60
-rw-r--r--ctr-std/src/sys/unix/backtrace.rs37
-rw-r--r--ctr-std/src/sys/unix/cmath.rs43
-rw-r--r--ctr-std/src/sys/unix/condvar.rs4
-rw-r--r--ctr-std/src/sys/unix/env.rs19
-rw-r--r--ctr-std/src/sys/unix/ext/ffi.rs60
-rw-r--r--ctr-std/src/sys/unix/ext/io.rs108
-rw-r--r--ctr-std/src/sys/unix/ext/mod.rs31
-rw-r--r--ctr-std/src/sys/unix/ext/raw.rs33
-rw-r--r--ctr-std/src/sys/unix/fd.rs104
-rw-r--r--ctr-std/src/sys/unix/fs.rs131
-rw-r--r--ctr-std/src/sys/unix/io.rs81
-rw-r--r--ctr-std/src/sys/unix/memchr.rs14
-rw-r--r--ctr-std/src/sys/unix/mod.rs53
-rw-r--r--ctr-std/src/sys/unix/mutex.rs30
-rw-r--r--ctr-std/src/sys/unix/net.rs418
-rw-r--r--ctr-std/src/sys/unix/os.rs94
-rw-r--r--ctr-std/src/sys/unix/os_str.rs81
-rw-r--r--ctr-std/src/sys/unix/path.rs2
-rw-r--r--ctr-std/src/sys/unix/pipe.rs35
-rw-r--r--ctr-std/src/sys/unix/process.rs151
-rw-r--r--ctr-std/src/sys/unix/stack_overflow.rs23
-rw-r--r--ctr-std/src/sys/unix/stdio.rs12
-rw-r--r--ctr-std/src/sys/unix/thread.rs53
-rw-r--r--ctr-std/src/sys/unix/thread_local.rs7
-rw-r--r--ctr-std/src/sys/unix/time.rs12
27 files changed, 1539 insertions, 224 deletions
diff --git a/ctr-std/src/sys/mod.rs b/ctr-std/src/sys/mod.rs
index 175e227..569336d 100644
--- a/ctr-std/src/sys/mod.rs
+++ b/ctr-std/src/sys/mod.rs
@@ -13,25 +13,78 @@
//! The `std::sys` module is the abstracted interface through which
//! `std` talks to the underlying operating system. It has different
//! implementations for different operating system families, today
-//! just Unix and Windows.
+//! just Unix and Windows, and initial support for Redox.
//!
//! The centralization of platform-specific code in this module is
//! enforced by the "platform abstraction layer" tidy script in
-//! `tools/tidy/pal.rs`.
+//! `tools/tidy/src/pal.rs`.
//!
//! This module is closely related to the platform-independent system
//! integration code in `std::sys_common`. See that module's
//! documentation for details.
//!
-//! In the future it would be desirable for the indepedent
+//! In the future it would be desirable for the independent
//! implementations of this module to be extracted to their own crates
//! that `std` can link to, thus enabling their implementation
//! out-of-tree via crate replacement. Though due to the complex
//! inter-dependencies within `std` that will be a challenging goal to
//! achieve.
-pub use self::imp::*;
+#![allow(missing_debug_implementations)]
-#[cfg(unix)]
-#[path = "unix/mod.rs"]
-mod imp;
+cfg_if! {
+ if #[cfg(unix)] {
+ mod unix;
+ pub use self::unix::*;
+ } else {
+ compile_error!("libstd doesn't compile for this platform yet");
+ }
+}
+
+// Import essential modules from both platforms when documenting. These are
+// then later used in the `std::os` module when documenting, for example,
+// Windows when we're compiling for Linux.
+
+#[cfg(dox)]
+cfg_if! {
+ if #[cfg(any(unix, target_os = "redox"))] {
+ // On unix we'll document what's already available
+ pub use self::ext as unix_ext;
+ } else if #[cfg(any(target_os = "cloudabi", target_arch = "wasm32"))] {
+ // On CloudABI and wasm right now the module below doesn't compile
+ // (missing things in `libc` which is empty) so just omit everything
+ // with an empty module
+ #[unstable(issue = "0", feature = "std_internals")]
+ pub mod unix_ext {}
+ } else {
+ // On other platforms like Windows document the bare bones of unix
+ use os::linux as platform;
+ #[path = "unix/ext/mod.rs"]
+ pub mod unix_ext;
+ }
+}
+
+#[cfg(dox)]
+cfg_if! {
+ if #[cfg(windows)] {
+ // On windows we'll just be documenting what's already available
+ 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")]
+ pub mod windows_ext {}
+ } else {
+ // On all other platforms (aka linux/osx/etc) then pull in a "minimal"
+ // amount of windows goop which ends up compiling
+ #[macro_use]
+ #[path = "windows/compat.rs"]
+ mod compat;
+
+ #[path = "windows/c.rs"]
+ mod c;
+
+ #[path = "windows/ext/mod.rs"]
+ pub mod windows_ext;
+ }
+}
diff --git a/ctr-std/src/sys/unix/args.rs b/ctr-std/src/sys/unix/args.rs
new file mode 100644
index 0000000..84d0c85
--- /dev/null
+++ b/ctr-std/src/sys/unix/args.rs
@@ -0,0 +1,60 @@
+// Copyright 2017 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.
+
+use ffi::OsString;
+use marker::PhantomData;
+use vec;
+
+pub unsafe fn init(_argc: isize, _argv: *const *const u8) {
+ // Currently null because we haven't implemented args yet
+}
+
+pub unsafe fn cleanup() {
+}
+
+pub fn args() -> Args {
+ return Args {
+ iter: Vec::new().into_iter(),
+ _dont_send_or_sync_me: PhantomData,
+ }
+}
+
+pub struct Args {
+ iter: vec::IntoIter<OsString>,
+ _dont_send_or_sync_me: PhantomData<*mut ()>,
+}
+
+impl Args {
+ pub fn inner_debug(&self) -> &[OsString] {
+ self.iter.as_slice()
+ }
+}
+
+impl Iterator for Args {
+ type Item = OsString;
+ fn next(&mut self) -> Option<OsString> {
+ self.iter.next()
+ }
+ fn size_hint(&self) -> (usize, Option<usize>) {
+ self.iter.size_hint()
+ }
+}
+
+impl ExactSizeIterator for Args {
+ fn len(&self) -> usize {
+ self.iter.len()
+ }
+}
+
+impl DoubleEndedIterator for Args {
+ fn next_back(&mut self) -> Option<OsString> {
+ self.iter.next_back()
+ }
+}
diff --git a/ctr-std/src/sys/unix/backtrace.rs b/ctr-std/src/sys/unix/backtrace.rs
new file mode 100644
index 0000000..9a8c48f
--- /dev/null
+++ b/ctr-std/src/sys/unix/backtrace.rs
@@ -0,0 +1,37 @@
+// Copyright 2017 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.
+
+use io;
+use sys::unsupported;
+use sys_common::backtrace::Frame;
+
+pub struct BacktraceContext;
+
+pub fn unwind_backtrace(_frames: &mut [Frame])
+ -> io::Result<(usize, BacktraceContext)>
+{
+ unsupported()
+}
+
+pub fn resolve_symname<F>(_frame: Frame,
+ _callback: F,
+ _: &BacktraceContext) -> io::Result<()>
+ where F: FnOnce(Option<&str>) -> io::Result<()>
+{
+ unsupported()
+}
+
+pub fn foreach_symbol_fileline<F>(_: Frame,
+ _: F,
+ _: &BacktraceContext) -> io::Result<bool>
+ where F: FnMut(&[u8], u32) -> io::Result<()>
+{
+ unsupported()
+}
diff --git a/ctr-std/src/sys/unix/cmath.rs b/ctr-std/src/sys/unix/cmath.rs
new file mode 100644
index 0000000..2bc9665
--- /dev/null
+++ b/ctr-std/src/sys/unix/cmath.rs
@@ -0,0 +1,43 @@
+// Copyright 2017 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.
+
+#![cfg(not(test))]
+
+use libc::{c_float, c_double};
+
+#[link_name = "m"]
+extern {
+ pub fn acos(n: c_double) -> c_double;
+ pub fn acosf(n: c_float) -> c_float;
+ pub fn asin(n: c_double) -> c_double;
+ pub fn asinf(n: c_float) -> c_float;
+ pub fn atan(n: c_double) -> c_double;
+ pub fn atan2(a: c_double, b: c_double) -> c_double;
+ pub fn atan2f(a: c_float, b: c_float) -> c_float;
+ pub fn atanf(n: c_float) -> c_float;
+ pub fn cbrt(n: c_double) -> c_double;
+ pub fn cbrtf(n: c_float) -> c_float;
+ pub fn cosh(n: c_double) -> c_double;
+ pub fn coshf(n: c_float) -> c_float;
+ pub fn expm1(n: c_double) -> c_double;
+ pub fn expm1f(n: c_float) -> c_float;
+ pub fn fdim(a: c_double, b: c_double) -> c_double;
+ pub fn fdimf(a: c_float, b: c_float) -> c_float;
+ pub fn hypot(x: c_double, y: c_double) -> c_double;
+ pub fn hypotf(x: c_float, y: c_float) -> c_float;
+ pub fn log1p(n: c_double) -> c_double;
+ pub fn log1pf(n: c_float) -> c_float;
+ pub fn sinh(n: c_double) -> c_double;
+ pub fn sinhf(n: c_float) -> c_float;
+ pub fn tan(n: c_double) -> c_double;
+ pub fn tanf(n: c_float) -> c_float;
+ pub fn tanh(n: c_double) -> c_double;
+ pub fn tanhf(n: c_float) -> c_float;
+}
diff --git a/ctr-std/src/sys/unix/condvar.rs b/ctr-std/src/sys/unix/condvar.rs
index 938df8f..bfff16b 100644
--- a/ctr-std/src/sys/unix/condvar.rs
+++ b/ctr-std/src/sys/unix/condvar.rs
@@ -112,7 +112,9 @@ impl Condvar {
let now = Instant::now();
- let nanos = dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64;
+ let nanos = dur.as_secs()
+ .saturating_mul(1_000_000_000)
+ .saturating_add(dur.subsec_nanos() as u64);
mutex.unlock();
diff --git a/ctr-std/src/sys/unix/env.rs b/ctr-std/src/sys/unix/env.rs
new file mode 100644
index 0000000..393bdfe
--- /dev/null
+++ b/ctr-std/src/sys/unix/env.rs
@@ -0,0 +1,19 @@
+// Copyright 2017 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.
+
+pub mod os {
+ pub const FAMILY: &'static str = "nintendo";
+ pub const OS: &'static str = "horizon";
+ pub const DLL_PREFIX: &'static str = "";
+ pub const DLL_SUFFIX: &'static str = ".cro";
+ pub const DLL_EXTENSION: &'static str = ".cro";
+ pub const EXE_SUFFIX: &'static str = ".3dsx";
+ pub const EXE_EXTENSION: &'static str = "3dsx";
+}
diff --git a/ctr-std/src/sys/unix/ext/ffi.rs b/ctr-std/src/sys/unix/ext/ffi.rs
index d59b4fc..fb9984c 100644
--- a/ctr-std/src/sys/unix/ext/ffi.rs
+++ b/ctr-std/src/sys/unix/ext/ffi.rs
@@ -20,11 +20,38 @@ use sys_common::{FromInner, IntoInner, AsInner};
/// Unix-specific extensions to `OsString`.
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
- /// Creates an `OsString` from a byte vector.
+ /// Creates an [`OsString`] from a byte vector.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::OsStringExt;
+ ///
+ /// let bytes = b"foo".to_vec();
+ /// let os_string = OsString::from_vec(bytes);
+ /// assert_eq!(os_string.to_str(), Some("foo"));
+ /// ```
+ ///
+ /// [`OsString`]: ../../../ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
fn from_vec(vec: Vec<u8>) -> Self;
- /// Yields the underlying byte vector of this `OsString`.
+ /// Yields the underlying byte vector of this [`OsString`].
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsString;
+ /// use std::os::unix::ffi::OsStringExt;
+ ///
+ /// let mut os_string = OsString::new();
+ /// os_string.push("foo");
+ /// let bytes = os_string.into_vec();
+ /// assert_eq!(bytes, b"foo");
+ /// ```
+ ///
+ /// [`OsString`]: ../../../ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
fn into_vec(self) -> Vec<u8>;
}
@@ -43,9 +70,36 @@ impl OsStringExt for OsString {
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
+ /// Creates an [`OsStr`] from a byte slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ /// use std::os::unix::ffi::OsStrExt;
+ ///
+ /// let bytes = b"foo";
+ /// let os_str = OsStr::from_bytes(bytes);
+ /// assert_eq!(os_str.to_str(), Some("foo"));
+ /// ```
+ ///
+ /// [`OsStr`]: ../../../ffi/struct.OsStr.html
fn from_bytes(slice: &[u8]) -> &Self;
- /// Gets the underlying byte view of the `OsStr` slice.
+ /// Gets the underlying byte view of the [`OsStr`] slice.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use std::ffi::OsStr;
+ /// use std::os::unix::ffi::OsStrExt;
+ ///
+ /// let mut os_str = OsStr::new("foo");
+ /// let bytes = os_str.as_bytes();
+ /// assert_eq!(bytes, b"foo");
+ /// ```
+ ///
+ /// [`OsStr`]: ../../../ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8];
}
diff --git a/ctr-std/src/sys/unix/ext/io.rs b/ctr-std/src/sys/unix/ext/io.rs
new file mode 100644
index 0000000..c9fe359
--- /dev/null
+++ b/ctr-std/src/sys/unix/ext/io.rs
@@ -0,0 +1,108 @@
+// Copyright 2015 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.
+
+//! Unix-specific extensions to general I/O primitives
+
+#![stable(feature = "rust1", since = "1.0.0")]
+
+use fs;
+use os::raw;
+use sys;
+use io;
+use sys_common::{AsInner, FromInner, IntoInner};
+use libc;
+
+/// Raw file descriptors.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub type RawFd = raw::c_int;
+
+/// A trait to extract the raw unix file descriptor from an underlying
+/// object.
+///
+/// This is only available on unix platforms and must be imported in order
+/// to call the method. Windows platforms have a corresponding `AsRawHandle`
+/// and `AsRawSocket` set of traits.
+#[stable(feature = "rust1", since = "1.0.0")]
+pub trait AsRawFd {
+ /// Extracts the raw file descriptor.
+ ///
+ /// This method does **not** pass ownership of the raw file descriptor
+ /// to the caller. The descriptor is only guaranteed to be valid while
+ /// the original object has not yet been destroyed.
+ #[stable(feature = "rust1", since = "1.0.0")]
+ fn as_raw_fd(&self) -> RawFd;
+}
+
+/// A trait to express the ability to construct an object from a raw file
+/// descriptor.
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+pub trait FromRawFd {
+ /// Constructs a new instance of `Self` from the given raw file
+ /// descriptor.
+ ///
+ /// This function **consumes ownership** of the specified file
+ /// descriptor. The returned object will take responsibility for closing
+ /// it when the object goes out of scope.
+ ///
+ /// This function is also unsafe as the primitives currently returned
+ /// have the contract that they are the sole owner of the file
+ /// descriptor they are wrapping. Usage of this function could
+ /// accidentally allow violating this contract which can cause memory
+ /// unsafety in code that relies on it being true.
+ #[stable(feature = "from_raw_os", since = "1.1.0")]
+ unsafe fn from_raw_fd(fd: RawFd) -> Self;
+}
+
+/// A trait to express the ability to consume an object and acquire ownership of
+/// its raw file descriptor.
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+pub trait IntoRawFd {
+ /// Consumes this object, returning the raw underlying file descriptor.
+ ///
+ /// This function **transfers ownership** of the underlying file descriptor
+ /// to the caller. Callers are then the unique owners of the file descriptor
+ /// and must close the descriptor once it's no longer needed.
+ #[stable(feature = "into_raw_os", since = "1.4.0")]
+ fn into_raw_fd(self) -> RawFd;
+}
+
+#[stable(feature = "rust1", since = "1.0.0")]
+impl AsRawFd for fs::File {
+ fn as_raw_fd(&self) -> RawFd {
+ self.as_inner().fd().raw()
+ }
+}
+#[stable(feature = "from_raw_os", since = "1.1.0")]
+impl FromRawFd for fs::File {
+ unsafe fn from_raw_fd(fd: RawFd) -> fs::File {
+ fs::File::from_inner(sys::fs::File::from_inner(fd))
+ }
+}
+#[stable(feature = "into_raw_os", since = "1.4.0")]
+impl IntoRawFd for fs::File {
+ fn into_raw_fd(self) -> RawFd {
+ self.into_inner().into_fd().into_raw()
+ }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdin {
+ fn as_raw_fd(&self) -> RawFd { libc::STDIN_FILENO }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stdout {
+ fn as_raw_fd(&self) -> RawFd { libc::STDOUT_FILENO }
+}
+
+#[stable(feature = "asraw_stdio", since = "1.21.0")]
+impl AsRawFd for io::Stderr {
+ fn as_raw_fd(&self) -> RawFd { libc::STDERR_FILENO }
+}
diff --git a/ctr-std/src/sys/unix/ext/mod.rs b/ctr-std/src/sys/unix/ext/mod.rs
index 04ea563..7b0d175 100644
--- a/ctr-std/src/sys/unix/ext/mod.rs
+++ b/ctr-std/src/sys/unix/ext/mod.rs
@@ -10,10 +10,16 @@
//! Experimental extensions to `std` for Unix platforms.
//!
-//! For now, this module is limited to extracting file descriptors,
-//! but its functionality will grow over time.
+//! Provides access to platform-level information on Unix platforms, and
+//! exposes Unix-specific functions that would otherwise be inappropriate as
+//! part of the core `std` library.
//!
-//! # Example
+//! It exposes more ways to deal with platform-specific strings (`OsStr`,
+//! `OsString`), allows to set permissions more granularly, extract low-level
+//! file descriptors from files and sockets, and has platform-specific helpers
+//! for spawning processes.
+//!
+//! # Examples
//!
//! ```no_run
//! use std::fs::File;
@@ -28,8 +34,15 @@
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
+#![doc(cfg(unix))]
+pub mod io;
pub mod ffi;
+//pub mod fs;
+//pub mod process;
+pub mod raw;
+//pub mod thread;
+//pub mod net;
/// A prelude for conveniently writing platform-specific code.
///
@@ -37,5 +50,17 @@ pub mod ffi;
#[stable(feature = "rust1", since = "1.0.0")]
pub mod prelude {
#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ pub use super::io::{RawFd, AsRawFd, FromRawFd, IntoRawFd};
+ #[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
pub use super::ffi::{OsStrExt, OsStringExt};
+ //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ //pub use super::fs::{PermissionsExt, OpenOptionsExt, MetadataExt, FileTypeExt};
+ //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ //pub use super::fs::DirEntryExt;
+ //#[doc(no_inline)] #[stable(feature = "file_offset", since = "1.15.0")]
+ //pub use super::fs::FileExt;
+ //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ //pub use super::thread::JoinHandleExt;
+ //#[doc(no_inline)] #[stable(feature = "rust1", since = "1.0.0")]
+ //pub use super::process::{CommandExt, ExitStatusExt};
}
diff --git a/ctr-std/src/sys/unix/ext/raw.rs b/ctr-std/src/sys/unix/ext/raw.rs
new file mode 100644
index 0000000..7e4a439
--- /dev/null
+++ b/ctr-std/src/sys/unix/ext/raw.rs
@@ -0,0 +1,33 @@
+// Copyright 2015 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.
+
+//! Unix-specific primitives available on all unix platforms
+
+#![stable(feature = "raw_ext", since = "1.1.0")]
+#![rustc_deprecated(since = "1.8.0",
+ reason = "these type aliases are no longer supported by \
+ the standard library, the `libc` crate on \
+ crates.io should be used instead for the correct \
+ definitions")]
+#![allow(deprecated, warnings)]
+
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type uid_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type gid_t = u32;
+#[stable(feature = "raw_ext", since = "1.1.0")] pub type pid_t = i32;
+
+#[doc(inline)]
+#[stable(feature = "pthread_t", since = "1.8.0")]
+pub use sys::platform::raw::pthread_t;
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use sys::platform::raw::{dev_t, ino_t, mode_t, nlink_t, off_t, blksize_t};
+#[doc(inline)]
+#[stable(feature = "raw_ext", since = "1.1.0")]
+pub use sys::platform::raw::{blkcnt_t, time_t};
diff --git a/ctr-std/src/sys/unix/fd.rs b/ctr-std/src/sys/unix/fd.rs
index 91adac1..e19cbb0 100644
--- a/ctr-std/src/sys/unix/fd.rs
+++ b/ctr-std/src/sys/unix/fd.rs
@@ -14,9 +14,9 @@ use cmp;
use io::{self, Read};
use libc::{self, c_int, c_void, ssize_t};
use mem;
+use sync::atomic::{AtomicBool, Ordering};
use sys::cvt;
use sys_common::AsInner;
-use sys_common::io::read_to_end_uninitialized;
#[derive(Debug)]
pub struct FileDesc {
@@ -28,7 +28,7 @@ fn max_len() -> usize {
// with the man page quoting that if the count of bytes to read is
// greater than `SSIZE_MAX` the result is "unspecified".
//
- // On OSX, however, apparently the 64-bit libc is either buggy or
+ // On macOS, however, apparently the 64-bit libc is either buggy or
// intentionally showing odd behavior by rejecting any read with a size
// larger than or equal to INT_MAX. To handle both of these the read
// size is capped on both platforms.
@@ -110,22 +110,98 @@ impl FileDesc {
}
}
- // This is a unix-specific operation that the 3DS likely doesn't support.
- // However, there's no reason to make calling this function an error either.
+ #[cfg(not(any(target_env = "newlib",
+ target_os = "solaris",
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "l4re",
+ target_os = "haiku")))]
pub fn set_cloexec(&self) -> io::Result<()> {
- Ok(())
+ unsafe {
+ cvt(libc::ioctl(self.fd, libc::FIOCLEX))?;
+ Ok(())
+ }
+ }
+ #[cfg(any(target_env = "newlib",
+ target_os = "solaris",
+ target_os = "emscripten",
+ target_os = "fuchsia",
+ target_os = "l4re",
+ target_os = "haiku"))]
+ pub fn set_cloexec(&self) -> io::Result<()> {
+ unsafe {
+ let previous = cvt(libc::fcntl(self.fd, libc::F_GETFD))?;
+ let new = previous | libc::FD_CLOEXEC;
+ if new != previous {
+ cvt(libc::fcntl(self.fd, libc::F_SETFD, new))?;
+ }
+ Ok(())
+ }
}
- // This is a unix-specific operation that the 3DS likely doesn't support.
- // However, there's no reason to make calling this function an error either.
- pub fn set_nonblocking(&self) -> io::Result<()> {
- Ok(())
+ pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
+ unsafe {
+ let previous = cvt(libc::fcntl(self.fd, libc::F_GETFL))?;
+ let new = if nonblocking {
+ previous | libc::O_NONBLOCK
+ } else {
+ previous & !libc::O_NONBLOCK
+ };
+ if new != previous {
+ cvt(libc::fcntl(self.fd, libc::F_SETFL, new))?;
+ }
+ Ok(())
+ }
}
- // The sdmc and romfs devoptabs definitely don't support this operation.
- // Not sure if it will be needed for network support or not.
pub fn duplicate(&self) -> io::Result<FileDesc> {
- unimplemented!()
+ // We want to atomically duplicate this file descriptor and set the
+ // CLOEXEC flag, and currently that's done via F_DUPFD_CLOEXEC. This
+ // flag, however, isn't supported on older Linux kernels (earlier than
+ // 2.6.24).
+ //
+ // To detect this and ensure that CLOEXEC is still set, we
+ // follow a strategy similar to musl [1] where if passing
+ // F_DUPFD_CLOEXEC causes `fcntl` to return EINVAL it means it's not
+ // supported (the third parameter, 0, is always valid), so we stop
+ // trying that.
+ //
+ // Also note that Android doesn't have F_DUPFD_CLOEXEC, but get it to
+ // resolve so we at least compile this.
+ //
+ // [1]: http://comments.gmane.org/gmane.linux.lib.musl.general/2963
+ #[cfg(any(target_os = "android", target_os = "haiku"))]
+ use libc::F_DUPFD as F_DUPFD_CLOEXEC;
+ #[cfg(not(any(target_os = "android", target_os="haiku")))]
+ use libc::F_DUPFD_CLOEXEC;
+
+ let make_filedesc = |fd| {
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ Ok(fd)
+ };
+ static TRY_CLOEXEC: AtomicBool =
+ AtomicBool::new(!cfg!(target_os = "android"));
+ let fd = self.raw();
+ if TRY_CLOEXEC.load(Ordering::Relaxed) {
+ match cvt(unsafe { libc::fcntl(fd, F_DUPFD_CLOEXEC, 0) }) {
+ // We *still* call the `set_cloexec` method as apparently some
+ // linux kernel at some point stopped setting CLOEXEC even
+ // though it reported doing so on F_DUPFD_CLOEXEC.
+ Ok(fd) => {
+ return Ok(if cfg!(target_os = "linux") {
+ make_filedesc(fd)?
+ } else {
+ FileDesc::new(fd)
+ })
+ }
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {
+ TRY_CLOEXEC.store(false, Ordering::Relaxed);
+ }
+ Err(e) => return Err(e),
+ }
+ }
+ cvt(unsafe { libc::fcntl(fd, libc::F_DUPFD, 0) }).and_then(make_filedesc)
}
}
@@ -133,10 +209,6 @@ impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
-
- fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
- unsafe { read_to_end_uninitialized(self, buf) }
- }
}
impl AsInner<c_int> for FileDesc {
diff --git a/ctr-std/src/sys/unix/fs.rs b/ctr-std/src/sys/unix/fs.rs
index 06413c3..f30b270 100644
--- a/ctr-std/src/sys/unix/fs.rs
+++ b/ctr-std/src/sys/unix/fs.rs
@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+#![allow(dead_code)]
+
use os::unix::prelude::*;
use ffi::{CString, CStr, OsString, OsStr};
@@ -23,8 +25,8 @@ use sys::time::SystemTime;
use sys::{cvt, cvt_r};
use sys_common::{AsInner, FromInner};
-use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek as lseek64,
- dirent as dirent64, open as open64, ftruncate as ftruncate64, off_t as off64_t};
+use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, off_t as off64_t,
+ ftruncate as ftruncate64, lseek as lseek64, dirent as dirent64, open as open64};
use libc::{readdir_r as readdir64_r};
pub struct File(FileDesc);
@@ -47,6 +49,12 @@ unsafe impl Sync for Dir {}
pub struct DirEntry {
entry: dirent64,
root: Arc<PathBuf>,
+ // We need to store an owned copy of the directory name
+ // on Solaris and Fuchsia because a) it uses a zero-length
+ // array to store the name, b) its lifetime between readdir
+ // calls is not guaranteed.
+ #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
+ name: Box<[u8]>
}
#[derive(Clone, Debug)]
@@ -75,7 +83,7 @@ pub struct DirBuilder { mode: mode_t }
impl FileAttr {
pub fn size(&self) -> u64 { self.stat.st_size as u64 }
pub fn perm(&self) -> FilePermissions {
- FilePermissions { mode: (self.stat.st_mode as mode_t) & 0o777 }
+ FilePermissions { mode: (self.stat.st_mode as mode_t) }
}
pub fn file_type(&self) -> FileType {
@@ -85,17 +93,15 @@ impl FileAttr {
impl FileAttr {
pub fn modified(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_mtime as libc::time_t,
- tv_nsec: 0,
- }))
+ Err(io::Error::new(io::ErrorKind::Other,
+ "modification time is not available on this platform \
+ currently"))
}
pub fn accessed(&self) -> io::Result<SystemTime> {
- Ok(SystemTime::from(libc::timespec {
- tv_sec: self.stat.st_atime as libc::time_t,
- tv_nsec: 0,
- }))
+ Err(io::Error::new(io::ErrorKind::Other,
+ "access time is not available on this platform \
+ currently"))
}
pub fn created(&self) -> io::Result<SystemTime> {
@@ -110,11 +116,17 @@ impl AsInner<stat64> for FileAttr {
}
impl FilePermissions {
- pub fn readonly(&self) -> bool { self.mode & 0o222 == 0 }
+ pub fn readonly(&self) -> bool {
+ // check if any class (owner, group, others) has write permission
+ self.mode & 0o222 == 0
+ }
+
pub fn set_readonly(&mut self, readonly: bool) {
if readonly {
+ // remove write permission for all classes; equivalent to `chmod a-w <file>`
self.mode &= !0o222;
} else {
+ // add write permission for all classes; equivalent to `chmod a+w <file>`
self.mode |= 0o222;
}
}
@@ -146,6 +158,42 @@ impl fmt::Debug for ReadDir {
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
+ #[cfg(any(target_os = "solaris", target_os = "fuchsia"))]
+ fn next(&mut self) -> Option<io::Result<DirEntry>> {
+ unsafe {
+ loop {
+ // Although readdir_r(3) would be a correct function to use here because
+ // of the thread safety, on Illumos and Fuchsia the readdir(3C) function
+ // 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.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.
+ return match super::os::errno() {
+ 0 => None,
+ e => Some(Err(Error::from_raw_os_error(e))),
+ }
+ }
+
+ let name = (*entry_ptr).d_name.as_ptr();
+ let namelen = libc::strlen(name) as usize;
+
+ let ret = DirEntry {
+ entry: *entry_ptr,
+ name: ::slice::from_raw_parts(name as *const u8,
+ namelen as usize).to_owned().into_boxed_slice(),
+ root: self.root.clone()
+ };
+ if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
+ return Some(Ok(ret))
+ }
+ }
+ }
+ }
+
+ #[cfg(not(any(target_os = "solaris", target_os = "fuchsia")))]
fn next(&mut self) -> Option<io::Result<DirEntry>> {
unsafe {
let mut ret = DirEntry {
@@ -188,6 +236,12 @@ impl DirEntry {
lstat(&self.path())
}
+ #[cfg(any(target_os = "solaris", target_os = "haiku"))]
+ 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")))]
pub fn file_type(&self) -> io::Result<FileType> {
match self.entry.d_type {
libc::DT_CHR => Ok(FileType { mode: libc::S_IFCHR }),
@@ -293,7 +347,7 @@ impl File {
// Linux kernel then the flag is just ignored by the OS, so we continue
// to explicitly ask for a CLOEXEC fd here.
//
- // The CLOEXEC flag, however, is supported on versions of OSX/BSD/etc
+ // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
// that we support, so we only do this on Linux currently.
if cfg!(target_os = "linux") {
fd.set_cloexec()?;
@@ -323,6 +377,10 @@ impl File {
}
pub fn truncate(&self, size: u64) -> io::Result<()> {
+ #[cfg(target_os = "android")]
+ return ::sys::android::ftruncate64(self.0.raw(), size);
+
+ #[cfg(not(target_os = "android"))]
return cvt_r(|| unsafe {
ftruncate64(self.0.raw(), size as off64_t)
}).map(|_| ());
@@ -332,10 +390,6 @@ impl File {
self.0.read(buf)
}
- pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
- self.0.read_to_end(buf)
- }
-
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.0.read_at(buf, offset)
}
@@ -358,6 +412,8 @@ impl File {
SeekFrom::End(off) => (libc::SEEK_END, off),
SeekFrom::Current(off) => (libc::SEEK_CUR, off),
};
+ #[cfg(target_os = "emscripten")]
+ let pos = pos as i32;
let n = cvt(unsafe { lseek64(self.0.raw(), pos, whence) })?;
Ok(n as u64)
}
@@ -404,11 +460,52 @@ impl FromInner<c_int> for File {
impl fmt::Debug for File {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ #[cfg(target_os = "linux")]
+ fn get_path(fd: c_int) -> Option<PathBuf> {
+ let mut p = PathBuf::from("/proc/self/fd");
+ p.push(&fd.to_string());
+ readlink(&p).ok()
+ }
+
+ #[cfg(target_os = "macos")]
+ fn get_path(fd: c_int) -> Option<PathBuf> {
+ // FIXME: The use of PATH_MAX is generally not encouraged, but it
+ // is inevitable in this case because macOS defines `fcntl` with
+ // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no
+ // alternatives. If a better method is invented, it should be used
+ // instead.
+ let mut buf = vec![0;libc::PATH_MAX as usize];
+ let n = unsafe { libc::fcntl(fd, libc::F_GETPATH, buf.as_ptr()) };
+ if n == -1 {
+ return None;
+ }
+ let l = buf.iter().position(|&c| c == 0).unwrap();
+ buf.truncate(l as usize);
+ buf.shrink_to_fit();
+ Some(PathBuf::from(OsString::from_vec(buf)))
+ }
+
+ #[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn get_path(_fd: c_int) -> Option<PathBuf> {
// FIXME(#24570): implement this for other Unix platforms
None
}
+ #[cfg(any(target_os = "linux", target_os = "macos"))]
+ fn get_mode(fd: c_int) -> Option<(bool, bool)> {
+ let mode = unsafe { libc::fcntl(fd, libc::F_GETFL) };
+ if mode == -1 {
+ return None;
+ }
+ match mode & libc::O_ACCMODE {
+ libc::O_RDONLY => Some((true, false)),
+ libc::O_RDWR => Some((true, true)),
+ libc::O_WRONLY => Some((false, true)),
+ _ => None
+ }
+ }
+
+ #[cfg(not(any(target_os = "linux", target_os = "macos")))]
fn get_mode(_fd: c_int) -> Option<(bool, bool)> {
// FIXME(#24570): implement this for other Unix platforms
None
diff --git a/ctr-std/src/sys/unix/io.rs b/ctr-std/src/sys/unix/io.rs
deleted file mode 100644
index 6d38b00..0000000
--- a/ctr-std/src/sys/unix/io.rs
+++ /dev/null
@@ -1,81 +0,0 @@
-// Copyright 2015 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.
-
-use io;
-use libc;
-use sys::fd::FileDesc;
-
-pub struct Stdin(());
-pub struct Stdout(());
-pub struct Stderr(());
-
-impl Stdin {
- pub fn new() -> io::Result<Stdin> { Ok(Stdin(())) }
-
- pub fn read(&self, data: &mut [u8]) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDIN_FILENO);
- let ret = fd.read(data);
- fd.into_raw();
- ret
- }
-
- pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDIN_FILENO);
- let ret = fd.read_to_end(buf);
- fd.into_raw();
- ret
- }
-}
-
-impl Stdout {
- pub fn new() -> io::Result<Stdout> { Ok(Stdout(())) }
-
- pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDOUT_FILENO);
- let ret = fd.write(data);
- fd.into_raw();
- ret
- }
-
- pub fn flush(&self) -> io::Result<()> {
- Ok(())
- }
-}
-
-impl Stderr {
- pub fn new() -> io::Result<Stderr> { Ok(Stderr(())) }
-
- pub fn write(&self, data: &[u8]) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDERR_FILENO);
- let ret = fd.write(data);
- fd.into_raw();
- ret
- }
-
- pub fn flush(&self) -> io::Result<()> {
- Ok(())
- }
-}
-
-// FIXME: right now this raw stderr handle is used in a few places because
-// std::io::stderr_raw isn't exposed, but once that's exposed this impl
-// should go away
-impl io::Write for Stderr {
- fn write(&mut self, data: &[u8]) -> io::Result<usize> {
- Stderr::write(self, data)
- }
-
- fn flush(&mut self) -> io::Result<()> {
- Stderr::flush(self)
- }
-}
-
-pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
-pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
diff --git a/ctr-std/src/sys/unix/memchr.rs b/ctr-std/src/sys/unix/memchr.rs
index ae8e3d0..71d9111 100644
--- a/ctr-std/src/sys/unix/memchr.rs
+++ b/ctr-std/src/sys/unix/memchr.rs
@@ -1,3 +1,13 @@
+// Copyright 2017 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.
+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
@@ -28,10 +38,8 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
}
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
- // turns out that newlib doesn't have memrchr(), so we
- // use the fallback version instead
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
- ::sys_common::memchr::fallback::memrchr(needle, haystack)
+ ::core::slice::memchr::memrchr(needle, haystack)
}
memrchr_specific(needle, haystack)
diff --git a/ctr-std/src/sys/unix/mod.rs b/ctr-std/src/sys/unix/mod.rs
index c0e4eb4..11be366 100644
--- a/ctr-std/src/sys/unix/mod.rs
+++ b/ctr-std/src/sys/unix/mod.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -8,46 +8,53 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![allow(missing_docs, bad_style)]
+//! System bindings for the Nintendo 3DS
use io::{self, ErrorKind};
use libc;
+#[cfg(any(dox, target_os = "linux", target_os = "horizon"))] pub use os::linux as platform;
+
pub use self::rand::hashmap_random_keys;
+pub use libc::strlen;
+pub mod args;
+#[cfg(feature = "backtrace")]
+pub mod backtrace;
+pub mod cmath;
pub mod condvar;
+pub mod env;
pub mod ext;
pub mod fast_thread_local;
pub mod fd;
pub mod fs;
-pub mod stdio;
pub mod memchr;
pub mod mutex;
+pub mod net;
pub mod os;
pub mod os_str;
pub mod path;
+pub mod pipe;
+pub mod process;
+pub mod rand;
pub mod rwlock;
+pub mod stack_overflow;
pub mod thread;
-pub mod rand;
pub mod thread_local;
pub mod time;
+pub mod stdio;
#[cfg(not(test))]
pub fn init() {
- // By default, some platforms will send a *signal* when an EPIPE error
- // would otherwise be delivered. This runtime doesn't install a SIGPIPE
- // handler, causing it to kill the program, which isn't exactly what we
- // want!
- //
- // Hence, we set SIGPIPE to ignore when the program starts up in order
- // to prevent this problem.
- unsafe {
- reset_sigpipe();
- }
+}
- // I don't think we have signal handling on the 3DS, so let's leave this
- // blank for now
- unsafe fn reset_sigpipe() {}
+pub fn unsupported<T>() -> io::Result<T> {
+ Err(unsupported_err())
+}
+
+pub fn unsupported_err() -> io::Error {
+ io::Error::new(io::ErrorKind::Other,
+ "operation not supported on 3DS yet")
}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
@@ -76,6 +83,11 @@ pub fn decode_error_kind(errno: i32) -> ErrorKind {
}
}
+// This enum is used as the storage for a bunch of types which can't actually
+// exist.
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
+pub enum Void {}
+
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
@@ -111,6 +123,13 @@ pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
}
}
+// On Unix-like platforms, libc::abort will unregister signal handlers
+// including the SIGABRT handler, preventing the abort from being blocked, and
+// fclose streams, with the side effect of flushing them so libc bufferred
+// output will be printed. Additionally the shell will generally print a more
+// understandable error message like "Abort trap" rather than "Illegal
+// instruction" that intrinsics::abort would cause, as intrinsics::abort is
+// implemented as an illegal instruction.
pub unsafe fn abort_internal() -> ! {
::libc::abort()
}
diff --git a/ctr-std/src/sys/unix/mutex.rs b/ctr-std/src/sys/unix/mutex.rs
index 0cfd392..51e6b47 100644
--- a/ctr-std/src/sys/unix/mutex.rs
+++ b/ctr-std/src/sys/unix/mutex.rs
@@ -1,4 +1,4 @@
-// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -11,7 +11,9 @@
use cell::UnsafeCell;
use mem;
-pub struct Mutex { inner: UnsafeCell<::libctru::LightLock> }
+pub struct Mutex {
+ inner: UnsafeCell<::libctru::LightLock>,
+}
#[inline]
pub unsafe fn raw(m: &Mutex) -> *mut ::libctru::LightLock {
@@ -21,23 +23,26 @@ pub unsafe fn raw(m: &Mutex) -> *mut ::libctru::LightLock {
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
-#[allow(dead_code)] // sys isn't exported yet
impl Mutex {
pub const fn new() -> Mutex {
Mutex { inner: UnsafeCell::new(0) }
}
+
#[inline]
pub unsafe fn init(&mut self) {
::libctru::LightLock_Init(self.inner.get());
}
+
#[inline]
pub unsafe fn lock(&self) {
::libctru::LightLock_Lock(self.inner.get());
}
+
#[inline]
pub unsafe fn unlock(&self) {
::libctru::LightLock_Unlock(self.inner.get());
}
+
#[inline]
pub unsafe fn try_lock(&self) -> bool {
match ::libctru::LightLock_TryLock(self.inner.get()) {
@@ -45,8 +50,10 @@ impl Mutex {
_ => false,
}
}
+
#[inline]
- pub unsafe fn destroy(&self) {}
+ pub unsafe fn destroy(&self) {
+ }
}
pub struct ReentrantMutex { inner: UnsafeCell<::libctru::RecursiveLock> }
@@ -58,18 +65,15 @@ impl ReentrantMutex {
pub unsafe fn uninitialized() -> ReentrantMutex {
ReentrantMutex { inner: mem::uninitialized() }
}
- #[inline]
+
pub unsafe fn init(&mut self) {
::libctru::RecursiveLock_Init(self.inner.get());
}
- #[inline]
+
pub unsafe fn lock(&self) {
::libctru::RecursiveLock_Lock(self.inner.get());
}
- #[inline]
- pub unsafe fn unlock(&self) {
- ::libctru::RecursiveLock_Unlock(self.inner.get());
- }
+
#[inline]
pub unsafe fn try_lock(&self) -> bool {
match ::libctru::RecursiveLock_TryLock(self.inner.get()) {
@@ -77,6 +81,10 @@ impl ReentrantMutex {
_ => false,
}
}
- #[inline]
+
+ pub unsafe fn unlock(&self) {
+ ::libctru::RecursiveLock_Unlock(self.inner.get());
+ }
+
pub unsafe fn destroy(&self) {}
}
diff --git a/ctr-std/src/sys/unix/net.rs b/ctr-std/src/sys/unix/net.rs
new file mode 100644
index 0000000..b9b1a39
--- /dev/null
+++ b/ctr-std/src/sys/unix/net.rs
@@ -0,0 +1,418 @@
+// Copyright 2015 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.
+
+#![allow(dead_code)]
+
+use ffi::CStr;
+use io;
+use libc::{self, c_int, c_void, size_t, sockaddr, socklen_t, EAI_NONAME as EAI_SYSTEM, MSG_PEEK};
+use mem;
+use net::{SocketAddr, Shutdown};
+use str;
+use sys::fd::FileDesc;
+use sys_common::{AsInner, FromInner, IntoInner};
+use sys_common::net::{getsockopt, setsockopt, sockaddr_to_addr};
+use time::{Duration, Instant};
+use cmp;
+
+pub use sys::{cvt, cvt_r};
+pub extern crate libc as netc;
+
+#[allow(non_camel_case_types)]
+pub type wrlen_t = size_t;
+
+// See below for the usage of SOCK_CLOEXEC, but this constant is only defined on
+// Linux currently (e.g. support doesn't exist on other platforms). In order to
+// get name resolution to work and things to compile we just define a dummy
+// SOCK_CLOEXEC here for other platforms. Note that the dummy constant isn't
+// actually ever used (the blocks below are wrapped in `if cfg!` as well.
+#[cfg(target_os = "linux")]
+use libc::SOCK_CLOEXEC;
+#[cfg(not(target_os = "linux"))]
+const SOCK_CLOEXEC: c_int = 0;
+
+// Another conditional contant for name resolution: Macos et iOS use
+// SO_NOSIGPIPE as a setsockopt flag to disable SIGPIPE emission on socket.
+// Other platforms do otherwise.
+#[cfg(target_vendor = "apple")]
+use libc::SO_NOSIGPIPE;
+#[cfg(not(target_vendor = "apple"))]
+const SO_NOSIGPIPE: c_int = 0;
+
+pub struct Socket(FileDesc);
+
+pub fn init() {}
+
+pub fn cvt_gai(err: c_int) -> io::Result<()> {
+ if err == 0 {
+ return Ok(())
+ }
+ if err == EAI_SYSTEM {
+ return Err(io::Error::last_os_error())
+ }
+
+ let detail = unsafe {
+ str::from_utf8(CStr::from_ptr(libc::gai_strerror(err)).to_bytes()).unwrap()
+ .to_owned()
+ };
+ Err(io::Error::new(io::ErrorKind::Other,
+ &format!("failed to lookup address information: {}",
+ detail)[..]))
+}
+
+impl Socket {
+ pub fn new(addr: &SocketAddr, ty: c_int) -> io::Result<Socket> {
+ let fam = match *addr {
+ SocketAddr::V4(..) => libc::AF_INET,
+ SocketAddr::V6(..) => libc::AF_INET6,
+ };
+ Socket::new_raw(fam, ty)
+ }
+
+ pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
+ unsafe {
+ // On linux we first attempt to pass the SOCK_CLOEXEC flag to
+ // atomically create the socket and set it as CLOEXEC. Support for
+ // this option, however, was added in 2.6.27, and we still support
+ // 2.6.18 as a kernel, so if the returned error is EINVAL we
+ // fallthrough to the fallback.
+ if cfg!(target_os = "linux") {
+ match cvt(libc::socket(fam, ty | SOCK_CLOEXEC, 0)) {
+ Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {}
+ Err(e) => return Err(e),
+ }
+ }
+
+ let fd = cvt(libc::socket(fam, ty, 0))?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ let socket = Socket(fd);
+ if cfg!(target_vendor = "apple") {
+ setsockopt(&socket, libc::SOL_SOCKET, SO_NOSIGPIPE, 1)?;
+ }
+ Ok(socket)
+ }
+ }
+
+ pub fn new_pair(fam: c_int, ty: c_int) -> io::Result<(Socket, Socket)> {
+ unsafe {
+ let mut fds = [0, 0];
+
+ // Like above, see if we can set cloexec atomically
+ if cfg!(target_os = "linux") {
+ match cvt(libc::socketpair(fam, ty | SOCK_CLOEXEC, 0, fds.as_mut_ptr())) {
+ Ok(_) => {
+ return Ok((Socket(FileDesc::new(fds[0])), Socket(FileDesc::new(fds[1]))));
+ }
+ Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {},
+ Err(e) => return Err(e),
+ }
+ }
+
+ cvt(libc::socketpair(fam, ty, 0, fds.as_mut_ptr()))?;
+ let a = FileDesc::new(fds[0]);
+ let b = FileDesc::new(fds[1]);
+ a.set_cloexec()?;
+ b.set_cloexec()?;
+ Ok((Socket(a), Socket(b)))
+ }
+ }
+
+ pub fn connect_timeout(&self, addr: &SocketAddr, timeout: Duration) -> io::Result<()> {
+ self.set_nonblocking(true)?;
+ let r = unsafe {
+ let (addrp, len) = addr.into_inner();
+ cvt(libc::connect(self.0.raw(), addrp, len))
+ };
+ self.set_nonblocking(false)?;
+
+ match r {
+ Ok(_) => return Ok(()),
+ // there's no ErrorKind for EINPROGRESS :(
+ Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
+ Err(e) => return Err(e),
+ }
+
+ let mut pollfd = libc::pollfd {
+ fd: self.0.raw(),
+ events: libc::POLLOUT,
+ revents: 0,
+ };
+
+ if timeout.as_secs() == 0 && timeout.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+
+ let start = Instant::now();
+
+ loop {
+ let elapsed = start.elapsed();
+ if elapsed >= timeout {
+ return Err(io::Error::new(io::ErrorKind::TimedOut, "connection timed out"));
+ }
+
+ let timeout = timeout - elapsed;
+ let mut timeout = timeout.as_secs()
+ .saturating_mul(1_000)
+ .saturating_add(timeout.subsec_nanos() as u64 / 1_000_000);
+ if timeout == 0 {
+ timeout = 1;
+ }
+
+ let timeout = cmp::min(timeout, c_int::max_value() as u64) as c_int;
+
+ match unsafe { libc::poll(&mut pollfd, 1, timeout) } {
+ -1 => {
+ let err = io::Error::last_os_error();
+ if err.kind() != io::ErrorKind::Interrupted {
+ return Err(err);
+ }
+ }
+ 0 => {}
+ _ => {
+ // linux returns POLLOUT|POLLERR|POLLHUP for refused connections (!), so look
+ // for POLLHUP rather than read readiness
+ if pollfd.revents & libc::POLLHUP != 0 {
+ let e = self.take_error()?
+ .unwrap_or_else(|| {
+ io::Error::new(io::ErrorKind::Other, "no error set after POLLHUP")
+ });
+ return Err(e);
+ }
+
+ return Ok(());
+ }
+ }
+ }
+ }
+
+ pub fn accept(&self, storage: *mut sockaddr, len: *mut socklen_t)
+ -> io::Result<Socket> {
+ let fd = cvt_r(|| unsafe {
+ libc::accept(self.0.raw(), storage, len)
+ })?;
+ let fd = FileDesc::new(fd);
+ fd.set_cloexec()?;
+ Ok(Socket(fd))
+ }
+
+ pub fn duplicate(&self) -> io::Result<Socket> {
+ self.0.duplicate().map(Socket)
+ }
+
+ fn recv_with_flags(&self, buf: &mut [u8], flags: c_int) -> io::Result<usize> {
+ let ret = cvt(unsafe {
+ libc::recv(self.0.raw(),
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ flags)
+ })?;
+ Ok(ret as usize)
+ }
+
+ pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, 0)
+ }
+
+ pub fn peek(&self, buf: &mut [u8]) -> io::Result<usize> {
+ self.recv_with_flags(buf, MSG_PEEK)
+ }
+
+ fn recv_from_with_flags(&self, buf: &mut [u8], flags: c_int)
+ -> io::Result<(usize, SocketAddr)> {
+ let mut storage: libc::sockaddr_storage = unsafe { mem::zeroed() };
+ let mut addrlen = mem::size_of_val(&storage) as libc::socklen_t;
+
+ let n = cvt(unsafe {
+ libc::recvfrom(self.0.raw(),
+ buf.as_mut_ptr() as *mut c_void,
+ buf.len(),
+ flags,
+ &mut storage as *mut _ as *mut _,
+ &mut addrlen)
+ })?;
+ Ok((n as usize, sockaddr_to_addr(&storage, addrlen as usize)?))
+ }
+
+ pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, 0)
+ }
+
+ pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
+ self.recv_from_with_flags(buf, MSG_PEEK)
+ }
+
+ pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
+ self.0.write(buf)
+ }
+
+ pub fn set_timeout(&self, dur: Option<Duration>, kind: libc::c_int) -> io::Result<()> {
+ let timeout = match dur {
+ Some(dur) => {
+ if dur.as_secs() == 0 && dur.subsec_nanos() == 0 {
+ return Err(io::Error::new(io::ErrorKind::InvalidInput,
+ "cannot set a 0 duration timeout"));
+ }
+
+ let secs = if dur.as_secs() > libc::time_t::max_value() as u64 {
+ libc::time_t::max_value()
+ } else {
+ dur.as_secs() as libc::time_t
+ };
+ let mut timeout = libc::timeval {
+ tv_sec: secs,
+ tv_usec: (dur.subsec_nanos() / 1000) as libc::suseconds_t,
+ };
+ if timeout.tv_sec == 0 && timeout.tv_usec == 0 {
+ timeout.tv_usec = 1;
+ }
+ timeout
+ }
+ None => {
+ libc::timeval {
+ tv_sec: 0,
+ tv_usec: 0,
+ }
+ }
+ };
+ setsockopt(self, libc::SOL_SOCKET, kind, timeout)
+ }
+
+ pub fn timeout(&self, kind: libc::c_int) -> io::Result<Option<Duration>> {
+ let raw: libc::timeval = getsockopt(self, libc::SOL_SOCKET, kind)?;
+ if raw.tv_sec == 0 && raw.tv_usec == 0 {
+ Ok(None)
+ } else {
+ let sec = raw.tv_sec as u64;
+ let nsec = (raw.tv_usec as u32) * 1000;
+ Ok(Some(Duration::new(sec, nsec)))
+ }
+ }
+
+ pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
+ let how = match how {
+ Shutdown::Write => libc::SHUT_WR,
+ Shutdown::Read => libc::SHUT_RD,
+ Shutdown::Both => libc::SHUT_RDWR,
+ };
+ cvt(unsafe { libc::shutdown(self.0.raw(), how) })?;
+ Ok(())
+ }
+
+ pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
+ setsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY, nodelay as c_int)
+ }
+
+ pub fn nodelay(&self) -> io::Result<bool> {
+ let raw: c_int = getsockopt(self, libc::IPPROTO_TCP, libc::TCP_NODELAY)?;
+ Ok(raw != 0)
+ }
+
+ // TODO: Fix libc::FIONBIO and remove explicit cast
+ 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(|_| ())
+ }
+
+ pub fn take_error(&self) -> io::Result<Option<io::Error>> {
+ let raw: c_int = getsockopt(self, libc::SOL_SOCKET, libc::SO_ERROR)?;
+ if raw == 0 {
+ Ok(None)
+ } else {
+ Ok(Some(io::Error::from_raw_os_error(raw as i32)))
+ }
+ }
+}
+
+impl AsInner<c_int> for Socket {
+ fn as_inner(&self) -> &c_int { self.0.as_inner() }
+}
+
+impl FromInner<c_int> for Socket {
+ fn from_inner(fd: c_int) -> Socket { Socket(FileDesc::new(fd)) }
+}
+
+impl IntoInner<c_int> for Socket {
+ fn into_inner(self) -> c_int { self.0.into_raw() }
+}
+
+// In versions of glibc prior to 2.26, there's a bug where the DNS resolver
+// will cache the contents of /etc/resolv.conf, so changes to that file on disk
+// can be ignored by a long-running program. That can break DNS lookups on e.g.
+// laptops where the network comes and goes. See
+// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some
+// distros including Debian have patched glibc to fix this for a long time.
+//
+// A workaround for this bug is to call the res_init libc function, to clear
+// the cached configs. Unfortunately, while we believe glibc's implementation
+// of res_init is thread-safe, we know that other implementations are not
+// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could
+// try to synchronize its res_init calls with a Mutex, but that wouldn't
+// protect programs that call into libc in other ways. So instead of calling
+// res_init unconditionally, we call it only when we detect we're linking
+// against glibc version < 2.26. (That is, when we both know its needed and
+// believe it's thread-safe).
+pub fn res_init_if_glibc_before_2_26() -> io::Result<()> {
+ // If the version fails to parse, we treat it the same as "not glibc".
+ if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) {
+ if let Some(version) = parse_glibc_version(version_str) {
+ if version < (2, 26) {
+ let ret = unsafe { libc::res_init() };
+ if ret != 0 {
+ return Err(io::Error::last_os_error());
+ }
+ }
+ }
+ }
+ Ok(())
+}
+
+fn glibc_version_cstr() -> Option<&'static CStr> {
+ None
+}
+
+// Returns Some((major, minor)) if the string is a valid "x.y" version,
+// ignoring any extra dot-separated parts. Otherwise return None.
+fn parse_glibc_version(version: &str) -> Option<(usize, usize)> {
+ 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
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_res_init() {
+ // This mostly just tests that the weak linkage doesn't panic wildly...
+ res_init_if_glibc_before_2_26().unwrap();
+ }
+
+ #[test]
+ fn test_parse_glibc_version() {
+ let cases = [
+ ("0.0", Some((0, 0))),
+ ("01.+2", Some((1, 2))),
+ ("3.4.5.six", Some((3, 4))),
+ ("1", None),
+ ("1.-2", None),
+ ("1.foo", None),
+ ("foo.1", None),
+ ];
+ for &(version_str, parsed) in cases.iter() {
+ assert_eq!(parsed, parse_glibc_version(version_str));
+ }
+ }
+}
diff --git a/ctr-std/src/sys/unix/os.rs b/ctr-std/src/sys/unix/os.rs
index de087d9..5de756d 100644
--- a/ctr-std/src/sys/unix/os.rs
+++ b/ctr-std/src/sys/unix/os.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -8,26 +8,17 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-//! Implementation of `std::os` functionality for unix systems
-
-#![allow(unused_imports)] // lots of cfg code here
-
-use os::unix::prelude::*;
-
use error::Error as StdError;
use ffi::{CString, CStr, OsString, OsStr};
use fmt;
use io;
use iter;
-use libc::{self, c_int, c_char, c_void};
-use marker::PhantomData;
-use mem;
-use memchr;
+use libc::{self, c_int, c_char};
use path::{self, PathBuf};
-use ptr;
use slice;
use str;
-use vec;
+use sys::{unsupported, Void};
+use sys::unix::ext::ffi::{OsStrExt, OsStringExt};
const TMPBUF_SZ: usize = 128;
@@ -64,6 +55,42 @@ pub fn error_string(errno: i32) -> String {
}
}
+pub fn getcwd() -> io::Result<PathBuf> {
+ let mut buf = Vec::with_capacity(512);
+ loop {
+ unsafe {
+ let ptr = buf.as_mut_ptr() as *mut libc::c_char;
+ if !libc::getcwd(ptr, buf.capacity()).is_null() {
+ let len = CStr::from_ptr(buf.as_ptr() as *const libc::c_char).to_bytes().len();
+ buf.set_len(len);
+ buf.shrink_to_fit();
+ return Ok(PathBuf::from(OsString::from_vec(buf)));
+ } else {
+ let error = io::Error::last_os_error();
+ if error.raw_os_error() != Some(libc::ERANGE) {
+ return Err(error);
+ }
+ }
+
+ // Trigger the internal buffer resizing logic of `Vec` by requiring
+ // more space than the current capacity.
+ let cap = buf.capacity();
+ buf.set_len(cap);
+ buf.reserve(1);
+ }
+ }
+}
+
+pub fn chdir(p: &path::Path) -> io::Result<()> {
+ let p: &OsStr = p.as_ref();
+ let p = CString::new(p.as_bytes())?;
+ unsafe {
+ match libc::chdir(p.as_ptr()) == (0 as c_int) {
+ true => Ok(()),
+ false => Err(io::Error::last_os_error()),
+ }
+ }
+}
pub struct SplitPaths<'a> {
iter: iter::Map<slice::Split<'a, u8, fn(&u8) -> bool>,
@@ -118,6 +145,47 @@ impl StdError for JoinPathsError {
fn description(&self) -> &str { "failed to join paths" }
}
+pub fn current_exe() -> io::Result<PathBuf> {
+ unsupported()
+}
+
+pub struct Env(Void);
+
+impl Iterator for Env {
+ type Item = (OsString, OsString);
+ fn next(&mut self) -> Option<(OsString, OsString)> {
+ match self.0 {}
+ }
+}
+
+pub fn env() -> Env {
+ panic!("not supported on 3DS yet")
+}
+
+pub fn getenv(_k: &OsStr) -> io::Result<Option<OsString>> {
+ return Ok(None)
+}
+
+pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn unsetenv(_n: &OsStr) -> io::Result<()> {
+ unsupported()
+}
+
+pub fn temp_dir() -> PathBuf {
+ PathBuf::from("/tmp")
+}
+
+pub fn home_dir() -> Option<PathBuf> {
+ None
+}
+
pub fn exit(code: i32) -> ! {
unsafe { libc::exit(code as c_int) }
}
+
+pub fn getpid() -> u32 {
+ panic!("no pids on 3DS")
+}
diff --git a/ctr-std/src/sys/unix/os_str.rs b/ctr-std/src/sys/unix/os_str.rs
index 5a733c0..543c22e 100644
--- a/ctr-std/src/sys/unix/os_str.rs
+++ b/ctr-std/src/sys/unix/os_str.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -12,10 +12,14 @@
/// a `Vec<u8>`/`[u8]`.
use borrow::Cow;
-use fmt::{self, Debug};
+use fmt;
use str;
use mem;
+use rc::Rc;
+use sync::Arc;
use sys_common::{AsInner, IntoInner};
+use sys_common::bytestring::debug_fmt_bytestring;
+use std_unicode::lossy::Utf8Lossy;
#[derive(Clone, Hash)]
pub struct Buf {
@@ -26,15 +30,27 @@ pub struct Slice {
pub inner: [u8]
}
-impl Debug for Slice {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- self.to_string_lossy().fmt(formatter)
+impl fmt::Debug for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ debug_fmt_bytestring(&self.inner, formatter)
}
}
-impl Debug for Buf {
- fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> {
- self.as_slice().fmt(formatter)
+impl fmt::Display for Slice {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(&Utf8Lossy::from_bytes(&self.inner), formatter)
+ }
+}
+
+impl fmt::Debug for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Debug::fmt(self.as_slice(), formatter)
+ }
+}
+
+impl fmt::Display for Buf {
+ fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
+ fmt::Display::fmt(self.as_slice(), formatter)
}
}
@@ -83,6 +99,11 @@ impl Buf {
self.inner.reserve_exact(additional)
}
+ #[inline]
+ pub fn shrink_to_fit(&mut self) {
+ self.inner.shrink_to_fit()
+ }
+
pub fn as_slice(&self) -> &Slice {
unsafe { mem::transmute(&*self.inner) }
}
@@ -94,6 +115,27 @@ impl Buf {
pub fn push_slice(&mut self, s: &Slice) {
self.inner.extend_from_slice(&s.inner)
}
+
+ #[inline]
+ pub fn into_box(self) -> Box<Slice> {
+ unsafe { mem::transmute(self.inner.into_boxed_slice()) }
+ }
+
+ #[inline]
+ pub fn from_box(boxed: Box<Slice>) -> Buf {
+ let inner: Box<[u8]> = unsafe { mem::transmute(boxed) };
+ Buf { inner: inner.into_vec() }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ self.as_slice().into_arc()
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ self.as_slice().into_rc()
+ }
}
impl Slice {
@@ -116,4 +158,27 @@ impl Slice {
pub fn to_owned(&self) -> Buf {
Buf { inner: self.inner.to_vec() }
}
+
+ #[inline]
+ pub fn into_box(&self) -> Box<Slice> {
+ let boxed: Box<[u8]> = self.inner.into();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ pub fn empty_box() -> Box<Slice> {
+ let boxed: Box<[u8]> = Default::default();
+ unsafe { mem::transmute(boxed) }
+ }
+
+ #[inline]
+ pub fn into_arc(&self) -> Arc<Slice> {
+ let arc: Arc<[u8]> = Arc::from(&self.inner);
+ unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) }
+ }
+
+ #[inline]
+ pub fn into_rc(&self) -> Rc<Slice> {
+ let rc: Rc<[u8]> = Rc::from(&self.inner);
+ unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) }
+ }
}
diff --git a/ctr-std/src/sys/unix/path.rs b/ctr-std/src/sys/unix/path.rs
index bf9af7a..395b8c1 100644
--- a/ctr-std/src/sys/unix/path.rs
+++ b/ctr-std/src/sys/unix/path.rs
@@ -1,4 +1,4 @@
-// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
diff --git a/ctr-std/src/sys/unix/pipe.rs b/ctr-std/src/sys/unix/pipe.rs
new file mode 100644
index 0000000..992e1ac
--- /dev/null
+++ b/ctr-std/src/sys/unix/pipe.rs
@@ -0,0 +1,35 @@
+// Copyright 2017 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.
+
+use io;
+use sys::Void;
+
+pub struct AnonPipe(Void);
+
+impl AnonPipe {
+ pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn write(&self, _buf: &[u8]) -> io::Result<usize> {
+ match self.0 {}
+ }
+
+ pub fn diverge(&self) -> ! {
+ match self.0 {}
+ }
+}
+
+pub fn read2(p1: AnonPipe,
+ _v1: &mut Vec<u8>,
+ _p2: AnonPipe,
+ _v2: &mut Vec<u8>) -> io::Result<()> {
+ match p1.0 {}
+}
diff --git a/ctr-std/src/sys/unix/process.rs b/ctr-std/src/sys/unix/process.rs
new file mode 100644
index 0000000..f058aa9
--- /dev/null
+++ b/ctr-std/src/sys/unix/process.rs
@@ -0,0 +1,151 @@
+// Copyright 2017 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.
+
+use ffi::OsStr;
+use fmt;
+use io;
+use sys::fs::File;
+use sys::pipe::AnonPipe;
+use sys::{unsupported, Void};
+use sys_common::process::{CommandEnv, DefaultEnvKey};
+
+////////////////////////////////////////////////////////////////////////////////
+// Command
+////////////////////////////////////////////////////////////////////////////////
+
+pub struct Command {
+ env: CommandEnv<DefaultEnvKey>
+}
+
+// passed back to std::process with the pipes connected to the child, if any
+// were requested
+pub struct StdioPipes {
+ pub stdin: Option<AnonPipe>,
+ pub stdout: Option<AnonPipe>,
+ pub stderr: Option<AnonPipe>,
+}
+
+pub enum Stdio {
+ Inherit,
+ Null,
+ MakePipe,
+}
+
+impl Command {
+ pub fn new(_program: &OsStr) -> Command {
+ Command {
+ env: Default::default()
+ }
+ }
+
+ pub fn arg(&mut self, _arg: &OsStr) {
+ }
+
+ pub fn env_mut(&mut self) -> &mut CommandEnv<DefaultEnvKey> {
+ &mut self.env
+ }
+
+ pub fn cwd(&mut self, _dir: &OsStr) {
+ }
+
+ pub fn stdin(&mut self, _stdin: Stdio) {
+ }
+
+ pub fn stdout(&mut self, _stdout: Stdio) {
+ }
+
+ pub fn stderr(&mut self, _stderr: Stdio) {
+ }
+
+ pub fn spawn(&mut self, _default: Stdio, _needs_stdin: bool)
+ -> io::Result<(Process, StdioPipes)> {
+ unsupported()
+ }
+}
+
+impl From<AnonPipe> for Stdio {
+ fn from(pipe: AnonPipe) -> Stdio {
+ pipe.diverge()
+ }
+}
+
+impl From<File> for Stdio {
+ fn from(_file: File) -> Stdio {
+ //file.diverge()
+ unimplemented!()
+ }
+}
+
+impl fmt::Debug for Command {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ Ok(())
+ }
+}
+
+pub struct ExitStatus(Void);
+
+impl ExitStatus {
+ pub fn success(&self) -> bool {
+ match self.0 {}
+ }
+
+ pub fn code(&self) -> Option<i32> {
+ match self.0 {}
+ }
+}
+
+impl Clone for ExitStatus {
+ fn clone(&self) -> ExitStatus {
+ match self.0 {}
+ }
+}
+
+impl Copy for ExitStatus {}
+
+impl PartialEq for ExitStatus {
+ fn eq(&self, _other: &ExitStatus) -> bool {
+ match self.0 {}
+ }
+}
+
+impl Eq for ExitStatus {
+}
+
+impl fmt::Debug for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+impl fmt::Display for ExitStatus {
+ fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
+ match self.0 {}
+ }
+}
+
+pub struct Process(Void);
+
+impl Process {
+ pub fn id(&self) -> u32 {
+ match self.0 {}
+ }
+
+ pub fn kill(&mut self) -> io::Result<()> {
+ match self.0 {}
+ }
+
+ pub fn wait(&mut self) -> io::Result<ExitStatus> {
+ match self.0 {}
+ }
+
+ pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> {
+ match self.0 {}
+ }
+}
diff --git a/ctr-std/src/sys/unix/stack_overflow.rs b/ctr-std/src/sys/unix/stack_overflow.rs
new file mode 100644
index 0000000..bed2741
--- /dev/null
+++ b/ctr-std/src/sys/unix/stack_overflow.rs
@@ -0,0 +1,23 @@
+// Copyright 2017 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.
+
+pub struct Handler;
+
+impl Handler {
+ pub unsafe fn new() -> Handler {
+ Handler
+ }
+}
+
+pub unsafe fn init() {
+}
+
+pub unsafe fn cleanup() {
+}
diff --git a/ctr-std/src/sys/unix/stdio.rs b/ctr-std/src/sys/unix/stdio.rs
index 6d38b00..e9b3d4a 100644
--- a/ctr-std/src/sys/unix/stdio.rs
+++ b/ctr-std/src/sys/unix/stdio.rs
@@ -25,13 +25,6 @@ impl Stdin {
fd.into_raw();
ret
}
-
- pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
- let fd = FileDesc::new(libc::STDIN_FILENO);
- let ret = fd.read_to_end(buf);
- fd.into_raw();
- ret
- }
}
impl Stdout {
@@ -77,5 +70,8 @@ impl io::Write for Stderr {
}
}
-pub const EBADF_ERR: i32 = ::libc::EBADF as i32;
+pub fn is_ebadf(err: &io::Error) -> bool {
+ err.raw_os_error() == Some(libc::EBADF as i32)
+}
+
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
diff --git a/ctr-std/src/sys/unix/thread.rs b/ctr-std/src/sys/unix/thread.rs
index 0b21bff..21224ad 100644
--- a/ctr-std/src/sys/unix/thread.rs
+++ b/ctr-std/src/sys/unix/thread.rs
@@ -1,4 +1,4 @@
-// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
@@ -18,29 +18,28 @@ use ptr;
use sys_common::thread::start_thread;
use time::Duration;
-use libctru::{svcSleepThread, svcGetThreadPriority,
- threadCreate, threadJoin, threadFree, threadDetach,
- Thread as ThreadHandle};
+use libctru::Thread as ThreadHandle;
pub struct Thread {
handle: ThreadHandle,
}
-// Some platforms may have pthread_t as a pointer in which case we still want
-// a thread to be Send/Sync
unsafe impl Send for Thread {}
unsafe impl Sync for Thread {}
+pub const DEFAULT_MIN_STACK_SIZE: usize = 4096;
+
+
impl Thread {
pub unsafe fn new<'a>(stack: usize, p: Box<FnBox() + 'a>) -> io::Result<Thread> {
let p = box p;
- let stack_size = cmp::max(stack, 0x10000);
+ let stack_size = cmp::max(stack, DEFAULT_MIN_STACK_SIZE);
let mut priority = 0;
- svcGetThreadPriority(&mut priority, 0xFFFF8000);
+ ::libctru::svcGetThreadPriority(&mut priority, 0xFFFF8000);
- let handle = threadCreate(Some(thread_func), &*p as *const _ as *mut _,
- stack_size, priority, -2, false);
+ let handle = ::libctru::threadCreate(Some(thread_func), &*p as *const _ as *mut _,
+ stack_size, priority, -2, false);
return if handle == ptr::null_mut() {
Err(io::Error::from_raw_os_error(libc::EAGAIN))
@@ -50,12 +49,14 @@ impl Thread {
};
extern "C" fn thread_func(start: *mut libc::c_void) {
- unsafe { start_thread(start) }
+ unsafe { start_thread(start as *mut u8) }
}
}
-
+
pub fn yield_now() {
- unsafe { svcSleepThread(0) }
+ unsafe {
+ ::libctru::svcSleepThread(0)
+ }
}
pub fn set_name(_name: &CStr) {
@@ -64,35 +65,21 @@ impl Thread {
pub fn sleep(dur: Duration) {
unsafe {
- let nanos = dur.as_secs() * 1_000_000_000 + dur.subsec_nanos() as u64;
- svcSleepThread(nanos as i64)
+ let nanos = dur.as_secs()
+ .saturating_mul(1_000_000_000)
+ .saturating_add(dur.subsec_nanos() as u64);
+ ::libctru::svcSleepThread(nanos as i64)
}
}
pub fn join(self) {
unsafe {
- let ret = threadJoin(self.handle, u64::max_value());
- threadFree(self.handle);
+ let ret = ::libctru::threadJoin(self.handle, u64::max_value());
+ ::libctru::threadFree(self.handle);
mem::forget(self);
debug_assert_eq!(ret, 0);
}
}
-
- pub fn id(&self) -> ThreadHandle {
- self.handle
- }
-
- pub fn into_id(self) -> ThreadHandle {
- let handle = self.handle;
- mem::forget(self);
- handle
- }
-}
-
-impl Drop for Thread {
- fn drop(&mut self) {
- unsafe { threadDetach(self.handle) }
- }
}
pub mod guard {
diff --git a/ctr-std/src/sys/unix/thread_local.rs b/ctr-std/src/sys/unix/thread_local.rs
index abdd9ac..3cb3523 100644
--- a/ctr-std/src/sys/unix/thread_local.rs
+++ b/ctr-std/src/sys/unix/thread_local.rs
@@ -8,6 +8,8 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
+// Borrowed from /sys/redox/thread_local.rs
+
#![allow(dead_code)] // not used on all platforms
use collections::BTreeMap;
@@ -64,3 +66,8 @@ pub unsafe fn set(key: Key, value: *mut u8) {
pub unsafe fn destroy(key: Key) {
keys().remove(&key);
}
+
+#[inline]
+pub fn requires_synchronized_create() -> bool {
+ false
+}
diff --git a/ctr-std/src/sys/unix/time.rs b/ctr-std/src/sys/unix/time.rs
index 3bc1dca..d5dcbc4 100644
--- a/ctr-std/src/sys/unix/time.rs
+++ b/ctr-std/src/sys/unix/time.rs
@@ -11,6 +11,7 @@
use cmp::Ordering;
use libc;
use time::Duration;
+use core::hash::{Hash, Hasher};
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
@@ -103,6 +104,13 @@ impl Ord for Timespec {
}
}
+impl Hash for Timespec {
+ fn hash<H : Hasher>(&self, state: &mut H) {
+ self.t.tv_sec.hash(state);
+ self.t.tv_nsec.hash(state);
+ }
+}
+
mod inner {
use fmt;
use libc;
@@ -116,12 +124,12 @@ mod inner {
use libctru;
- #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant {
t: u64
}
- #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
+ #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SystemTime {
t: Timespec,
}