Browse Source

Update for latest nightly 2018-06-09 (#70)

* Update for latest nightly 2018-06-09
* We now have a proper horizon os and sys modules in libstd
pull/10/head
Valentin 7 years ago committed by FenrirWolf
parent
commit
f2a90174bb
  1. 2
      .travis.yml
  2. 113
      ctr-std/src/alloc.rs
  3. 137
      ctr-std/src/build.rs
  4. 60
      ctr-std/src/collections/hash/map.rs
  5. 166
      ctr-std/src/collections/hash/table.rs
  6. 8
      ctr-std/src/collections/mod.rs
  7. 33
      ctr-std/src/env.rs
  8. 98
      ctr-std/src/f32.rs
  9. 98
      ctr-std/src/f64.rs
  10. 129
      ctr-std/src/ffi/c_str.rs
  11. 32
      ctr-std/src/ffi/os_str.rs
  12. 14
      ctr-std/src/fs.rs
  13. 29
      ctr-std/src/lib.rs
  14. 17
      ctr-std/src/macros.rs
  15. 8
      ctr-std/src/num.rs
  16. 393
      ctr-std/src/os/horizon/fs.rs
  17. 16
      ctr-std/src/os/horizon/mod.rs
  18. 275
      ctr-std/src/os/horizon/raw.rs
  19. 1
      ctr-std/src/os/mod.rs
  20. 113
      ctr-std/src/panicking.rs
  21. 28
      ctr-std/src/path.rs
  22. 77
      ctr-std/src/primitive_docs.rs
  23. 8
      ctr-std/src/process.rs
  24. 2
      ctr-std/src/sync/mutex.rs
  25. 23
      ctr-std/src/sync/once.rs
  26. 4
      ctr-std/src/sync/rwlock.rs
  27. 51
      ctr-std/src/sys/cloudabi/abi/bitflags.rs
  28. 2847
      ctr-std/src/sys/cloudabi/abi/cloudabi.rs
  29. 13
      ctr-std/src/sys/cloudabi/abi/mod.rs
  30. 17
      ctr-std/src/sys/cloudabi/args.rs
  31. 122
      ctr-std/src/sys/cloudabi/backtrace.rs
  32. 169
      ctr-std/src/sys/cloudabi/condvar.rs
  33. 76
      ctr-std/src/sys/cloudabi/mod.rs
  34. 158
      ctr-std/src/sys/cloudabi/mutex.rs
  35. 37
      ctr-std/src/sys/cloudabi/os.rs
  36. 237
      ctr-std/src/sys/cloudabi/rwlock.rs
  37. 45
      ctr-std/src/sys/cloudabi/shims/args.rs
  38. 19
      ctr-std/src/sys/cloudabi/shims/env.rs
  39. 302
      ctr-std/src/sys/cloudabi/shims/fs.rs
  40. 32
      ctr-std/src/sys/cloudabi/shims/mod.rs
  41. 296
      ctr-std/src/sys/cloudabi/shims/net.rs
  42. 95
      ctr-std/src/sys/cloudabi/shims/os.rs
  43. 32
      ctr-std/src/sys/cloudabi/shims/pipe.rs
  44. 159
      ctr-std/src/sys/cloudabi/shims/process.rs
  45. 23
      ctr-std/src/sys/cloudabi/stack_overflow.rs
  46. 83
      ctr-std/src/sys/cloudabi/stdio.rs
  47. 126
      ctr-std/src/sys/cloudabi/thread.rs
  48. 111
      ctr-std/src/sys/cloudabi/time.rs
  49. 170
      ctr-std/src/sys/horizon/android.rs
  50. 60
      ctr-std/src/sys/horizon/args.rs
  51. 119
      ctr-std/src/sys/horizon/backtrace/mod.rs
  52. 45
      ctr-std/src/sys/horizon/backtrace/printing/dladdr.rs
  53. 43
      ctr-std/src/sys/horizon/backtrace/printing/mod.rs
  54. 49
      ctr-std/src/sys/horizon/backtrace/tracing/backtrace_fn.rs
  55. 107
      ctr-std/src/sys/horizon/backtrace/tracing/gcc_s.rs
  56. 18
      ctr-std/src/sys/horizon/backtrace/tracing/mod.rs
  57. 43
      ctr-std/src/sys/horizon/cmath.rs
  58. 139
      ctr-std/src/sys/horizon/condvar.rs
  59. 185
      ctr-std/src/sys/horizon/env.rs
  60. 119
      ctr-std/src/sys/horizon/ext/ffi.rs
  61. 736
      ctr-std/src/sys/horizon/ext/fs.rs
  62. 108
      ctr-std/src/sys/horizon/ext/io.rs
  63. 59
      ctr-std/src/sys/horizon/ext/mod.rs
  64. 33
      ctr-std/src/sys/horizon/ext/raw.rs
  65. 77
      ctr-std/src/sys/horizon/fast_thread_local.rs
  66. 265
      ctr-std/src/sys/horizon/fd.rs
  67. 928
      ctr-std/src/sys/horizon/fs.rs
  68. 441
      ctr-std/src/sys/horizon/l4re.rs
  69. 57
      ctr-std/src/sys/horizon/memchr.rs
  70. 179
      ctr-std/src/sys/horizon/mod.rs
  71. 90
      ctr-std/src/sys/horizon/mutex.rs
  72. 428
      ctr-std/src/sys/horizon/net.rs
  73. 191
      ctr-std/src/sys/horizon/os.rs
  74. 189
      ctr-std/src/sys/horizon/os_str.rs
  75. 29
      ctr-std/src/sys/horizon/path.rs
  76. 137
      ctr-std/src/sys/horizon/pipe.rs
  77. 151
      ctr-std/src/sys/horizon/process.rs
  78. 241
      ctr-std/src/sys/horizon/rand.rs
  79. 127
      ctr-std/src/sys/horizon/rwlock.rs
  80. 220
      ctr-std/src/sys/horizon/stack_overflow.rs
  81. 81
      ctr-std/src/sys/horizon/stdio.rs
  82. 106
      ctr-std/src/sys/horizon/thread.rs
  83. 71
      ctr-std/src/sys/horizon/thread_local.rs
  84. 285
      ctr-std/src/sys/horizon/time.rs
  85. 79
      ctr-std/src/sys/horizon/weak.rs
  86. 17
      ctr-std/src/sys/mod.rs
  87. 111
      ctr-std/src/sys/redox/args.rs
  88. 42
      ctr-std/src/sys/redox/backtrace/mod.rs
  89. 11
      ctr-std/src/sys/redox/backtrace/printing.rs
  90. 107
      ctr-std/src/sys/redox/backtrace/tracing.rs
  91. 43
      ctr-std/src/sys/redox/cmath.rs
  92. 121
      ctr-std/src/sys/redox/condvar.rs
  93. 19
      ctr-std/src/sys/redox/env.rs
  94. 65
      ctr-std/src/sys/redox/ext/ffi.rs
  95. 349
      ctr-std/src/sys/redox/ext/fs.rs
  96. 167
      ctr-std/src/sys/redox/ext/io.rs
  97. 54
      ctr-std/src/sys/redox/ext/mod.rs
  98. 187
      ctr-std/src/sys/redox/ext/process.rs
  99. 49
      ctr-std/src/sys/redox/ext/thread.rs
  100. 121
      ctr-std/src/sys/redox/fast_thread_local.rs
  101. Some files were not shown because too many files have changed in this diff Show More

2
.travis.yml

@ -1,7 +1,7 @@
language: rust language: rust
rust: rust:
- nightly-2018-05-06 - nightly-2018-06-09
- nightly - nightly
matrix: matrix:

113
ctr-std/src/alloc.rs

@ -13,16 +13,61 @@
#![unstable(issue = "32838", feature = "allocator_api")] #![unstable(issue = "32838", feature = "allocator_api")]
#[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap; #[doc(inline)] #[allow(deprecated)] pub use alloc_crate::alloc::Heap;
#[doc(inline)] pub use alloc_crate::alloc::{Global, oom}; #[doc(inline)] pub use alloc_crate::alloc::{Global, Layout, oom};
#[doc(inline)] pub use alloc_system::System; #[doc(inline)] pub use alloc_system::System;
#[doc(inline)] pub use core::alloc::*; #[doc(inline)] pub use core::alloc::*;
#[cfg(not(stage0))] use core::sync::atomic::{AtomicPtr, Ordering};
use core::{mem, ptr};
use sys_common::util::dumb_print;
static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
/// Registers a custom OOM hook, replacing any that was previously registered.
///
/// The OOM hook is invoked when an infallible memory allocation fails, before
/// the runtime aborts. The default hook prints a message to standard error,
/// but this behavior can be customized with the [`set_oom_hook`] and
/// [`take_oom_hook`] functions.
///
/// The hook is provided with a `Layout` struct which contains information
/// about the allocation that failed.
///
/// The OOM hook is a global resource.
pub fn set_oom_hook(hook: fn(Layout)) {
HOOK.store(hook as *mut (), Ordering::SeqCst);
}
/// Unregisters the current OOM hook, returning it.
///
/// *See also the function [`set_oom_hook`].*
///
/// If no custom hook is registered, the default hook will be returned.
pub fn take_oom_hook() -> fn(Layout) {
let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
if hook.is_null() {
default_oom_hook
} else {
unsafe { mem::transmute(hook) }
}
}
fn default_oom_hook(layout: Layout) {
dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
}
#[cfg(not(test))] #[cfg(not(test))]
#[doc(hidden)] #[doc(hidden)]
#[lang = "oom"] #[lang = "oom"]
pub extern fn rust_oom() -> ! { pub extern fn rust_oom(layout: Layout) -> ! {
rtabort!("memory allocation failed"); let hook = HOOK.load(Ordering::SeqCst);
let hook: fn(Layout) = if hook.is_null() {
default_oom_hook
} else {
unsafe { mem::transmute(hook) }
};
hook(layout);
unsafe { ::sys::abort_internal(); }
} }
#[cfg(not(test))] #[cfg(not(test))]
@ -43,13 +88,6 @@ pub mod __default_lib_allocator {
System.alloc(layout) as *mut u8 System.alloc(layout) as *mut u8
} }
#[cfg(stage0)]
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_oom() -> ! {
super::oom()
}
#[no_mangle] #[no_mangle]
#[rustc_std_internal_symbol] #[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_dealloc(ptr: *mut u8, pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
@ -74,57 +112,4 @@ pub mod __default_lib_allocator {
let layout = Layout::from_size_align_unchecked(size, align); let layout = Layout::from_size_align_unchecked(size, align);
System.alloc_zeroed(layout) as *mut u8 System.alloc_zeroed(layout) as *mut u8
} }
#[cfg(stage0)]
pub mod stage0 {
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_usable_size(_layout: *const u8,
_min: *mut usize,
_max: *mut usize) {
unimplemented!()
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_alloc_excess(_size: usize,
_align: usize,
_excess: *mut usize,
_err: *mut u8) -> *mut u8 {
unimplemented!()
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_realloc_excess(_ptr: *mut u8,
_old_size: usize,
_old_align: usize,
_new_size: usize,
_new_align: usize,
_excess: *mut usize,
_err: *mut u8) -> *mut u8 {
unimplemented!()
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_grow_in_place(_ptr: *mut u8,
_old_size: usize,
_old_align: usize,
_new_size: usize,
_new_align: usize) -> u8 {
unimplemented!()
}
#[no_mangle]
#[rustc_std_internal_symbol]
pub unsafe extern fn __rdl_shrink_in_place(_ptr: *mut u8,
_old_size: usize,
_old_align: usize,
_new_size: usize,
_new_align: usize) -> u8 {
unimplemented!()
}
}
} }

137
ctr-std/src/build.rs

@ -0,0 +1,137 @@
// 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.
#![deny(warnings)]
extern crate build_helper;
extern crate cc;
use build_helper::native_lib_boilerplate;
use std::env;
use std::fs::File;
fn main() {
let target = env::var("TARGET").expect("TARGET was not set");
if cfg!(feature = "backtrace") &&
!target.contains("cloudabi") &&
!target.contains("emscripten") &&
!target.contains("fuchsia") &&
!target.contains("msvc") &&
!target.contains("wasm32")
{
let _ = build_libbacktrace(&target);
}
if target.contains("linux") {
if target.contains("android") {
println!("cargo:rustc-link-lib=dl");
println!("cargo:rustc-link-lib=log");
println!("cargo:rustc-link-lib=gcc");
} else if !target.contains("musl") {
println!("cargo:rustc-link-lib=dl");
println!("cargo:rustc-link-lib=rt");
println!("cargo:rustc-link-lib=pthread");
}
} else if target.contains("freebsd") {
println!("cargo:rustc-link-lib=execinfo");
println!("cargo:rustc-link-lib=pthread");
} else if target.contains("dragonfly") || target.contains("bitrig") ||
target.contains("netbsd") || target.contains("openbsd") {
println!("cargo:rustc-link-lib=pthread");
} else if target.contains("solaris") {
println!("cargo:rustc-link-lib=socket");
println!("cargo:rustc-link-lib=posix4");
println!("cargo:rustc-link-lib=pthread");
println!("cargo:rustc-link-lib=resolv");
} else if target.contains("apple-darwin") {
println!("cargo:rustc-link-lib=System");
// res_init and friends require -lresolv on macOS/iOS.
// See #41582 and http://blog.achernya.com/2013/03/os-x-has-silly-libsystem.html
println!("cargo:rustc-link-lib=resolv");
} else if target.contains("apple-ios") {
println!("cargo:rustc-link-lib=System");
println!("cargo:rustc-link-lib=objc");
println!("cargo:rustc-link-lib=framework=Security");
println!("cargo:rustc-link-lib=framework=Foundation");
println!("cargo:rustc-link-lib=resolv");
} else if target.contains("windows") {
println!("cargo:rustc-link-lib=advapi32");
println!("cargo:rustc-link-lib=ws2_32");
println!("cargo:rustc-link-lib=userenv");
println!("cargo:rustc-link-lib=shell32");
} else if target.contains("fuchsia") {
// use system-provided libbacktrace
if cfg!(feature = "backtrace") {
println!("cargo:rustc-link-lib=backtrace");
}
println!("cargo:rustc-link-lib=zircon");
println!("cargo:rustc-link-lib=fdio");
} else if target.contains("cloudabi") {
if cfg!(feature = "backtrace") {
println!("cargo:rustc-link-lib=unwind");
}
println!("cargo:rustc-link-lib=c");
println!("cargo:rustc-link-lib=compiler_rt");
}
}
fn build_libbacktrace(target: &str) -> Result<(), ()> {
let native = native_lib_boilerplate("libbacktrace", "libbacktrace", "backtrace", "")?;
let mut build = cc::Build::new();
build
.flag("-fvisibility=hidden")
.include("../libbacktrace")
.include(&native.out_dir)
.out_dir(&native.out_dir)
.warnings(false)
.file("../libbacktrace/alloc.c")
.file("../libbacktrace/backtrace.c")
.file("../libbacktrace/dwarf.c")
.file("../libbacktrace/fileline.c")
.file("../libbacktrace/posix.c")
.file("../libbacktrace/read.c")
.file("../libbacktrace/sort.c")
.file("../libbacktrace/state.c");
if target.contains("darwin") {
build.file("../libbacktrace/macho.c");
} else if target.contains("windows") {
build.file("../libbacktrace/pecoff.c");
} else {
build.file("../libbacktrace/elf.c");
if target.contains("64") {
build.define("BACKTRACE_ELF_SIZE", "64");
} else {
build.define("BACKTRACE_ELF_SIZE", "32");
}
}
File::create(native.out_dir.join("backtrace-supported.h")).unwrap();
build.define("BACKTRACE_SUPPORTED", "1");
build.define("BACKTRACE_USES_MALLOC", "1");
build.define("BACKTRACE_SUPPORTS_THREADS", "0");
build.define("BACKTRACE_SUPPORTS_DATA", "0");
File::create(native.out_dir.join("config.h")).unwrap();
if !target.contains("apple-ios") &&
!target.contains("solaris") &&
!target.contains("redox") &&
!target.contains("android") {
build.define("HAVE_DL_ITERATE_PHDR", "1");
}
build.define("_GNU_SOURCE", "1");
build.define("_LARGE_FILES", "1");
build.compile("backtrace");
Ok(())
}

60
ctr-std/src/collections/hash/map.rs

@ -11,7 +11,7 @@
use self::Entry::*; use self::Entry::*;
use self::VacantEntryState::*; use self::VacantEntryState::*;
use alloc::{CollectionAllocErr, oom}; use alloc::CollectionAllocErr;
use cell::Cell; use cell::Cell;
use borrow::Borrow; use borrow::Borrow;
use cmp::max; use cmp::max;
@ -23,8 +23,10 @@ use mem::{self, replace};
use ops::{Deref, Index}; use ops::{Deref, Index};
use sys; use sys;
use super::table::{self, Bucket, EmptyBucket, FullBucket, FullBucketMut, RawTable, SafeHash}; use super::table::{self, Bucket, EmptyBucket, Fallibility, FullBucket, FullBucketMut, RawTable,
SafeHash};
use super::table::BucketState::{Empty, Full}; use super::table::BucketState::{Empty, Full};
use super::table::Fallibility::{Fallible, Infallible};
const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two const MIN_NONZERO_RAW_CAPACITY: usize = 32; // must be a power of two
@ -783,11 +785,11 @@ impl<K, V, S> HashMap<K, V, S>
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn reserve(&mut self, additional: usize) { pub fn reserve(&mut self, additional: usize) {
match self.try_reserve(additional) { match self.reserve_internal(additional, Infallible) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
Err(CollectionAllocErr::AllocErr) => oom(), Err(CollectionAllocErr::AllocErr) => unreachable!(),
Ok(()) => { /* yay */ } Ok(()) => { /* yay */ }
} }
} }
/// Tries to reserve capacity for at least `additional` more elements to be inserted /// Tries to reserve capacity for at least `additional` more elements to be inserted
@ -809,17 +811,24 @@ impl<K, V, S> HashMap<K, V, S>
/// ``` /// ```
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> { pub fn try_reserve(&mut self, additional: usize) -> Result<(), CollectionAllocErr> {
self.reserve_internal(additional, Fallible)
}
fn reserve_internal(&mut self, additional: usize, fallibility: Fallibility)
-> Result<(), CollectionAllocErr> {
let remaining = self.capacity() - self.len(); // this can't overflow let remaining = self.capacity() - self.len(); // this can't overflow
if remaining < additional { if remaining < additional {
let min_cap = self.len().checked_add(additional) let min_cap = self.len()
.checked_add(additional)
.ok_or(CollectionAllocErr::CapacityOverflow)?; .ok_or(CollectionAllocErr::CapacityOverflow)?;
let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?; let raw_cap = self.resize_policy.try_raw_capacity(min_cap)?;
self.try_resize(raw_cap)?; self.try_resize(raw_cap, fallibility)?;
} else if self.table.tag() && remaining <= self.len() { } else if self.table.tag() && remaining <= self.len() {
// Probe sequence is too long and table is half full, // Probe sequence is too long and table is half full,
// resize early to reduce probing length. // resize early to reduce probing length.
let new_capacity = self.table.capacity() * 2; let new_capacity = self.table.capacity() * 2;
self.try_resize(new_capacity)?; self.try_resize(new_capacity, fallibility)?;
} }
Ok(()) Ok(())
} }
@ -831,11 +840,21 @@ impl<K, V, S> HashMap<K, V, S>
/// 2) Ensure `new_raw_cap` is a power of two or zero. /// 2) Ensure `new_raw_cap` is a power of two or zero.
#[inline(never)] #[inline(never)]
#[cold] #[cold]
fn try_resize(&mut self, new_raw_cap: usize) -> Result<(), CollectionAllocErr> { fn try_resize(
&mut self,
new_raw_cap: usize,
fallibility: Fallibility,
) -> Result<(), CollectionAllocErr> {
assert!(self.table.size() <= new_raw_cap); assert!(self.table.size() <= new_raw_cap);
assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0); assert!(new_raw_cap.is_power_of_two() || new_raw_cap == 0);
let mut old_table = replace(&mut self.table, RawTable::try_new(new_raw_cap)?); let mut old_table = replace(
&mut self.table,
match fallibility {
Infallible => RawTable::new(new_raw_cap),
Fallible => RawTable::try_new(new_raw_cap)?,
}
);
let old_size = old_table.size(); let old_size = old_table.size();
if old_table.size() == 0 { if old_table.size() == 0 {
@ -2142,14 +2161,13 @@ impl<'a, K, V> Entry<'a, K, V> {
} }
impl<'a, K, V: Default> Entry<'a, K, V> { impl<'a, K, V: Default> Entry<'a, K, V> {
#[unstable(feature = "entry_or_default", issue = "44324")] #[stable(feature = "entry_or_default", since = "1.28.0")]
/// Ensures a value is in the entry by inserting the default value if empty, /// Ensures a value is in the entry by inserting the default value if empty,
/// and returns a mutable reference to the value in the entry. /// and returns a mutable reference to the value in the entry.
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// #![feature(entry_or_default)]
/// # fn main() { /// # fn main() {
/// use std::collections::HashMap; /// use std::collections::HashMap;
/// ///
@ -2165,7 +2183,6 @@ impl<'a, K, V: Default> Entry<'a, K, V> {
Vacant(entry) => entry.insert(Default::default()), Vacant(entry) => entry.insert(Default::default()),
} }
} }
} }
impl<'a, K, V> OccupiedEntry<'a, K, V> { impl<'a, K, V> OccupiedEntry<'a, K, V> {
@ -2231,6 +2248,11 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
/// Gets a mutable reference to the value in the entry. /// Gets a mutable reference to the value in the entry.
/// ///
/// If you need a reference to the `OccupiedEntry` which may outlive the
/// destruction of the `Entry` value, see [`into_mut`].
///
/// [`into_mut`]: #method.into_mut
///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
@ -2242,10 +2264,14 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
/// ///
/// assert_eq!(map["poneyland"], 12); /// assert_eq!(map["poneyland"], 12);
/// if let Entry::Occupied(mut o) = map.entry("poneyland") { /// if let Entry::Occupied(mut o) = map.entry("poneyland") {
/// *o.get_mut() += 10; /// *o.get_mut() += 10;
/// assert_eq!(*o.get(), 22);
///
/// // We can use the same Entry multiple times.
/// *o.get_mut() += 2;
/// } /// }
/// ///
/// assert_eq!(map["poneyland"], 22); /// assert_eq!(map["poneyland"], 24);
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub fn get_mut(&mut self) -> &mut V { pub fn get_mut(&mut self) -> &mut V {
@ -2255,6 +2281,10 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> {
/// Converts the OccupiedEntry into a mutable reference to the value in the entry /// Converts the OccupiedEntry into a mutable reference to the value in the entry
/// with a lifetime bound to the map itself. /// with a lifetime bound to the map itself.
/// ///
/// If you need multiple references to the `OccupiedEntry`, see [`get_mut`].
///
/// [`get_mut`]: #method.get_mut
///
/// # Examples /// # Examples
/// ///
/// ``` /// ```

166
ctr-std/src/collections/hash/table.rs

@ -8,14 +8,14 @@
// option. This file may not be copied, modified, or distributed // option. This file may not be copied, modified, or distributed
// except according to those terms. // except according to those terms.
use alloc::{Global, Alloc, Layout, CollectionAllocErr, oom}; use alloc::{Global, Alloc, Layout, LayoutErr, CollectionAllocErr, oom};
use cmp;
use hash::{BuildHasher, Hash, Hasher}; use hash::{BuildHasher, Hash, Hasher};
use marker; use marker;
use mem::{align_of, size_of, needs_drop}; use mem::{size_of, needs_drop};
use mem; use mem;
use ops::{Deref, DerefMut}; use ops::{Deref, DerefMut};
use ptr::{self, Unique, NonNull}; use ptr::{self, Unique, NonNull};
use hint;
use self::BucketState::*; use self::BucketState::*;
@ -651,71 +651,39 @@ impl<K, V, M> GapThenFull<K, V, M>
} }
} }
// Returns a Layout which describes the allocation required for a hash table,
/// Rounds up to a multiple of a power of two. Returns the closest multiple // and the offset of the array of (key, value) pairs in the allocation.
/// of `target_alignment` that is higher or equal to `unrounded`. fn calculate_layout<K, V>(capacity: usize) -> Result<(Layout, usize), LayoutErr> {
/// let hashes = Layout::array::<HashUint>(capacity)?;
/// # Panics let pairs = Layout::array::<(K, V)>(capacity)?;
/// hashes.extend(pairs).map(|(layout, _)| {
/// Panics if `target_alignment` is not a power of two. // LLVM seems to have trouble properly const-propagating pairs.align(),
#[inline] // possibly due to the use of NonZeroUsize. This little hack allows it
fn round_up_to_next(unrounded: usize, target_alignment: usize) -> usize { // to generate optimal code.
assert!(target_alignment.is_power_of_two()); //
(unrounded + target_alignment - 1) & !(target_alignment - 1) // See https://github.com/rust-lang/rust/issues/51346 for more details.
} (
layout,
#[test] hashes.size() + hashes.padding_needed_for(mem::align_of::<(K, V)>()),
fn test_rounding() { )
assert_eq!(round_up_to_next(0, 4), 0); })
assert_eq!(round_up_to_next(1, 4), 4);
assert_eq!(round_up_to_next(2, 4), 4);
assert_eq!(round_up_to_next(3, 4), 4);
assert_eq!(round_up_to_next(4, 4), 4);
assert_eq!(round_up_to_next(5, 4), 8);
}
// Returns a tuple of (pairs_offset, end_of_pairs_offset),
// from the start of a mallocated array.
#[inline]
fn calculate_offsets(hashes_size: usize,
pairs_size: usize,
pairs_align: usize)
-> (usize, usize, bool) {
let pairs_offset = round_up_to_next(hashes_size, pairs_align);
let (end_of_pairs, oflo) = pairs_offset.overflowing_add(pairs_size);
(pairs_offset, end_of_pairs, oflo)
} }
// Returns a tuple of (minimum required malloc alignment, pub(crate) enum Fallibility {
// array_size), from the start of a mallocated array. Fallible,
fn calculate_allocation(hash_size: usize, Infallible,
hash_align: usize,
pairs_size: usize,
pairs_align: usize)
-> (usize, usize, bool) {
let (_, end_of_pairs, oflo) = calculate_offsets(hash_size, pairs_size, pairs_align);
let align = cmp::max(hash_align, pairs_align);
(align, end_of_pairs, oflo)
} }
#[test] use self::Fallibility::*;
fn test_offset_calculation() {
assert_eq!(calculate_allocation(128, 8, 16, 8), (8, 144, false));
assert_eq!(calculate_allocation(3, 1, 2, 1), (1, 5, false));
assert_eq!(calculate_allocation(6, 2, 12, 4), (4, 20, false));
assert_eq!(calculate_offsets(128, 15, 4), (128, 143, false));
assert_eq!(calculate_offsets(3, 2, 4), (4, 6, false));
assert_eq!(calculate_offsets(6, 12, 4), (8, 20, false));
}
impl<K, V> RawTable<K, V> { impl<K, V> RawTable<K, V> {
/// Does not initialize the buckets. The caller should ensure they, /// Does not initialize the buckets. The caller should ensure they,
/// at the very least, set every hash to EMPTY_BUCKET. /// at the very least, set every hash to EMPTY_BUCKET.
/// Returns an error if it cannot allocate or capacity overflows. /// Returns an error if it cannot allocate or capacity overflows.
unsafe fn try_new_uninitialized(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> { unsafe fn new_uninitialized_internal(
capacity: usize,
fallibility: Fallibility,
) -> Result<RawTable<K, V>, CollectionAllocErr> {
if capacity == 0 { if capacity == 0 {
return Ok(RawTable { return Ok(RawTable {
size: 0, size: 0,
@ -725,37 +693,15 @@ impl<K, V> RawTable<K, V> {
}); });
} }
// No need for `checked_mul` before a more restrictive check performed
// later in this method.
let hashes_size = capacity.wrapping_mul(size_of::<HashUint>());
let pairs_size = capacity.wrapping_mul(size_of::<(K, V)>());
// Allocating hashmaps is a little tricky. We need to allocate two // Allocating hashmaps is a little tricky. We need to allocate two
// arrays, but since we know their sizes and alignments up front, // arrays, but since we know their sizes and alignments up front,
// we just allocate a single array, and then have the subarrays // we just allocate a single array, and then have the subarrays
// point into it. // point into it.
// let (layout, _) = calculate_layout::<K, V>(capacity)?;
// This is great in theory, but in practice getting the alignment let buffer = Global.alloc(layout).map_err(|e| match fallibility {
// right is a little subtle. Therefore, calculating offsets has been Infallible => oom(layout),
// factored out into a different function. Fallible => e,
let (alignment, size, oflo) = calculate_allocation(hashes_size, })?;
align_of::<HashUint>(),
pairs_size,
align_of::<(K, V)>());
if oflo {
return Err(CollectionAllocErr::CapacityOverflow);
}
// One check for overflow that covers calculation and rounding of size.
let size_of_bucket = size_of::<HashUint>().checked_add(size_of::<(K, V)>())
.ok_or(CollectionAllocErr::CapacityOverflow)?;
let capacity_mul_size_of_bucket = capacity.checked_mul(size_of_bucket);
if capacity_mul_size_of_bucket.is_none() || size < capacity_mul_size_of_bucket.unwrap() {
return Err(CollectionAllocErr::CapacityOverflow);
}
let buffer = Global.alloc(Layout::from_size_align(size, alignment)
.map_err(|_| CollectionAllocErr::CapacityOverflow)?)?;
Ok(RawTable { Ok(RawTable {
capacity_mask: capacity.wrapping_sub(1), capacity_mask: capacity.wrapping_sub(1),
@ -768,48 +714,50 @@ impl<K, V> RawTable<K, V> {
/// Does not initialize the buckets. The caller should ensure they, /// Does not initialize the buckets. The caller should ensure they,
/// at the very least, set every hash to EMPTY_BUCKET. /// at the very least, set every hash to EMPTY_BUCKET.
unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> { unsafe fn new_uninitialized(capacity: usize) -> RawTable<K, V> {
match Self::try_new_uninitialized(capacity) { match Self::new_uninitialized_internal(capacity, Infallible) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
Err(CollectionAllocErr::AllocErr) => oom(), Err(CollectionAllocErr::AllocErr) => unreachable!(),
Ok(table) => { table } Ok(table) => { table }
} }
} }
fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> { fn raw_bucket_at(&self, index: usize) -> RawBucket<K, V> {
let hashes_size = self.capacity() * size_of::<HashUint>(); let (_, pairs_offset) = calculate_layout::<K, V>(self.capacity())
let pairs_size = self.capacity() * size_of::<(K, V)>(); .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
let (pairs_offset, _, oflo) =
calculate_offsets(hashes_size, pairs_size, align_of::<(K, V)>());
debug_assert!(!oflo, "capacity overflow");
let buffer = self.hashes.ptr() as *mut u8; let buffer = self.hashes.ptr() as *mut u8;
unsafe { unsafe {
RawBucket { RawBucket {
hash_start: buffer as *mut HashUint, hash_start: buffer as *mut HashUint,
pair_start: buffer.offset(pairs_offset as isize) as *const (K, V), pair_start: buffer.add(pairs_offset) as *const (K, V),
idx: index, idx: index,
_marker: marker::PhantomData, _marker: marker::PhantomData,
} }
} }
} }
/// Tries to create a new raw table from a given capacity. If it cannot allocate, fn new_internal(
/// it returns with AllocErr. capacity: usize,
pub fn try_new(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> { fallibility: Fallibility,
) -> Result<RawTable<K, V>, CollectionAllocErr> {
unsafe { unsafe {
let ret = RawTable::try_new_uninitialized(capacity)?; let ret = RawTable::new_uninitialized_internal(capacity, fallibility)?;
ptr::write_bytes(ret.hashes.ptr(), 0, capacity); ptr::write_bytes(ret.hashes.ptr(), 0, capacity);
Ok(ret) Ok(ret)
} }
} }
/// Tries to create a new raw table from a given capacity. If it cannot allocate,
/// it returns with AllocErr.
pub fn try_new(capacity: usize) -> Result<RawTable<K, V>, CollectionAllocErr> {
Self::new_internal(capacity, Fallible)
}
/// Creates a new raw table from a given capacity. All buckets are /// Creates a new raw table from a given capacity. All buckets are
/// initially empty. /// initially empty.
pub fn new(capacity: usize) -> RawTable<K, V> { pub fn new(capacity: usize) -> RawTable<K, V> {
match Self::try_new(capacity) { match Self::new_internal(capacity, Infallible) {
Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"), Err(CollectionAllocErr::CapacityOverflow) => panic!("capacity overflow"),
Err(CollectionAllocErr::AllocErr) => oom(), Err(CollectionAllocErr::AllocErr) => unreachable!(),
Ok(table) => { table } Ok(table) => { table }
} }
} }
@ -1173,18 +1121,10 @@ unsafe impl<#[may_dangle] K, #[may_dangle] V> Drop for RawTable<K, V> {
} }
} }
let hashes_size = self.capacity() * size_of::<HashUint>(); let (layout, _) = calculate_layout::<K, V>(self.capacity())
let pairs_size = self.capacity() * size_of::<(K, V)>(); .unwrap_or_else(|_| unsafe { hint::unreachable_unchecked() });
let (align, size, oflo) = calculate_allocation(hashes_size,
align_of::<HashUint>(),
pairs_size,
align_of::<(K, V)>());
debug_assert!(!oflo, "should be impossible");
unsafe { unsafe {
Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), Global.dealloc(NonNull::new_unchecked(self.hashes.ptr()).as_opaque(), layout);
Layout::from_size_align(size, align).unwrap());
// Remember how everything was allocated out of one buffer // Remember how everything was allocated out of one buffer
// during initialization? We only need one call to free here. // during initialization? We only need one call to free here.
} }

8
ctr-std/src/collections/mod.rs

@ -437,14 +437,6 @@ pub use self::hash_map::HashMap;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub use self::hash_set::HashSet; pub use self::hash_set::HashSet;
#[unstable(feature = "collections_range", issue = "30877")]
#[rustc_deprecated(reason = "renamed and moved to `std::ops::RangeBounds`", since = "1.26.0")]
#[doc(hidden)]
/// Range syntax
pub mod range {
pub use ops::RangeBounds as RangeArgument;
}
#[unstable(feature = "try_reserve", reason = "new API", issue="48043")] #[unstable(feature = "try_reserve", reason = "new API", issue="48043")]
pub use heap::CollectionAllocErr; pub use heap::CollectionAllocErr;

33
ctr-std/src/env.rs

@ -49,9 +49,11 @@ use sys::os as os_imp;
/// ``` /// ```
/// use std::env; /// use std::env;
/// ///
/// // We assume that we are in a valid directory. /// fn main() -> std::io::Result<()> {
/// let path = env::current_dir().unwrap(); /// let path = env::current_dir()?;
/// println!("The current directory is {}", path.display()); /// println!("The current directory is {}", path.display());
/// Ok(())
/// }
/// ``` /// ```
#[stable(feature = "env", since = "1.0.0")] #[stable(feature = "env", since = "1.0.0")]
pub fn current_dir() -> io::Result<PathBuf> { pub fn current_dir() -> io::Result<PathBuf> {
@ -441,15 +443,18 @@ pub struct JoinPathsError {
/// Joining paths on a Unix-like platform: /// Joining paths on a Unix-like platform:
/// ///
/// ``` /// ```
/// # if cfg!(unix) {
/// use std::env; /// use std::env;
/// use std::ffi::OsString; /// use std::ffi::OsString;
/// use std::path::Path; /// use std::path::Path;
/// ///
/// let paths = [Path::new("/bin"), Path::new("/usr/bin")]; /// fn main() -> Result<(), env::JoinPathsError> {
/// let path_os_string = env::join_paths(paths.iter()).unwrap(); /// # if cfg!(unix) {
/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin")); /// let paths = [Path::new("/bin"), Path::new("/usr/bin")];
/// let path_os_string = env::join_paths(paths.iter())?;
/// assert_eq!(path_os_string, OsString::from("/bin:/usr/bin"));
/// # } /// # }
/// Ok(())
/// }
/// ``` /// ```
/// ///
/// Joining a path containing a colon on a Unix-like platform results in an error: /// Joining a path containing a colon on a Unix-like platform results in an error:
@ -471,11 +476,15 @@ pub struct JoinPathsError {
/// use std::env; /// use std::env;
/// use std::path::PathBuf; /// use std::path::PathBuf;
/// ///
/// if let Some(path) = env::var_os("PATH") { /// fn main() -> Result<(), env::JoinPathsError> {
/// let mut paths = env::split_paths(&path).collect::<Vec<_>>(); /// if let Some(path) = env::var_os("PATH") {
/// paths.push(PathBuf::from("/home/xyz/bin")); /// let mut paths = env::split_paths(&path).collect::<Vec<_>>();
/// let new_path = env::join_paths(paths).unwrap(); /// paths.push(PathBuf::from("/home/xyz/bin"));
/// env::set_var("PATH", &new_path); /// let new_path = env::join_paths(paths)?;
/// env::set_var("PATH", &new_path);
/// }
///
/// Ok(())
/// } /// }
/// ``` /// ```
#[stable(feature = "env", since = "1.0.0")] #[stable(feature = "env", since = "1.0.0")]

98
ctr-std/src/f32.rs

@ -11,22 +11,16 @@
//! This module provides constants which are specific to the implementation //! This module provides constants which are specific to the implementation
//! of the `f32` floating point data type. //! of the `f32` floating point data type.
//! //!
//! Mathematically significant numbers are provided in the `consts` sub-module.
//!
//! *[See also the `f32` primitive type](../../std/primitive.f32.html).* //! *[See also the `f32` primitive type](../../std/primitive.f32.html).*
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)] #![allow(missing_docs)]
#[cfg(not(test))]
#[cfg(stage0)]
use core::num::Float;
#[cfg(not(test))] #[cfg(not(test))]
use intrinsics; use intrinsics;
#[cfg(not(test))] #[cfg(not(test))]
#[cfg(stage0)]
use num::FpCategory;
#[cfg(not(test))]
use sys::cmath; use sys::cmath;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -41,14 +35,12 @@ pub use core::f32::{MIN, MIN_POSITIVE, MAX};
pub use core::f32::consts; pub use core::f32::consts;
#[cfg(not(test))] #[cfg(not(test))]
#[cfg_attr(stage0, lang = "f32")] #[lang = "f32_runtime"]
#[cfg_attr(not(stage0), lang = "f32_runtime")]
impl f32 { impl f32 {
#[cfg(stage0)]
f32_core_methods!();
/// Returns the largest integer less than or equal to a number. /// Returns the largest integer less than or equal to a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 3.99_f32; /// let f = 3.99_f32;
/// let g = 3.0_f32; /// let g = 3.0_f32;
@ -80,6 +72,8 @@ impl f32 {
/// Returns the smallest integer greater than or equal to a number. /// Returns the smallest integer greater than or equal to a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 3.01_f32; /// let f = 3.01_f32;
/// let g = 4.0_f32; /// let g = 4.0_f32;
@ -100,6 +94,8 @@ impl f32 {
/// Returns the nearest integer to a number. Round half-way cases away from /// Returns the nearest integer to a number. Round half-way cases away from
/// `0.0`. /// `0.0`.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 3.3_f32; /// let f = 3.3_f32;
/// let g = -3.3_f32; /// let g = -3.3_f32;
@ -115,6 +111,8 @@ impl f32 {
/// Returns the integer part of a number. /// Returns the integer part of a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 3.3_f32; /// let f = 3.3_f32;
/// let g = -3.7_f32; /// let g = -3.7_f32;
@ -130,6 +128,8 @@ impl f32 {
/// Returns the fractional part of a number. /// Returns the fractional part of a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -148,6 +148,8 @@ impl f32 {
/// Computes the absolute value of `self`. Returns `NAN` if the /// Computes the absolute value of `self`. Returns `NAN` if the
/// number is `NAN`. /// number is `NAN`.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -174,6 +176,8 @@ impl f32 {
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// - `NAN` if the number is `NAN` /// - `NAN` if the number is `NAN`
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -195,8 +199,12 @@ impl f32 {
} }
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error. This produces a more accurate result with better performance than /// error, yielding a more accurate result than an unfused multiply-add.
/// a separate multiplication operation followed by an add. ///
/// Using `mul_add` can be more performant than an unfused multiply-add if
/// the target architecture has a dedicated `fma` CPU instruction.
///
/// # Examples
/// ///
/// ``` /// ```
/// use std::f32; /// use std::f32;
@ -223,6 +231,8 @@ impl f32 {
/// In other words, the result is `self / rhs` rounded to the integer `n` /// In other words, the result is `self / rhs` rounded to the integer `n`
/// such that `self >= n * rhs`. /// such that `self >= n * rhs`.
/// ///
/// # Examples
///
/// ``` /// ```
/// #![feature(euclidean_division)] /// #![feature(euclidean_division)]
/// let a: f32 = 7.0; /// let a: f32 = 7.0;
@ -246,6 +256,8 @@ impl f32 {
/// ///
/// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
/// ///
/// # Examples
///
/// ``` /// ```
/// #![feature(euclidean_division)] /// #![feature(euclidean_division)]
/// let a: f32 = 7.0; /// let a: f32 = 7.0;
@ -271,6 +283,8 @@ impl f32 {
/// ///
/// Using this function is generally faster than using `powf` /// Using this function is generally faster than using `powf`
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -287,6 +301,8 @@ impl f32 {
/// Raises a number to a floating point power. /// Raises a number to a floating point power.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -309,6 +325,8 @@ impl f32 {
/// ///
/// Returns NaN if `self` is a negative number. /// Returns NaN if `self` is a negative number.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -332,6 +350,8 @@ impl f32 {
/// Returns `e^(self)`, (the exponential function). /// Returns `e^(self)`, (the exponential function).
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -356,6 +376,8 @@ impl f32 {
/// Returns `2^(self)`. /// Returns `2^(self)`.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -374,6 +396,8 @@ impl f32 {
/// Returns the natural logarithm of the number. /// Returns the natural logarithm of the number.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -402,6 +426,8 @@ impl f32 {
/// `self.log2()` can produce more accurate results for base 2, and /// `self.log2()` can produce more accurate results for base 2, and
/// `self.log10()` can produce more accurate results for base 10. /// `self.log10()` can produce more accurate results for base 10.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -418,6 +444,8 @@ impl f32 {
/// Returns the base 2 logarithm of the number. /// Returns the base 2 logarithm of the number.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -439,6 +467,8 @@ impl f32 {
/// Returns the base 10 logarithm of the number. /// Returns the base 10 logarithm of the number.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -464,6 +494,8 @@ impl f32 {
/// * If `self <= other`: `0:0` /// * If `self <= other`: `0:0`
/// * Else: `self - other` /// * Else: `self - other`
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -491,6 +523,8 @@ impl f32 {
/// Takes the cubic root of a number. /// Takes the cubic root of a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -510,6 +544,8 @@ impl f32 {
/// Calculates the length of the hypotenuse of a right-angle triangle given /// Calculates the length of the hypotenuse of a right-angle triangle given
/// legs of length `x` and `y`. /// legs of length `x` and `y`.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -529,6 +565,8 @@ impl f32 {
/// Computes the sine of a number (in radians). /// Computes the sine of a number (in radians).
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -550,6 +588,8 @@ impl f32 {
/// Computes the cosine of a number (in radians). /// Computes the cosine of a number (in radians).
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -571,6 +611,8 @@ impl f32 {
/// Computes the tangent of a number (in radians). /// Computes the tangent of a number (in radians).
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -589,6 +631,8 @@ impl f32 {
/// the range [-pi/2, pi/2] or NaN if the number is outside the range /// the range [-pi/2, pi/2] or NaN if the number is outside the range
/// [-1, 1]. /// [-1, 1].
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -609,6 +653,8 @@ impl f32 {
/// the range [0, pi] or NaN if the number is outside the range /// the range [0, pi] or NaN if the number is outside the range
/// [-1, 1]. /// [-1, 1].
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -628,6 +674,8 @@ impl f32 {
/// Computes the arctangent of a number. Return value is in radians in the /// Computes the arctangent of a number. Return value is in radians in the
/// range [-pi/2, pi/2]; /// range [-pi/2, pi/2];
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -651,6 +699,8 @@ impl f32 {
/// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
/// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -680,6 +730,8 @@ impl f32 {
/// Simultaneously computes the sine and cosine of the number, `x`. Returns /// Simultaneously computes the sine and cosine of the number, `x`. Returns
/// `(sin(x), cos(x))`. /// `(sin(x), cos(x))`.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -701,6 +753,8 @@ impl f32 {
/// Returns `e^(self) - 1` in a way that is accurate even if the /// Returns `e^(self) - 1` in a way that is accurate even if the
/// number is close to zero. /// number is close to zero.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -720,6 +774,8 @@ impl f32 {
/// Returns `ln(1+n)` (natural logarithm) more accurately than if /// Returns `ln(1+n)` (natural logarithm) more accurately than if
/// the operations were performed separately. /// the operations were performed separately.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -738,6 +794,8 @@ impl f32 {
/// Hyperbolic sine function. /// Hyperbolic sine function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -759,6 +817,8 @@ impl f32 {
/// Hyperbolic cosine function. /// Hyperbolic cosine function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -780,6 +840,8 @@ impl f32 {
/// Hyperbolic tangent function. /// Hyperbolic tangent function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -801,6 +863,8 @@ impl f32 {
/// Inverse hyperbolic sine function. /// Inverse hyperbolic sine function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -823,6 +887,8 @@ impl f32 {
/// Inverse hyperbolic cosine function. /// Inverse hyperbolic cosine function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///
@ -844,6 +910,8 @@ impl f32 {
/// Inverse hyperbolic tangent function. /// Inverse hyperbolic tangent function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f32; /// use std::f32;
/// ///

98
ctr-std/src/f64.rs

@ -11,22 +11,16 @@
//! This module provides constants which are specific to the implementation //! This module provides constants which are specific to the implementation
//! of the `f64` floating point data type. //! of the `f64` floating point data type.
//! //!
//! Mathematically significant numbers are provided in the `consts` sub-module.
//!
//! *[See also the `f64` primitive type](../../std/primitive.f64.html).* //! *[See also the `f64` primitive type](../../std/primitive.f64.html).*
//!
//! Mathematically significant numbers are provided in the `consts` sub-module.
#![stable(feature = "rust1", since = "1.0.0")] #![stable(feature = "rust1", since = "1.0.0")]
#![allow(missing_docs)] #![allow(missing_docs)]
#[cfg(not(test))]
#[cfg(stage0)]
use core::num::Float;
#[cfg(not(test))] #[cfg(not(test))]
use intrinsics; use intrinsics;
#[cfg(not(test))] #[cfg(not(test))]
#[cfg(stage0)]
use num::FpCategory;
#[cfg(not(test))]
use sys::cmath; use sys::cmath;
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
@ -41,14 +35,12 @@ pub use core::f64::{MIN, MIN_POSITIVE, MAX};
pub use core::f64::consts; pub use core::f64::consts;
#[cfg(not(test))] #[cfg(not(test))]
#[cfg_attr(stage0, lang = "f64")] #[lang = "f64_runtime"]
#[cfg_attr(not(stage0), lang = "f64_runtime")]
impl f64 { impl f64 {
#[cfg(stage0)]
f64_core_methods!();
/// Returns the largest integer less than or equal to a number. /// Returns the largest integer less than or equal to a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 3.99_f64; /// let f = 3.99_f64;
/// let g = 3.0_f64; /// let g = 3.0_f64;
@ -64,6 +56,8 @@ impl f64 {
/// Returns the smallest integer greater than or equal to a number. /// Returns the smallest integer greater than or equal to a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 3.01_f64; /// let f = 3.01_f64;
/// let g = 4.0_f64; /// let g = 4.0_f64;
@ -80,6 +74,8 @@ impl f64 {
/// Returns the nearest integer to a number. Round half-way cases away from /// Returns the nearest integer to a number. Round half-way cases away from
/// `0.0`. /// `0.0`.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 3.3_f64; /// let f = 3.3_f64;
/// let g = -3.3_f64; /// let g = -3.3_f64;
@ -95,6 +91,8 @@ impl f64 {
/// Returns the integer part of a number. /// Returns the integer part of a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 3.3_f64; /// let f = 3.3_f64;
/// let g = -3.7_f64; /// let g = -3.7_f64;
@ -110,6 +108,8 @@ impl f64 {
/// Returns the fractional part of a number. /// Returns the fractional part of a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 3.5_f64; /// let x = 3.5_f64;
/// let y = -3.5_f64; /// let y = -3.5_f64;
@ -126,6 +126,8 @@ impl f64 {
/// Computes the absolute value of `self`. Returns `NAN` if the /// Computes the absolute value of `self`. Returns `NAN` if the
/// number is `NAN`. /// number is `NAN`.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -152,6 +154,8 @@ impl f64 {
/// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY` /// - `-1.0` if the number is negative, `-0.0` or `NEG_INFINITY`
/// - `NAN` if the number is `NAN` /// - `NAN` if the number is `NAN`
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -173,8 +177,12 @@ impl f64 {
} }
/// Fused multiply-add. Computes `(self * a) + b` with only one rounding /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
/// error. This produces a more accurate result with better performance than /// error, yielding a more accurate result than an unfused multiply-add.
/// a separate multiplication operation followed by an add. ///
/// Using `mul_add` can be more performant than an unfused multiply-add if
/// the target architecture has a dedicated `fma` CPU instruction.
///
/// # Examples
/// ///
/// ``` /// ```
/// let m = 10.0_f64; /// let m = 10.0_f64;
@ -199,6 +207,8 @@ impl f64 {
/// In other words, the result is `self / rhs` rounded to the integer `n` /// In other words, the result is `self / rhs` rounded to the integer `n`
/// such that `self >= n * rhs`. /// such that `self >= n * rhs`.
/// ///
/// # Examples
///
/// ``` /// ```
/// #![feature(euclidean_division)] /// #![feature(euclidean_division)]
/// let a: f64 = 7.0; /// let a: f64 = 7.0;
@ -222,6 +232,8 @@ impl f64 {
/// ///
/// In particular, the result `n` satisfies `0 <= n < rhs.abs()`. /// In particular, the result `n` satisfies `0 <= n < rhs.abs()`.
/// ///
/// # Examples
///
/// ``` /// ```
/// #![feature(euclidean_division)] /// #![feature(euclidean_division)]
/// let a: f64 = 7.0; /// let a: f64 = 7.0;
@ -246,6 +258,8 @@ impl f64 {
/// ///
/// Using this function is generally faster than using `powf` /// Using this function is generally faster than using `powf`
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 2.0_f64; /// let x = 2.0_f64;
/// let abs_difference = (x.powi(2) - x*x).abs(); /// let abs_difference = (x.powi(2) - x*x).abs();
@ -260,6 +274,8 @@ impl f64 {
/// Raises a number to a floating point power. /// Raises a number to a floating point power.
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 2.0_f64; /// let x = 2.0_f64;
/// let abs_difference = (x.powf(2.0) - x*x).abs(); /// let abs_difference = (x.powf(2.0) - x*x).abs();
@ -276,6 +292,8 @@ impl f64 {
/// ///
/// Returns NaN if `self` is a negative number. /// Returns NaN if `self` is a negative number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let positive = 4.0_f64; /// let positive = 4.0_f64;
/// let negative = -4.0_f64; /// let negative = -4.0_f64;
@ -297,6 +315,8 @@ impl f64 {
/// Returns `e^(self)`, (the exponential function). /// Returns `e^(self)`, (the exponential function).
/// ///
/// # Examples
///
/// ``` /// ```
/// let one = 1.0_f64; /// let one = 1.0_f64;
/// // e^1 /// // e^1
@ -315,6 +335,8 @@ impl f64 {
/// Returns `2^(self)`. /// Returns `2^(self)`.
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 2.0_f64; /// let f = 2.0_f64;
/// ///
@ -331,6 +353,8 @@ impl f64 {
/// Returns the natural logarithm of the number. /// Returns the natural logarithm of the number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let one = 1.0_f64; /// let one = 1.0_f64;
/// // e^1 /// // e^1
@ -353,6 +377,8 @@ impl f64 {
/// `self.log2()` can produce more accurate results for base 2, and /// `self.log2()` can produce more accurate results for base 2, and
/// `self.log10()` can produce more accurate results for base 10. /// `self.log10()` can produce more accurate results for base 10.
/// ///
/// # Examples
///
/// ``` /// ```
/// let five = 5.0_f64; /// let five = 5.0_f64;
/// ///
@ -367,6 +393,8 @@ impl f64 {
/// Returns the base 2 logarithm of the number. /// Returns the base 2 logarithm of the number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let two = 2.0_f64; /// let two = 2.0_f64;
/// ///
@ -388,6 +416,8 @@ impl f64 {
/// Returns the base 10 logarithm of the number. /// Returns the base 10 logarithm of the number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let ten = 10.0_f64; /// let ten = 10.0_f64;
/// ///
@ -407,6 +437,8 @@ impl f64 {
/// * If `self <= other`: `0:0` /// * If `self <= other`: `0:0`
/// * Else: `self - other` /// * Else: `self - other`
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 3.0_f64; /// let x = 3.0_f64;
/// let y = -3.0_f64; /// let y = -3.0_f64;
@ -432,6 +464,8 @@ impl f64 {
/// Takes the cubic root of a number. /// Takes the cubic root of a number.
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 8.0_f64; /// let x = 8.0_f64;
/// ///
@ -449,6 +483,8 @@ impl f64 {
/// Calculates the length of the hypotenuse of a right-angle triangle given /// Calculates the length of the hypotenuse of a right-angle triangle given
/// legs of length `x` and `y`. /// legs of length `x` and `y`.
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 2.0_f64; /// let x = 2.0_f64;
/// let y = 3.0_f64; /// let y = 3.0_f64;
@ -466,6 +502,8 @@ impl f64 {
/// Computes the sine of a number (in radians). /// Computes the sine of a number (in radians).
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -483,6 +521,8 @@ impl f64 {
/// Computes the cosine of a number (in radians). /// Computes the cosine of a number (in radians).
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -500,6 +540,8 @@ impl f64 {
/// Computes the tangent of a number (in radians). /// Computes the tangent of a number (in radians).
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -518,6 +560,8 @@ impl f64 {
/// the range [-pi/2, pi/2] or NaN if the number is outside the range /// the range [-pi/2, pi/2] or NaN if the number is outside the range
/// [-1, 1]. /// [-1, 1].
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -538,6 +582,8 @@ impl f64 {
/// the range [0, pi] or NaN if the number is outside the range /// the range [0, pi] or NaN if the number is outside the range
/// [-1, 1]. /// [-1, 1].
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -557,6 +603,8 @@ impl f64 {
/// Computes the arctangent of a number. Return value is in radians in the /// Computes the arctangent of a number. Return value is in radians in the
/// range [-pi/2, pi/2]; /// range [-pi/2, pi/2];
/// ///
/// # Examples
///
/// ``` /// ```
/// let f = 1.0_f64; /// let f = 1.0_f64;
/// ///
@ -578,6 +626,8 @@ impl f64 {
/// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]` /// * `y >= 0`: `arctan(y/x) + pi` -> `(pi/2, pi]`
/// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)` /// * `y < 0`: `arctan(y/x) - pi` -> `(-pi, -pi/2)`
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -607,6 +657,8 @@ impl f64 {
/// Simultaneously computes the sine and cosine of the number, `x`. Returns /// Simultaneously computes the sine and cosine of the number, `x`. Returns
/// `(sin(x), cos(x))`. /// `(sin(x), cos(x))`.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -628,6 +680,8 @@ impl f64 {
/// Returns `e^(self) - 1` in a way that is accurate even if the /// Returns `e^(self) - 1` in a way that is accurate even if the
/// number is close to zero. /// number is close to zero.
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 7.0_f64; /// let x = 7.0_f64;
/// ///
@ -645,6 +699,8 @@ impl f64 {
/// Returns `ln(1+n)` (natural logarithm) more accurately than if /// Returns `ln(1+n)` (natural logarithm) more accurately than if
/// the operations were performed separately. /// the operations were performed separately.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -663,6 +719,8 @@ impl f64 {
/// Hyperbolic sine function. /// Hyperbolic sine function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -684,6 +742,8 @@ impl f64 {
/// Hyperbolic cosine function. /// Hyperbolic cosine function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -705,6 +765,8 @@ impl f64 {
/// Hyperbolic tangent function. /// Hyperbolic tangent function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///
@ -726,6 +788,8 @@ impl f64 {
/// Inverse hyperbolic sine function. /// Inverse hyperbolic sine function.
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 1.0_f64; /// let x = 1.0_f64;
/// let f = x.sinh().asinh(); /// let f = x.sinh().asinh();
@ -746,6 +810,8 @@ impl f64 {
/// Inverse hyperbolic cosine function. /// Inverse hyperbolic cosine function.
/// ///
/// # Examples
///
/// ``` /// ```
/// let x = 1.0_f64; /// let x = 1.0_f64;
/// let f = x.cosh().acosh(); /// let f = x.cosh().acosh();
@ -765,6 +831,8 @@ impl f64 {
/// Inverse hyperbolic tangent function. /// Inverse hyperbolic tangent function.
/// ///
/// # Examples
///
/// ``` /// ```
/// use std::f64; /// use std::f64;
/// ///

129
ctr-std/src/ffi/c_str.rs

@ -404,9 +404,59 @@ impl CString {
/// let c_string = CString::from_raw(raw); /// let c_string = CString::from_raw(raw);
/// } /// }
/// ``` /// ```
#[cfg(not(target_os = "horizon"))]
#[stable(feature = "cstr_memory", since = "1.4.0")] #[stable(feature = "cstr_memory", since = "1.4.0")]
pub unsafe fn from_raw(ptr: *mut c_char) -> CString { pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
let len = sys::strlen(ptr as *const _) + 1; // Including the NUL byte let len = sys::strlen(ptr) + 1; // Including the NUL byte
let slice = slice::from_raw_parts_mut(ptr, len as usize);
CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
}
/// Retakes ownership of a `CString` that was transferred to C via [`into_raw`].
///
/// Additionally, the length of the string will be recalculated from the pointer.
///
/// # Safety
///
/// This should only ever be called with a pointer that was earlier
/// obtained by calling [`into_raw`] on a `CString`. Other usage (e.g. trying to take
/// ownership of a string that was allocated by foreign code) is likely to lead
/// to undefined behavior or allocator corruption.
///
/// > **Note:** If you need to borrow a string that was allocated by
/// > foreign code, use [`CStr`]. If you need to take ownership of
/// > a string that was allocated by foreign code, you will need to
/// > make your own provisions for freeing it appropriately, likely
/// > with the foreign code's API to do that.
///
/// [`into_raw`]: #method.into_raw
/// [`CStr`]: struct.CStr.html
///
/// # Examples
///
/// Create a `CString`, pass ownership to an `extern` function (via raw pointer), then retake
/// ownership with `from_raw`:
///
/// ```ignore (extern-declaration)
/// use std::ffi::CString;
/// use std::os::raw::c_char;
///
/// extern {
/// fn some_extern_function(s: *mut c_char);
/// }
///
/// let c_string = CString::new("Hello!").unwrap();
/// let raw = c_string.into_raw();
/// unsafe {
/// some_extern_function(raw);
/// let c_string = CString::from_raw(raw);
/// }
/// ```
#[cfg(target_os = "horizon")]
#[stable(feature = "cstr_memory", since = "1.4.0")]
pub unsafe fn from_raw(ptr: *mut c_char) -> CString {
let len = sys::strlen(ptr as *const u8) + 1; // Including the NUL byte
let slice = slice::from_raw_parts_mut(ptr, len as usize); let slice = slice::from_raw_parts_mut(ptr, len as usize);
CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) } CString { inner: Box::from_raw(slice as *mut [c_char] as *mut [u8]) }
} }
@ -682,6 +732,14 @@ impl Borrow<CStr> for CString {
fn borrow(&self) -> &CStr { self } fn borrow(&self) -> &CStr { self }
} }
#[stable(feature = "cstring_from_cow_cstr", since = "1.28.0")]
impl<'a> From<Cow<'a, CStr>> for CString {
#[inline]
fn from(s: Cow<'a, CStr>) -> Self {
s.into_owned()
}
}
#[stable(feature = "box_from_c_str", since = "1.17.0")] #[stable(feature = "box_from_c_str", since = "1.17.0")]
impl<'a> From<&'a CStr> for Box<CStr> { impl<'a> From<&'a CStr> for Box<CStr> {
fn from(s: &'a CStr) -> Box<CStr> { fn from(s: &'a CStr) -> Box<CStr> {
@ -706,6 +764,30 @@ impl From<CString> for Box<CStr> {
} }
} }
#[stable(feature = "cow_from_cstr", since = "1.28.0")]
impl<'a> From<CString> for Cow<'a, CStr> {
#[inline]
fn from(s: CString) -> Cow<'a, CStr> {
Cow::Owned(s)
}
}
#[stable(feature = "cow_from_cstr", since = "1.28.0")]
impl<'a> From<&'a CStr> for Cow<'a, CStr> {
#[inline]
fn from(s: &'a CStr) -> Cow<'a, CStr> {
Cow::Borrowed(s)
}
}
#[stable(feature = "cow_from_cstr", since = "1.28.0")]
impl<'a> From<&'a CString> for Cow<'a, CStr> {
#[inline]
fn from(s: &'a CString) -> Cow<'a, CStr> {
Cow::Borrowed(s.as_c_str())
}
}
#[stable(feature = "shared_from_slice2", since = "1.24.0")] #[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<CString> for Arc<CStr> { impl From<CString> for Arc<CStr> {
#[inline] #[inline]
@ -899,13 +981,56 @@ impl CStr {
/// } /// }
/// # } /// # }
/// ``` /// ```
#[cfg(not(target_os = "horizon"))]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr { pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
let len = sys::strlen(ptr as *const _); let len = sys::strlen(ptr);
let ptr = ptr as *const u8; let ptr = ptr as *const u8;
CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1)) CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
} }
/// Wraps a raw C string with a safe C string wrapper.
///
/// This function will wrap the provided `ptr` with a `CStr` wrapper, which
/// allows inspection and interoperation of non-owned C strings. This method
/// is unsafe for a number of reasons:
///
/// * There is no guarantee to the validity of `ptr`.
/// * The returned lifetime is not guaranteed to be the actual lifetime of
/// `ptr`.
/// * There is no guarantee that the memory pointed to by `ptr` contains a
/// valid nul terminator byte at the end of the string.
/// * It is not guaranteed that the memory pointed by `ptr` won't change
/// before the `CStr` has been destroyed.
///
/// > **Note**: This operation is intended to be a 0-cost cast but it is
/// > currently implemented with an up-front calculation of the length of
/// > the string. This is not guaranteed to always be the case.
///
/// # Examples
///
/// ```ignore (extern-declaration)
/// # fn main() {
/// use std::ffi::CStr;
/// use std::os::raw::c_char;
///
/// extern {
/// fn my_string() -> *const c_char;
/// }
///
/// unsafe {
/// let slice = CStr::from_ptr(my_string());
/// println!("string returned: {}", slice.to_str().unwrap());
/// }
/// # }
/// ```
#[cfg(target_os = "horizon")]
#[stable(feature = "rust1", since = "1.0.0")]
pub unsafe fn from_ptr<'a>(ptr: *const c_char) -> &'a CStr {
let len = sys::strlen(ptr as *const u8);
let ptr = ptr as *const u8;
CStr::from_bytes_with_nul_unchecked(slice::from_raw_parts(ptr, len as usize + 1))
}
/// Creates a C string wrapper from a byte slice. /// Creates a C string wrapper from a byte slice.
/// ///
/// This function will cast the provided `bytes` to a `CStr` /// This function will cast the provided `bytes` to a `CStr`

32
ctr-std/src/ffi/os_str.rs

@ -664,6 +664,38 @@ impl<'a> From<&'a OsStr> for Rc<OsStr> {
} }
} }
#[stable(feature = "cow_from_osstr", since = "1.28.0")]
impl<'a> From<OsString> for Cow<'a, OsStr> {
#[inline]
fn from(s: OsString) -> Cow<'a, OsStr> {
Cow::Owned(s)
}
}
#[stable(feature = "cow_from_osstr", since = "1.28.0")]
impl<'a> From<&'a OsStr> for Cow<'a, OsStr> {
#[inline]
fn from(s: &'a OsStr) -> Cow<'a, OsStr> {
Cow::Borrowed(s)
}
}
#[stable(feature = "cow_from_osstr", since = "1.28.0")]
impl<'a> From<&'a OsString> for Cow<'a, OsStr> {
#[inline]
fn from(s: &'a OsString) -> Cow<'a, OsStr> {
Cow::Borrowed(s.as_os_str())
}
}
#[stable(feature = "osstring_from_cow_osstr", since = "1.28.0")]
impl<'a> From<Cow<'a, OsStr>> for OsString {
#[inline]
fn from(s: Cow<'a, OsStr>) -> Self {
s.into_owned()
}
}
#[stable(feature = "box_default_extra", since = "1.17.0")] #[stable(feature = "box_default_extra", since = "1.17.0")]
impl Default for Box<OsStr> { impl Default for Box<OsStr> {
fn default() -> Box<OsStr> { fn default() -> Box<OsStr> {

14
ctr-std/src/fs.rs

@ -295,8 +295,6 @@ pub fn read<P: AsRef<Path>>(path: P) -> io::Result<Vec<u8>> {
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```no_run
/// #![feature(fs_read_write)]
///
/// use std::fs; /// use std::fs;
/// use std::net::SocketAddr; /// use std::net::SocketAddr;
/// ///
@ -331,6 +329,7 @@ pub fn read_to_string<P: AsRef<Path>>(path: P) -> io::Result<String> {
/// ///
/// fn main() -> std::io::Result<()> { /// fn main() -> std::io::Result<()> {
/// fs::write("foo.txt", b"Lorem ipsum")?; /// fs::write("foo.txt", b"Lorem ipsum")?;
/// fs::write("bar.txt", "dolor sit")?;
/// Ok(()) /// Ok(())
/// } /// }
/// ``` /// ```
@ -1699,8 +1698,8 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
fs_imp::readlink(path.as_ref()) fs_imp::readlink(path.as_ref())
} }
/// Returns the canonical form of a path with all intermediate components /// Returns the canonical, absolute form of a path with all intermediate
/// normalized and symbolic links resolved. /// components normalized and symbolic links resolved.
/// ///
/// # Platform-specific behavior /// # Platform-specific behavior
/// ///
@ -1708,7 +1707,14 @@ pub fn read_link<P: AsRef<Path>>(path: P) -> io::Result<PathBuf> {
/// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows. /// and the `CreateFile` and `GetFinalPathNameByHandle` functions on Windows.
/// Note that, this [may change in the future][changes]. /// Note that, this [may change in the future][changes].
/// ///
/// On Windows, this converts the path to use [extended length path][path]
/// syntax, which allows your program to use longer path names, but means you
/// can only join backslash-delimited paths to it, and it may be incompatible
/// with other applications (if passed to the application on the command-line,
/// or written to a file another application may read).
///
/// [changes]: ../io/index.html#platform-specific-behavior /// [changes]: ../io/index.html#platform-specific-behavior
/// [path]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa365247(v=vs.85).aspx#maxpath
/// ///
/// # Errors /// # Errors
/// ///

29
ctr-std/src/lib.rs

@ -252,7 +252,6 @@
#![feature(collections_range)] #![feature(collections_range)]
#![feature(compiler_builtins_lib)] #![feature(compiler_builtins_lib)]
#![feature(const_fn)] #![feature(const_fn)]
#![cfg_attr(stage0, feature(core_float))]
#![feature(core_intrinsics)] #![feature(core_intrinsics)]
#![feature(dropck_eyepatch)] #![feature(dropck_eyepatch)]
#![feature(exact_size_is_empty)] #![feature(exact_size_is_empty)]
@ -260,10 +259,9 @@
#![feature(fs_read_write)] #![feature(fs_read_write)]
#![feature(fixed_size_array)] #![feature(fixed_size_array)]
#![feature(float_from_str_radix)] #![feature(float_from_str_radix)]
#![cfg_attr(stage0, feature(float_internals))]
#![feature(fn_traits)] #![feature(fn_traits)]
#![feature(fnbox)] #![feature(fnbox)]
#![cfg_attr(stage0, feature(generic_param_attrs))] #![feature(futures_api)]
#![feature(hashmap_internals)] #![feature(hashmap_internals)]
#![feature(heap_api)] #![feature(heap_api)]
#![feature(int_error_internals)] #![feature(int_error_internals)]
@ -277,7 +275,6 @@
#![feature(needs_panic_runtime)] #![feature(needs_panic_runtime)]
#![feature(never_type)] #![feature(never_type)]
#![feature(exhaustive_patterns)] #![feature(exhaustive_patterns)]
#![feature(nonzero)]
#![feature(num_bits_bytes)] #![feature(num_bits_bytes)]
#![feature(old_wrapping)] #![feature(old_wrapping)]
#![feature(on_unimplemented)] #![feature(on_unimplemented)]
@ -286,6 +283,7 @@
#![feature(panic_internals)] #![feature(panic_internals)]
#![feature(panic_unwind)] #![feature(panic_unwind)]
#![feature(peek)] #![feature(peek)]
#![feature(pin)]
#![feature(placement_new_protocol)] #![feature(placement_new_protocol)]
#![feature(prelude_import)] #![feature(prelude_import)]
#![feature(ptr_internals)] #![feature(ptr_internals)]
@ -320,6 +318,10 @@
#![cfg_attr(test, feature(update_panic_count))] #![cfg_attr(test, feature(update_panic_count))]
#![cfg_attr(windows, feature(used))] #![cfg_attr(windows, feature(used))]
#![feature(doc_alias)] #![feature(doc_alias)]
#![feature(doc_keyword)]
#![feature(float_internals)]
#![feature(panic_info_message)]
#![cfg_attr(not(stage0), feature(panic_implementation))]
#![default_lib_allocator] #![default_lib_allocator]
@ -368,11 +370,6 @@ extern crate ctru_sys as libctru;
#[allow(unused_extern_crates)] #[allow(unused_extern_crates)]
extern crate unwind; extern crate unwind;
// compiler-rt intrinsics
#[doc(masked)]
#[cfg(stage0)]
extern crate compiler_builtins;
// During testing, this crate is not actually the "real" std library, but rather // During testing, this crate is not actually the "real" std library, but rather
// it links to the real std library, which was compiled from this same source // it links to the real std library, which was compiled from this same source
// code. So any lang items std defines are conditionally excluded (or else they // code. So any lang items std defines are conditionally excluded (or else they
@ -468,6 +465,20 @@ pub use core::u128;
#[stable(feature = "core_hint", since = "1.27.0")] #[stable(feature = "core_hint", since = "1.27.0")]
pub use core::hint; pub use core::hint;
#[unstable(feature = "futures_api",
reason = "futures in libcore are unstable",
issue = "50547")]
pub mod task {
//! Types and Traits for working with asynchronous tasks.
pub use core::task::*;
pub use alloc_crate::task::*;
}
#[unstable(feature = "futures_api",
reason = "futures in libcore are unstable",
issue = "50547")]
pub use core::future;
pub mod f32; pub mod f32;
pub mod f64; pub mod f64;

17
ctr-std/src/macros.rs

@ -364,7 +364,6 @@ pub mod builtin {
/// ///
/// let s = fmt::format(format_args!("hello {}", "world")); /// let s = fmt::format(format_args!("hello {}", "world"));
/// assert_eq!(s, format!("hello {}", "world")); /// assert_eq!(s, format!("hello {}", "world"));
///
/// ``` /// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[macro_export]
@ -379,7 +378,7 @@ pub mod builtin {
/// compile time, yielding an expression of type `&'static str`. /// compile time, yielding an expression of type `&'static str`.
/// ///
/// If the environment variable is not defined, then a compilation error /// If the environment variable is not defined, then a compilation error
/// will be emitted. To not emit a compile error, use the [`option_env!`] /// will be emitted. To not emit a compile error, use the [`option_env!`]
/// macro instead. /// macro instead.
/// ///
/// [`option_env!`]: ../std/macro.option_env.html /// [`option_env!`]: ../std/macro.option_env.html
@ -390,6 +389,20 @@ pub mod builtin {
/// let path: &'static str = env!("PATH"); /// let path: &'static str = env!("PATH");
/// println!("the $PATH variable at the time of compiling was: {}", path); /// println!("the $PATH variable at the time of compiling was: {}", path);
/// ``` /// ```
///
/// You can customize the error message by passing a string as the second
/// parameter:
///
/// ```compile_fail
/// let doc: &'static str = env!("documentation", "what's that?!");
/// ```
///
/// If the `documentation` environment variable is not defined, you'll get
/// the following error:
///
/// ```text
/// error: what's that?!
/// ```
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
#[macro_export] #[macro_export]
macro_rules! env { macro_rules! env {

8
ctr-std/src/num.rs

@ -21,12 +21,8 @@ pub use core::num::{FpCategory, ParseIntError, ParseFloatError, TryFromIntError}
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub use core::num::Wrapping; pub use core::num::Wrapping;
#[unstable(feature = "nonzero", issue = "49137")] #[stable(feature = "nonzero", since = "1.28.0")]
#[allow(deprecated)] pub use core::num::{NonZeroU8, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU128, NonZeroUsize};
pub use core::num::{
NonZeroU8, NonZeroI8, NonZeroU16, NonZeroI16, NonZeroU32, NonZeroI32,
NonZeroU64, NonZeroI64, NonZeroU128, NonZeroI128, NonZeroUsize, NonZeroIsize,
};
#[cfg(test)] use fmt; #[cfg(test)] use fmt;
#[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem}; #[cfg(test)] use ops::{Add, Sub, Mul, Div, Rem};

393
ctr-std/src/os/horizon/fs.rs

@ -0,0 +1,393 @@
// 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 = "metadata_ext", since = "1.1.0")]
use libc;
use fs::Metadata;
use sys_common::AsInner;
#[allow(deprecated)]
use os::horizon::raw;
/// OS-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Gain a reference to the underlying `stat` structure which contains
/// the raw information returned by the OS.
///
/// The contents of the returned [`stat`] are **not** consistent across
/// Unix platforms. The `os::unix::fs::MetadataExt` trait contains the
/// cross-Unix abstractions contained within the raw stat.
///
/// [`stat`]: ../../../../std/os/linux/raw/struct.stat.html
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let stat = meta.as_raw_stat();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
#[rustc_deprecated(since = "1.8.0",
reason = "deprecated in favor of the accessor \
methods of this trait")]
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat;
/// Returns the device ID on which this file resides.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_dev());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_dev(&self) -> u64;
/// Returns the inode number.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ino());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ino(&self) -> u64;
/// Returns the file type and mode.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mode());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mode(&self) -> u32;
/// Returns the number of hard links to file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_nlink());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_nlink(&self) -> u64;
/// Returns the user ID of the file owner.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_uid());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_uid(&self) -> u32;
/// Returns the group ID of the file owner.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_gid());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_gid(&self) -> u32;
/// Returns the device ID that this file represents. Only relevant for special file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_rdev());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_rdev(&self) -> u64;
/// Returns the size of the file (if it is a regular file or a symbolic link) in bytes.
///
/// The size of a symbolic link is the length of the pathname it contains,
/// without a terminating null byte.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_size());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_size(&self) -> u64;
/// Returns the last access time.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_atime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime(&self) -> i64;
/// Returns the last access time, nano seconds part.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_atime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_atime_nsec(&self) -> i64;
/// Returns the last modification time.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mtime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime(&self) -> i64;
/// Returns the last modification time, nano seconds part.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_mtime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_mtime_nsec(&self) -> i64;
/// Returns the last status change time.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ctime());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime(&self) -> i64;
/// Returns the last status change time, nano seconds part.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_ctime_nsec());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_ctime_nsec(&self) -> i64;
/// Returns the "preferred" blocksize for efficient filesystem I/O.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_blksize());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blksize(&self) -> u64;
/// Returns the number of blocks allocated to the file, 512-byte units.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::io;
/// use std::os::linux::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// println!("{}", meta.st_blocks());
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext2", since = "1.8.0")]
fn st_blocks(&self) -> u64;
}
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for Metadata {
#[allow(deprecated)]
fn as_raw_stat(&self) -> &raw::stat {
unsafe {
&*(self.as_inner().as_inner() as *const libc::stat
as *const raw::stat)
}
}
fn st_dev(&self) -> u64 {
self.as_inner().as_inner().st_dev as u64
}
fn st_ino(&self) -> u64 {
self.as_inner().as_inner().st_ino as u64
}
fn st_mode(&self) -> u32 {
self.as_inner().as_inner().st_mode as u32
}
fn st_nlink(&self) -> u64 {
self.as_inner().as_inner().st_nlink as u64
}
fn st_uid(&self) -> u32 {
self.as_inner().as_inner().st_uid as u32
}
fn st_gid(&self) -> u32 {
self.as_inner().as_inner().st_gid as u32
}
fn st_rdev(&self) -> u64 {
self.as_inner().as_inner().st_rdev as u64
}
fn st_size(&self) -> u64 {
self.as_inner().as_inner().st_size as u64
}
fn st_atime(&self) -> i64 {
self.as_inner().as_inner().st_atime as i64
}
fn st_atime_nsec(&self) -> i64 {
//self.as_inner().as_inner().st_atime_nsec as i64
0i64
}
fn st_mtime(&self) -> i64 {
self.as_inner().as_inner().st_mtime as i64
}
fn st_mtime_nsec(&self) -> i64 {
//self.as_inner().as_inner().st_mtime_nsec as i64
0i64
}
fn st_ctime(&self) -> i64 {
//self.as_inner().as_inner().st_ctime as i64
0i64
}
fn st_ctime_nsec(&self) -> i64 {
//self.as_inner().as_inner().st_ctime_nsec as i64
0i64
}
fn st_blksize(&self) -> u64 {
self.as_inner().as_inner().st_blksize as u64
}
fn st_blocks(&self) -> u64 {
self.as_inner().as_inner().st_blocks as u64
}
}

16
ctr-std/src/os/horizon/mod.rs

@ -0,0 +1,16 @@
// 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.
//! Linux-specific definitions
#![stable(feature = "raw_ext", since = "1.1.0")]
pub mod raw;
pub mod fs;

275
ctr-std/src/os/horizon/raw.rs

@ -0,0 +1,275 @@
// 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.
//! Linux-specific raw type definitions
#![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)]
#![allow(missing_debug_implementations)]
use os::raw::c_ulong;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type dev_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type mode_t = u32;
#[stable(feature = "pthread_t", since = "1.8.0")]
pub type pthread_t = c_ulong;
#[doc(inline)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub use self::arch::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
#[cfg(any(target_arch = "x86",
target_arch = "le32",
target_arch = "powerpc",
target_arch = "arm",
target_arch = "asmjs",
target_arch = "wasm32"))]
mod arch {
use os::raw::{c_long, c_short, c_uint};
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_dev: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub __pad1: c_short,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub __st_ino: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mode: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_nlink: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_uid: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_gid: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_rdev: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub __pad2: c_uint,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_size: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blksize: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blocks: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ino: u64,
}
}
#[cfg(target_arch = "mips")]
mod arch {
use os::raw::{c_long, c_ulong};
#[cfg(target_env = "musl")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = i64;
#[cfg(not(target_env = "musl"))]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
#[cfg(target_env = "musl")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[cfg(not(target_env = "musl"))]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
#[cfg(target_env = "musl")]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[cfg(not(target_env = "musl"))]
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_dev: c_ulong,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_pad1: [c_long; 3],
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ino: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mode: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_nlink: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_uid: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_gid: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_rdev: c_ulong,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_pad2: [c_long; 2],
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_size: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blksize: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blocks: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_pad5: [c_long; 14],
}
}
#[cfg(any(target_arch = "mips64",
target_arch = "s390x",
target_arch = "sparc64"))]
mod arch {
pub use libc::{off_t, ino_t, nlink_t, blksize_t, blkcnt_t, stat, time_t};
}
#[cfg(target_arch = "aarch64")]
mod arch {
use os::raw::{c_long, c_int};
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_dev: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ino: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mode: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_nlink: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_uid: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_gid: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_rdev: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub __pad1: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_size: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blksize: i32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub __pad2: c_int,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blocks: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub __unused: [c_int; 2],
}
}
#[cfg(any(target_arch = "x86_64", target_arch = "powerpc64"))]
mod arch {
use os::raw::{c_long, c_int};
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blkcnt_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type ino_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type off_t = u64;
#[stable(feature = "raw_ext", since = "1.1.0")] pub type time_t = i64;
#[repr(C)]
#[derive(Clone)]
#[stable(feature = "raw_ext", since = "1.1.0")]
pub struct stat {
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_dev: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ino: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_nlink: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mode: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_uid: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_gid: u32,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub __pad0: c_int,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_rdev: u64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_size: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blksize: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_blocks: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_atime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_mtime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime: i64,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub st_ctime_nsec: c_long,
#[stable(feature = "raw_ext", since = "1.1.0")]
pub __unused: [c_long; 3],
}
}

1
ctr-std/src/os/mod.rs

@ -47,6 +47,7 @@ cfg_if! {
#[cfg(target_os = "solaris")] pub mod solaris; #[cfg(target_os = "solaris")] pub mod solaris;
#[cfg(target_os = "emscripten")] pub mod emscripten; #[cfg(target_os = "emscripten")] pub mod emscripten;
#[cfg(target_os = "fuchsia")] pub mod fuchsia; #[cfg(target_os = "fuchsia")] pub mod fuchsia;
#[cfg(target_os = "horizon")] pub mod horizon;
#[cfg(any(target_os = "redox", unix))] #[cfg(any(target_os = "redox", unix))]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]

113
ctr-std/src/panicking.rs

@ -76,7 +76,9 @@ static mut HOOK: Hook = Hook::Default;
/// is invoked. As such, the hook will run with both the aborting and unwinding /// is invoked. As such, the hook will run with both the aborting and unwinding
/// runtimes. The default hook prints a message to standard error and generates /// runtimes. The default hook prints a message to standard error and generates
/// a backtrace if requested, but this behavior can be customized with the /// a backtrace if requested, but this behavior can be customized with the
/// `set_hook` and `take_hook` functions. /// `set_hook` and [`take_hook`] functions.
///
/// [`take_hook`]: ./fn.take_hook.html
/// ///
/// The hook is provided with a `PanicInfo` struct which contains information /// The hook is provided with a `PanicInfo` struct which contains information
/// about the origin of the panic, including the payload passed to `panic!` and /// about the origin of the panic, including the payload passed to `panic!` and
@ -121,6 +123,10 @@ pub fn set_hook(hook: Box<Fn(&PanicInfo) + 'static + Sync + Send>) {
/// Unregisters the current panic hook, returning it. /// Unregisters the current panic hook, returning it.
/// ///
/// *See also the function [`set_hook`].*
///
/// [`set_hook`]: ./fn.set_hook.html
///
/// If no custom hook is registered, the default hook will be returned. /// If no custom hook is registered, the default hook will be returned.
/// ///
/// # Panics /// # Panics
@ -217,7 +223,8 @@ fn default_hook(info: &PanicInfo) {
} }
let write = |err: &mut ::io::Write| { let write = |err: &mut ::io::Write| {
let _ = write!(err, "{}", error_text); let _ = writeln!(err, "thread '{}' panicked at '{}', {}",
name, msg, location);
#[cfg(feature = "backtrace")] #[cfg(feature = "backtrace")]
{ {
@ -337,8 +344,8 @@ pub fn panicking() -> bool {
/// Entry point of panic from the libcore crate. /// Entry point of panic from the libcore crate.
#[cfg(not(test))] #[cfg(not(test))]
#[cfg(stage0)]
#[lang = "panic_fmt"] #[lang = "panic_fmt"]
#[unwind(allowed)]
pub extern fn rust_begin_panic(msg: fmt::Arguments, pub extern fn rust_begin_panic(msg: fmt::Arguments,
file: &'static str, file: &'static str,
line: u32, line: u32,
@ -346,59 +353,107 @@ pub extern fn rust_begin_panic(msg: fmt::Arguments,
begin_panic_fmt(&msg, &(file, line, col)) begin_panic_fmt(&msg, &(file, line, col))
} }
/// Entry point of panic from the libcore crate.
#[cfg(not(test))]
#[cfg(not(stage0))]
#[panic_implementation]
#[unwind(allowed)]
pub fn rust_begin_panic(info: &PanicInfo) -> ! {
continue_panic_fmt(&info)
}
/// The entry point for panicking with a formatted message. /// The entry point for panicking with a formatted message.
/// ///
/// This is designed to reduce the amount of code required at the call /// This is designed to reduce the amount of code required at the call
/// site as much as possible (so that `panic!()` has as low an impact /// site as much as possible (so that `panic!()` has as low an impact
/// on (e.g.) the inlining of other functions as possible), by moving /// on (e.g.) the inlining of other functions as possible), by moving
/// the actual formatting into this shared place. /// the actual formatting into this shared place.
#[cfg(stage0)]
#[unstable(feature = "libstd_sys_internals", #[unstable(feature = "libstd_sys_internals",
reason = "used by the panic! macro", reason = "used by the panic! macro",
issue = "0")] issue = "0")]
#[inline(never)] #[cold] #[inline(never)] #[cold]
pub fn begin_panic_fmt(msg: &fmt::Arguments, pub fn begin_panic_fmt(msg: &fmt::Arguments,
file_line_col: &(&'static str, u32, u32)) -> ! { file_line_col: &(&'static str, u32, u32)) -> ! {
use fmt::Write;
// We do two allocations here, unfortunately. But (a) they're // We do two allocations here, unfortunately. But (a) they're
// required with the current scheme, and (b) we don't handle // required with the current scheme, and (b) we don't handle
// panic + OOM properly anyway (see comment in begin_panic // panic + OOM properly anyway (see comment in begin_panic
// below). // below).
rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col); rust_panic_with_hook(&mut PanicPayload::new(msg), Some(msg), file_line_col);
}
struct PanicPayload<'a> { // NOTE(stage0) move into `continue_panic_fmt` on next stage0 update
inner: &'a fmt::Arguments<'a>, struct PanicPayload<'a> {
string: Option<String>, inner: &'a fmt::Arguments<'a>,
string: Option<String>,
}
impl<'a> PanicPayload<'a> {
fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> {
PanicPayload { inner, string: None }
} }
impl<'a> PanicPayload<'a> { fn fill(&mut self) -> &mut String {
fn new(inner: &'a fmt::Arguments<'a>) -> PanicPayload<'a> { use fmt::Write;
PanicPayload { inner, string: None }
}
fn fill(&mut self) -> &mut String { let inner = self.inner;
let inner = self.inner; self.string.get_or_insert_with(|| {
self.string.get_or_insert_with(|| { let mut s = String::new();
let mut s = String::new(); drop(s.write_fmt(*inner));
drop(s.write_fmt(*inner)); s
s })
})
}
} }
}
unsafe impl<'a> BoxMeUp for PanicPayload<'a> { unsafe impl<'a> BoxMeUp for PanicPayload<'a> {
fn box_me_up(&mut self) -> *mut (Any + Send) { fn box_me_up(&mut self) -> *mut (Any + Send) {
let contents = mem::replace(self.fill(), String::new()); let contents = mem::replace(self.fill(), String::new());
Box::into_raw(Box::new(contents)) Box::into_raw(Box::new(contents))
} }
fn get(&mut self) -> &(Any + Send) { fn get(&mut self) -> &(Any + Send) {
self.fill() self.fill()
}
} }
} }
/// The entry point for panicking with a formatted message.
///
/// This is designed to reduce the amount of code required at the call
/// site as much as possible (so that `panic!()` has as low an impact
/// on (e.g.) the inlining of other functions as possible), by moving
/// the actual formatting into this shared place.
#[cfg(not(stage0))]
#[unstable(feature = "libstd_sys_internals",
reason = "used by the panic! macro",
issue = "0")]
#[inline(never)] #[cold]
pub fn begin_panic_fmt(msg: &fmt::Arguments,
file_line_col: &(&'static str, u32, u32)) -> ! {
let (file, line, col) = *file_line_col;
let info = PanicInfo::internal_constructor(
Some(msg),
Location::internal_constructor(file, line, col),
);
continue_panic_fmt(&info)
}
#[cfg(not(stage0))]
fn continue_panic_fmt(info: &PanicInfo) -> ! {
// We do two allocations here, unfortunately. But (a) they're
// required with the current scheme, and (b) we don't handle
// panic + OOM properly anyway (see comment in begin_panic
// below).
let loc = info.location().unwrap(); // The current implementation always returns Some
let msg = info.message().unwrap(); // The current implementation always returns Some
let file_line_col = (loc.file(), loc.line(), loc.column());
rust_panic_with_hook(
&mut PanicPayload::new(msg),
info.message(),
&file_line_col);
}
/// This is the entry point of panicking for panic!() and assert!(). /// This is the entry point of panicking for panic!() and assert!().
#[unstable(feature = "libstd_sys_internals", #[unstable(feature = "libstd_sys_internals",
reason = "used by the panic! macro", reason = "used by the panic! macro",
@ -449,7 +504,7 @@ pub fn begin_panic<M: Any + Send>(msg: M, file_line_col: &(&'static str, u32, u3
/// abort or unwind. /// abort or unwind.
fn rust_panic_with_hook(payload: &mut BoxMeUp, fn rust_panic_with_hook(payload: &mut BoxMeUp,
message: Option<&fmt::Arguments>, message: Option<&fmt::Arguments>,
file_line_col: &(&'static str, u32, u32)) -> ! { file_line_col: &(&str, u32, u32)) -> ! {
let (file, line, col) = *file_line_col; let (file, line, col) = *file_line_col;
let panics = update_panic_count(1); let panics = update_panic_count(1);

28
ctr-std/src/path.rs

@ -201,10 +201,10 @@ impl<'a> Prefix<'a> {
os_str_as_u8_slice(s).len() os_str_as_u8_slice(s).len()
} }
match *self { match *self {
#[cfg(target_os = "horizon")] #[cfg(target_os = "horizon")]
Verbatim(x) => 1 + os_str_len(x),
#[cfg(not(target_os = "horizon"))]
Verbatim(x) => 1 + os_str_len(x), Verbatim(x) => 1 + os_str_len(x),
#[cfg(target_os = "windows")]
Verbatim(x) => 4 + os_str_len(x),
VerbatimUNC(x, y) => { VerbatimUNC(x, y) => {
8 + os_str_len(x) + 8 + os_str_len(x) +
if os_str_len(y) > 0 { if os_str_len(y) > 0 {
@ -1463,7 +1463,7 @@ impl<P: AsRef<Path>> iter::Extend<P> for PathBuf {
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
impl fmt::Debug for PathBuf { impl fmt::Debug for PathBuf {
fn fmt(&self, formatter: &mut fmt::Formatter) -> Result<(), fmt::Error> { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
fmt::Debug::fmt(&**self, formatter) fmt::Debug::fmt(&**self, formatter)
} }
} }
@ -1507,6 +1507,22 @@ impl<'a> From<PathBuf> for Cow<'a, Path> {
} }
} }
#[stable(feature = "cow_from_pathbuf_ref", since = "1.28.0")]
impl<'a> From<&'a PathBuf> for Cow<'a, Path> {
#[inline]
fn from(p: &'a PathBuf) -> Cow<'a, Path> {
Cow::Borrowed(p.as_path())
}
}
#[stable(feature = "pathbuf_from_cow_path", since = "1.28.0")]
impl<'a> From<Cow<'a, Path>> for PathBuf {
#[inline]
fn from(p: Cow<'a, Path>) -> Self {
p.into_owned()
}
}
#[stable(feature = "shared_from_slice2", since = "1.24.0")] #[stable(feature = "shared_from_slice2", since = "1.24.0")]
impl From<PathBuf> for Arc<Path> { impl From<PathBuf> for Arc<Path> {
#[inline] #[inline]
@ -2287,8 +2303,8 @@ impl Path {
fs::symlink_metadata(self) fs::symlink_metadata(self)
} }
/// Returns the canonical form of the path with all intermediate components /// Returns the canonical, absolute form of the path with all intermediate
/// normalized and symbolic links resolved. /// components normalized and symbolic links resolved.
/// ///
/// This is an alias to [`fs::canonicalize`]. /// This is an alias to [`fs::canonicalize`].
/// ///

77
ctr-std/src/primitive_docs.rs

@ -116,6 +116,8 @@ mod prim_bool { }
/// ///
/// # `!` and generics /// # `!` and generics
/// ///
/// ## Infallible errors
///
/// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`] /// The main place you'll see `!` used explicitly is in generic code. Consider the [`FromStr`]
/// trait: /// trait:
/// ///
@ -144,9 +146,60 @@ mod prim_bool { }
/// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain /// [`Ok`] variant. This illustrates another behaviour of `!` - it can be used to "delete" certain
/// enum variants from generic types like `Result`. /// enum variants from generic types like `Result`.
/// ///
/// ## Infinite loops
///
/// While [`Result<T, !>`] is very useful for removing errors, `!` can also be used to remove
/// successes as well. If we think of [`Result<T, !>`] as "if this function returns, it has not
/// errored," we get a very intuitive idea of [`Result<!, E>`] as well: if the function returns, it
/// *has* errored.
///
/// For example, consider the case of a simple web server, which can be simplified to:
///
/// ```ignore (hypothetical-example)
/// loop {
/// let (client, request) = get_request().expect("disconnected");
/// let response = request.process();
/// response.send(client);
/// }
/// ```
///
/// Currently, this isn't ideal, because we simply panic whenever we fail to get a new connection.
/// Instead, we'd like to keep track of this error, like this:
///
/// ```ignore (hypothetical-example)
/// loop {
/// match get_request() {
/// Err(err) => break err,
/// Ok((client, request)) => {
/// let response = request.process();
/// response.send(client);
/// },
/// }
/// }
/// ```
///
/// Now, when the server disconnects, we exit the loop with an error instead of panicking. While it
/// might be intuitive to simply return the error, we might want to wrap it in a [`Result<!, E>`]
/// instead:
///
/// ```ignore (hypothetical-example)
/// fn server_loop() -> Result<!, ConnectionError> {
/// loop {
/// let (client, request) = get_request()?;
/// let response = request.process();
/// response.send(client);
/// }
/// }
/// ```
///
/// Now, we can use `?` instead of `match`, and the return type makes a lot more sense: if the loop
/// ever stops, it means that an error occurred. We don't even have to wrap the loop in an `Ok`
/// because `!` coerces to `Result<!, ConnectionError>` automatically.
///
/// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str /// [`String::from_str`]: str/trait.FromStr.html#tymethod.from_str
/// [`Result<String, !>`]: result/enum.Result.html /// [`Result<String, !>`]: result/enum.Result.html
/// [`Result<T, !>`]: result/enum.Result.html /// [`Result<T, !>`]: result/enum.Result.html
/// [`Result<!, E>`]: result/enum.Result.html
/// [`Ok`]: result/enum.Result.html#variant.Ok /// [`Ok`]: result/enum.Result.html#variant.Ok
/// [`String`]: string/struct.String.html /// [`String`]: string/struct.String.html
/// [`Err`]: result/enum.Result.html#variant.Err /// [`Err`]: result/enum.Result.html#variant.Err
@ -317,6 +370,8 @@ mod prim_unit { }
// //
/// Raw, unsafe pointers, `*const T`, and `*mut T`. /// Raw, unsafe pointers, `*const T`, and `*mut T`.
/// ///
/// *[See also the `std::ptr` module](ptr/index.html).*
///
/// Working with raw pointers in Rust is uncommon, /// Working with raw pointers in Rust is uncommon,
/// typically limited to a few patterns. /// typically limited to a few patterns.
/// ///
@ -391,8 +446,6 @@ mod prim_unit { }
/// but C APIs hand out a lot of pointers generally, so are a common source /// but C APIs hand out a lot of pointers generally, so are a common source
/// of raw pointers in Rust. /// of raw pointers in Rust.
/// ///
/// *[See also the `std::ptr` module](ptr/index.html).*
///
/// [`null`]: ../std/ptr/fn.null.html /// [`null`]: ../std/ptr/fn.null.html
/// [`null_mut`]: ../std/ptr/fn.null_mut.html /// [`null_mut`]: ../std/ptr/fn.null_mut.html
/// [`is_null`]: ../std/primitive.pointer.html#method.is_null /// [`is_null`]: ../std/primitive.pointer.html#method.is_null
@ -510,6 +563,8 @@ mod prim_array { }
// //
/// A dynamically-sized view into a contiguous sequence, `[T]`. /// A dynamically-sized view into a contiguous sequence, `[T]`.
/// ///
/// *[See also the `std::slice` module](slice/index.html).*
///
/// Slices are a view into a block of memory represented as a pointer and a /// Slices are a view into a block of memory represented as a pointer and a
/// length. /// length.
/// ///
@ -532,8 +587,6 @@ mod prim_array { }
/// assert_eq!(x, &[1, 7, 3]); /// assert_eq!(x, &[1, 7, 3]);
/// ``` /// ```
/// ///
/// *[See also the `std::slice` module](slice/index.html).*
///
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_slice { } mod prim_slice { }
@ -541,15 +594,13 @@ mod prim_slice { }
// //
/// String slices. /// String slices.
/// ///
/// *[See also the `std::str` module](str/index.html).*
///
/// The `str` type, also called a 'string slice', is the most primitive string /// The `str` type, also called a 'string slice', is the most primitive string
/// type. It is usually seen in its borrowed form, `&str`. It is also the type /// type. It is usually seen in its borrowed form, `&str`. It is also the type
/// of string literals, `&'static str`. /// of string literals, `&'static str`.
/// ///
/// Strings slices are always valid UTF-8. /// String slices are always valid UTF-8.
///
/// This documentation describes a number of methods and trait implementations
/// on the `str` type. For technical reasons, there is additional, separate
/// documentation in the [`std::str`](str/index.html) module as well.
/// ///
/// # Examples /// # Examples
/// ///
@ -809,11 +860,11 @@ mod prim_u128 { }
// //
/// The pointer-sized signed integer type. /// The pointer-sized signed integer type.
/// ///
/// *[See also the `std::isize` module](isize/index.html).*
///
/// The size of this primitive is how many bytes it takes to reference any /// The size of this primitive is how many bytes it takes to reference any
/// location in memory. For example, on a 32 bit target, this is 4 bytes /// location in memory. For example, on a 32 bit target, this is 4 bytes
/// and on a 64 bit target, this is 8 bytes. /// and on a 64 bit target, this is 8 bytes.
///
/// *[See also the `std::isize` module](isize/index.html).*
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_isize { } mod prim_isize { }
@ -821,11 +872,11 @@ mod prim_isize { }
// //
/// The pointer-sized unsigned integer type. /// The pointer-sized unsigned integer type.
/// ///
/// *[See also the `std::usize` module](usize/index.html).*
///
/// The size of this primitive is how many bytes it takes to reference any /// The size of this primitive is how many bytes it takes to reference any
/// location in memory. For example, on a 32 bit target, this is 4 bytes /// location in memory. For example, on a 32 bit target, this is 4 bytes
/// and on a 64 bit target, this is 8 bytes. /// and on a 64 bit target, this is 8 bytes.
///
/// *[See also the `std::usize` module](usize/index.html).*
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
mod prim_usize { } mod prim_usize { }

8
ctr-std/src/process.rs

@ -1099,7 +1099,7 @@ impl fmt::Display for ExitStatus {
/// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937 /// [RFC #1937]: https://github.com/rust-lang/rfcs/pull/1937
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
pub struct ExitCode(imp::ExitCode); pub struct ExitCode(pub u8);
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
impl ExitCode { impl ExitCode {
@ -1109,7 +1109,7 @@ impl ExitCode {
/// termination, so there's no need to return this from `main` unless /// termination, so there's no need to return this from `main` unless
/// you're also returning other possible codes. /// you're also returning other possible codes.
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
pub const SUCCESS: ExitCode = ExitCode(imp::ExitCode::SUCCESS); pub const SUCCESS: ExitCode = ExitCode(0 as _);
/// The canonical ExitCode for unsuccessful termination on this platform. /// The canonical ExitCode for unsuccessful termination on this platform.
/// ///
@ -1117,7 +1117,7 @@ impl ExitCode {
/// instead returning `Err(_)` and `Ok(())` respectively, which will /// instead returning `Err(_)` and `Ok(())` respectively, which will
/// return the same codes (but will also `eprintln!` the error). /// return the same codes (but will also `eprintln!` the error).
#[unstable(feature = "process_exitcode_placeholder", issue = "48711")] #[unstable(feature = "process_exitcode_placeholder", issue = "48711")]
pub const FAILURE: ExitCode = ExitCode(imp::ExitCode::FAILURE); pub const FAILURE: ExitCode = ExitCode(-1 as _);
} }
impl Child { impl Child {
@ -1493,7 +1493,7 @@ impl<E: fmt::Debug> Termination for Result<!, E> {
impl Termination for ExitCode { impl Termination for ExitCode {
#[inline] #[inline]
fn report(self) -> i32 { fn report(self) -> i32 {
self.0.as_i32() self.0 as i32
} }
} }

2
ctr-std/src/sync/mutex.rs

@ -150,7 +150,7 @@ unsafe impl<T: ?Sized + Send> Sync for Mutex<T> { }
/// [`lock`]: struct.Mutex.html#method.lock /// [`lock`]: struct.Mutex.html#method.lock
/// [`try_lock`]: struct.Mutex.html#method.try_lock /// [`try_lock`]: struct.Mutex.html#method.try_lock
/// [`Mutex`]: struct.Mutex.html /// [`Mutex`]: struct.Mutex.html
#[must_use] #[must_use = "if unused the Mutex will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct MutexGuard<'a, T: ?Sized + 'a> { pub struct MutexGuard<'a, T: ?Sized + 'a> {
// funny underscores due to how Deref/DerefMut currently work (they // funny underscores due to how Deref/DerefMut currently work (they

23
ctr-std/src/sync/once.rs

@ -73,16 +73,17 @@ use thread::{self, Thread};
/// A synchronization primitive which can be used to run a one-time global /// A synchronization primitive which can be used to run a one-time global
/// initialization. Useful for one-time initialization for FFI or related /// initialization. Useful for one-time initialization for FFI or related
/// functionality. This type can only be constructed with the [`ONCE_INIT`] /// functionality. This type can only be constructed with the [`ONCE_INIT`]
/// value. /// value or the equivalent [`Once::new`] constructor.
/// ///
/// [`ONCE_INIT`]: constant.ONCE_INIT.html /// [`ONCE_INIT`]: constant.ONCE_INIT.html
/// [`Once::new`]: struct.Once.html#method.new
/// ///
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::sync::{Once, ONCE_INIT}; /// use std::sync::Once;
/// ///
/// static START: Once = ONCE_INIT; /// static START: Once = Once::new();
/// ///
/// START.call_once(|| { /// START.call_once(|| {
/// // run initialization here /// // run initialization here
@ -180,10 +181,10 @@ impl Once {
/// # Examples /// # Examples
/// ///
/// ``` /// ```
/// use std::sync::{Once, ONCE_INIT}; /// use std::sync::Once;
/// ///
/// static mut VAL: usize = 0; /// static mut VAL: usize = 0;
/// static INIT: Once = ONCE_INIT; /// static INIT: Once = Once::new();
/// ///
/// // Accessing a `static mut` is unsafe much of the time, but if we do so /// // Accessing a `static mut` is unsafe much of the time, but if we do so
/// // in a synchronized fashion (e.g. write once or read all) then we're /// // in a synchronized fashion (e.g. write once or read all) then we're
@ -248,10 +249,10 @@ impl Once {
/// ``` /// ```
/// #![feature(once_poison)] /// #![feature(once_poison)]
/// ///
/// use std::sync::{Once, ONCE_INIT}; /// use std::sync::Once;
/// use std::thread; /// use std::thread;
/// ///
/// static INIT: Once = ONCE_INIT; /// static INIT: Once = Once::new();
/// ///
/// // poison the once /// // poison the once
/// let handle = thread::spawn(|| { /// let handle = thread::spawn(|| {
@ -431,10 +432,10 @@ impl OnceState {
/// ``` /// ```
/// #![feature(once_poison)] /// #![feature(once_poison)]
/// ///
/// use std::sync::{Once, ONCE_INIT}; /// use std::sync::Once;
/// use std::thread; /// use std::thread;
/// ///
/// static INIT: Once = ONCE_INIT; /// static INIT: Once = Once::new();
/// ///
/// // poison the once /// // poison the once
/// let handle = thread::spawn(|| { /// let handle = thread::spawn(|| {
@ -452,9 +453,9 @@ impl OnceState {
/// ``` /// ```
/// #![feature(once_poison)] /// #![feature(once_poison)]
/// ///
/// use std::sync::{Once, ONCE_INIT}; /// use std::sync::Once;
/// ///
/// static INIT: Once = ONCE_INIT; /// static INIT: Once = Once::new();
/// ///
/// INIT.call_once_force(|state| { /// INIT.call_once_force(|state| {
/// assert!(!state.poisoned()); /// assert!(!state.poisoned());

4
ctr-std/src/sync/rwlock.rs

@ -94,7 +94,7 @@ unsafe impl<T: ?Sized + Send + Sync> Sync for RwLock<T> {}
/// [`read`]: struct.RwLock.html#method.read /// [`read`]: struct.RwLock.html#method.read
/// [`try_read`]: struct.RwLock.html#method.try_read /// [`try_read`]: struct.RwLock.html#method.try_read
/// [`RwLock`]: struct.RwLock.html /// [`RwLock`]: struct.RwLock.html
#[must_use] #[must_use = "if unused the RwLock will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLockReadGuard<'a, T: ?Sized + 'a> { pub struct RwLockReadGuard<'a, T: ?Sized + 'a> {
__lock: &'a RwLock<T>, __lock: &'a RwLock<T>,
@ -115,7 +115,7 @@ unsafe impl<'a, T: ?Sized + Sync> Sync for RwLockReadGuard<'a, T> {}
/// [`write`]: struct.RwLock.html#method.write /// [`write`]: struct.RwLock.html#method.write
/// [`try_write`]: struct.RwLock.html#method.try_write /// [`try_write`]: struct.RwLock.html#method.try_write
/// [`RwLock`]: struct.RwLock.html /// [`RwLock`]: struct.RwLock.html
#[must_use] #[must_use = "if unused the RwLock will immediately unlock"]
#[stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")]
pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> { pub struct RwLockWriteGuard<'a, T: ?Sized + 'a> {
__lock: &'a RwLock<T>, __lock: &'a RwLock<T>,

51
ctr-std/src/sys/cloudabi/abi/bitflags.rs

@ -0,0 +1,51 @@
// Copyright (c) 2018 Nuxi (https://nuxi.nl/) and contributors.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// 2. Redistributions in binary form must reproduce the above copyright
// notice, this list of conditions and the following disclaimer in the
// documentation and/or other materials provided with the distribution.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
// OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
// HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
// OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
// SUCH DAMAGE.
// Appease Rust's tidy.
// ignore-license
#[cfg(feature = "bitflags")]
#[macro_use]
extern crate bitflags;
// Minimal implementation of bitflags! in case we can't depend on the bitflags
// crate. Only implements `bits()` and a `from_bits_truncate()` that doesn't
// actually truncate.
#[cfg(not(feature = "bitflags"))]
macro_rules! bitflags {
(
$(#[$attr:meta])*
pub struct $name:ident: $type:ty {
$($(#[$const_attr:meta])* const $const:ident = $val:expr;)*
}
) => {
$(#[$attr])*
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct $name { bits: $type }
impl $name {
$($(#[$const_attr])* pub const $const: $name = $name{ bits: $val };)*
pub fn bits(&self) -> $type { self.bits }
pub fn from_bits_truncate(bits: $type) -> Self { $name{ bits } }
}
}
}

2847
ctr-std/src/sys/cloudabi/abi/cloudabi.rs

File diff suppressed because it is too large Load Diff

13
ctr-std/src/sys/cloudabi/abi/mod.rs

@ -0,0 +1,13 @@
// Copyright 2018 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(warnings)]
mod cloudabi;
pub use self::cloudabi::*;

17
ctr-std/src/sys/cloudabi/args.rs

@ -0,0 +1,17 @@
// Copyright 2018 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 use sys::cloudabi::shims::args::*;
#[allow(dead_code)]
pub fn init(_: isize, _: *const *const u8) {}
#[allow(dead_code)]
pub fn cleanup() {}

122
ctr-std/src/sys/cloudabi/backtrace.rs

@ -0,0 +1,122 @@
// Copyright 2014-2018 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 error::Error;
use ffi::CStr;
use intrinsics;
use io;
use libc;
use sys_common::backtrace::Frame;
use unwind as uw;
pub struct BacktraceContext;
struct Context<'a> {
idx: usize,
frames: &'a mut [Frame],
}
#[derive(Debug)]
struct UnwindError(uw::_Unwind_Reason_Code);
impl Error for UnwindError {
fn description(&self) -> &'static str {
"unexpected return value while unwinding"
}
}
impl ::fmt::Display for UnwindError {
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
write!(f, "{}: {:?}", self.description(), self.0)
}
}
#[inline(never)] // if we know this is a function call, we can skip it when
// tracing
pub fn unwind_backtrace(frames: &mut [Frame]) -> io::Result<(usize, BacktraceContext)> {
let mut cx = Context { idx: 0, frames };
let result_unwind =
unsafe { uw::_Unwind_Backtrace(trace_fn, &mut cx as *mut Context as *mut libc::c_void) };
// See libunwind:src/unwind/Backtrace.c for the return values.
// No, there is no doc.
match result_unwind {
// These return codes seem to be benign and need to be ignored for backtraces
// to show up properly on all tested platforms.
uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
Ok((cx.idx, BacktraceContext))
}
_ => Err(io::Error::new(
io::ErrorKind::Other,
UnwindError(result_unwind),
)),
}
}
extern "C" 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) };
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 {
// this is a non-signaling frame, so `ip` refers to the address
// after the calling instruction. account for that.
ip = (ip as usize - 1) as *mut _;
}
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;
}
uw::_URC_NO_REASON
}
pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
where
F: FnMut(&[u8], u32) -> io::Result<()>,
{
// No way to obtain this information on CloudABI.
Ok(false)
}
pub fn resolve_symname<F>(frame: Frame, callback: F, _: &BacktraceContext) -> io::Result<()>
where
F: FnOnce(Option<&str>) -> io::Result<()>,
{
unsafe {
let mut info: Dl_info = intrinsics::init();
let symname =
if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() {
None
} else {
CStr::from_ptr(info.dli_sname).to_str().ok()
};
callback(symname)
}
}
#[repr(C)]
struct Dl_info {
dli_fname: *const libc::c_char,
dli_fbase: *mut libc::c_void,
dli_sname: *const libc::c_char,
dli_saddr: *mut libc::c_void,
}
extern "C" {
fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
}

169
ctr-std/src/sys/cloudabi/condvar.rs

@ -0,0 +1,169 @@
// Copyright 2018 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 cell::UnsafeCell;
use mem;
use sync::atomic::{AtomicU32, Ordering};
use sys::cloudabi::abi;
use sys::mutex::{self, Mutex};
use sys::time::dur2intervals;
use time::Duration;
extern "C" {
#[thread_local]
static __pthread_thread_id: abi::tid;
}
pub struct Condvar {
condvar: UnsafeCell<AtomicU32>,
}
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
impl Condvar {
pub const fn new() -> Condvar {
Condvar {
condvar: UnsafeCell::new(AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0)),
}
}
pub unsafe fn init(&mut self) {}
pub unsafe fn notify_one(&self) {
let condvar = self.condvar.get();
if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
let ret = abi::condvar_signal(condvar as *mut abi::condvar, abi::scope::PRIVATE, 1);
assert_eq!(
ret,
abi::errno::SUCCESS,
"Failed to signal on condition variable"
);
}
}
pub unsafe fn notify_all(&self) {
let condvar = self.condvar.get();
if (*condvar).load(Ordering::Relaxed) != abi::CONDVAR_HAS_NO_WAITERS.0 {
let ret = abi::condvar_signal(
condvar as *mut abi::condvar,
abi::scope::PRIVATE,
abi::nthreads::max_value(),
);
assert_eq!(
ret,
abi::errno::SUCCESS,
"Failed to broadcast on condition variable"
);
}
}
pub unsafe fn wait(&self, mutex: &Mutex) {
let mutex = mutex::raw(mutex);
assert_eq!(
(*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
"This lock is not write-locked by this thread"
);
// Call into the kernel to wait on the condition variable.
let condvar = self.condvar.get();
let subscription = abi::subscription {
type_: abi::eventtype::CONDVAR,
union: abi::subscription_union {
condvar: abi::subscription_condvar {
condvar: condvar as *mut abi::condvar,
condvar_scope: abi::scope::PRIVATE,
lock: mutex as *mut abi::lock,
lock_scope: abi::scope::PRIVATE,
},
},
..mem::zeroed()
};
let mut event: abi::event = mem::uninitialized();
let mut nevents: usize = mem::uninitialized();
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
assert_eq!(
ret,
abi::errno::SUCCESS,
"Failed to wait on condition variable"
);
assert_eq!(
event.error,
abi::errno::SUCCESS,
"Failed to wait on condition variable"
);
}
pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
let mutex = mutex::raw(mutex);
assert_eq!(
(*mutex).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
"This lock is not write-locked by this thread"
);
// Call into the kernel to wait on the condition variable.
let condvar = self.condvar.get();
let subscriptions = [
abi::subscription {
type_: abi::eventtype::CONDVAR,
union: abi::subscription_union {
condvar: abi::subscription_condvar {
condvar: condvar as *mut abi::condvar,
condvar_scope: abi::scope::PRIVATE,
lock: mutex as *mut abi::lock,
lock_scope: abi::scope::PRIVATE,
},
},
..mem::zeroed()
},
abi::subscription {
type_: abi::eventtype::CLOCK,
union: abi::subscription_union {
clock: abi::subscription_clock {
clock_id: abi::clockid::MONOTONIC,
timeout: dur2intervals(&dur),
..mem::zeroed()
},
},
..mem::zeroed()
},
];
let mut events: [abi::event; 2] = mem::uninitialized();
let mut nevents: usize = mem::uninitialized();
let ret = abi::poll(subscriptions.as_ptr(), events.as_mut_ptr(), 2, &mut nevents);
assert_eq!(
ret,
abi::errno::SUCCESS,
"Failed to wait on condition variable"
);
for i in 0..nevents {
assert_eq!(
events[i].error,
abi::errno::SUCCESS,
"Failed to wait on condition variable"
);
if events[i].type_ == abi::eventtype::CONDVAR {
return true;
}
}
false
}
pub unsafe fn destroy(&self) {
let condvar = self.condvar.get();
assert_eq!(
(*condvar).load(Ordering::Relaxed),
abi::CONDVAR_HAS_NO_WAITERS.0,
"Attempted to destroy a condition variable with blocked threads"
);
}
}

76
ctr-std/src/sys/cloudabi/mod.rs

@ -0,0 +1,76 @@
// Copyright 2018 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 mem;
pub mod args;
#[cfg(feature = "backtrace")]
pub mod backtrace;
#[path = "../unix/cmath.rs"]
pub mod cmath;
pub mod condvar;
#[path = "../unix/memchr.rs"]
pub mod memchr;
pub mod mutex;
pub mod os;
#[path = "../unix/os_str.rs"]
pub mod os_str;
pub mod rwlock;
pub mod stack_overflow;
pub mod stdio;
pub mod thread;
#[path = "../unix/thread_local.rs"]
pub mod thread_local;
pub mod time;
mod abi;
mod shims;
pub use self::shims::*;
#[allow(dead_code)]
pub fn init() {}
pub fn decode_error_kind(errno: i32) -> io::ErrorKind {
match errno {
x if x == abi::errno::ACCES as i32 => io::ErrorKind::PermissionDenied,
x if x == abi::errno::ADDRINUSE as i32 => io::ErrorKind::AddrInUse,
x if x == abi::errno::ADDRNOTAVAIL as i32 => io::ErrorKind::AddrNotAvailable,
x if x == abi::errno::AGAIN as i32 => io::ErrorKind::WouldBlock,
x if x == abi::errno::CONNABORTED as i32 => io::ErrorKind::ConnectionAborted,
x if x == abi::errno::CONNREFUSED as i32 => io::ErrorKind::ConnectionRefused,
x if x == abi::errno::CONNRESET as i32 => io::ErrorKind::ConnectionReset,
x if x == abi::errno::EXIST as i32 => io::ErrorKind::AlreadyExists,
x if x == abi::errno::INTR as i32 => io::ErrorKind::Interrupted,
x if x == abi::errno::INVAL as i32 => io::ErrorKind::InvalidInput,
x if x == abi::errno::NOENT as i32 => io::ErrorKind::NotFound,
x if x == abi::errno::NOTCONN as i32 => io::ErrorKind::NotConnected,
x if x == abi::errno::PERM as i32 => io::ErrorKind::PermissionDenied,
x if x == abi::errno::PIPE as i32 => io::ErrorKind::BrokenPipe,
x if x == abi::errno::TIMEDOUT as i32 => io::ErrorKind::TimedOut,
_ => io::ErrorKind::Other,
}
}
pub unsafe fn abort_internal() -> ! {
::core::intrinsics::abort();
}
pub use libc::strlen;
pub fn hashmap_random_keys() -> (u64, u64) {
unsafe {
let mut v = mem::uninitialized();
libc::arc4random_buf(&mut v as *mut _ as *mut libc::c_void, mem::size_of_val(&v));
v
}
}

158
ctr-std/src/sys/cloudabi/mutex.rs

@ -0,0 +1,158 @@
// Copyright 2018 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 cell::UnsafeCell;
use mem;
use sync::atomic::{AtomicU32, Ordering};
use sys::cloudabi::abi;
use sys::rwlock::{self, RWLock};
extern "C" {
#[thread_local]
static __pthread_thread_id: abi::tid;
}
// Implement Mutex using an RWLock. This doesn't introduce any
// performance overhead in this environment, as the operations would be
// implemented identically.
pub struct Mutex(RWLock);
pub unsafe fn raw(m: &Mutex) -> *mut AtomicU32 {
rwlock::raw(&m.0)
}
impl Mutex {
pub const fn new() -> Mutex {
Mutex(RWLock::new())
}
pub unsafe fn init(&mut self) {
// This function should normally reinitialize the mutex after
// moving it to a different memory address. This implementation
// does not require adjustments after moving.
}
pub unsafe fn try_lock(&self) -> bool {
self.0.try_write()
}
pub unsafe fn lock(&self) {
self.0.write()
}
pub unsafe fn unlock(&self) {
self.0.write_unlock()
}
pub unsafe fn destroy(&self) {
self.0.destroy()
}
}
pub struct ReentrantMutex {
lock: UnsafeCell<AtomicU32>,
recursion: UnsafeCell<u32>,
}
impl ReentrantMutex {
pub unsafe fn uninitialized() -> ReentrantMutex {
mem::uninitialized()
}
pub unsafe fn init(&mut self) {
self.lock = UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0));
self.recursion = UnsafeCell::new(0);
}
pub unsafe fn try_lock(&self) -> bool {
// Attempt to acquire the lock.
let lock = self.lock.get();
let recursion = self.recursion.get();
if let Err(old) = (*lock).compare_exchange(
abi::LOCK_UNLOCKED.0,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
Ordering::Acquire,
Ordering::Relaxed,
) {
// If we fail to acquire the lock, it may be the case
// that we've already acquired it and may need to recurse.
if old & !abi::LOCK_KERNEL_MANAGED.0 == __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 {
*recursion += 1;
true
} else {
false
}
} else {
// Success.
assert_eq!(*recursion, 0, "Mutex has invalid recursion count");
true
}
}
pub unsafe fn lock(&self) {
if !self.try_lock() {
// Call into the kernel to acquire a write lock.
let lock = self.lock.get();
let subscription = abi::subscription {
type_: abi::eventtype::LOCK_WRLOCK,
union: abi::subscription_union {
lock: abi::subscription_lock {
lock: lock as *mut abi::lock,
lock_scope: abi::scope::PRIVATE,
},
},
..mem::zeroed()
};
let mut event: abi::event = mem::uninitialized();
let mut nevents: usize = mem::uninitialized();
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire mutex");
assert_eq!(event.error, abi::errno::SUCCESS, "Failed to acquire mutex");
}
}
pub unsafe fn unlock(&self) {
let lock = self.lock.get();
let recursion = self.recursion.get();
assert_eq!(
(*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
"This mutex is locked by a different thread"
);
if *recursion > 0 {
*recursion -= 1;
} else if !(*lock)
.compare_exchange(
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
abi::LOCK_UNLOCKED.0,
Ordering::Release,
Ordering::Relaxed,
)
.is_ok()
{
// Lock is managed by kernelspace. Call into the kernel
// to unblock waiting threads.
let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
assert_eq!(ret, abi::errno::SUCCESS, "Failed to unlock a mutex");
}
}
pub unsafe fn destroy(&self) {
let lock = self.lock.get();
let recursion = self.recursion.get();
assert_eq!(
(*lock).load(Ordering::Relaxed),
abi::LOCK_UNLOCKED.0,
"Attempted to destroy locked mutex"
);
assert_eq!(*recursion, 0, "Recursion counter invalid");
}
}

37
ctr-std/src/sys/cloudabi/os.rs

@ -0,0 +1,37 @@
// Copyright 2018 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::CStr;
use libc::{self, c_int};
use str;
pub use sys::cloudabi::shims::os::*;
pub fn errno() -> i32 {
extern "C" {
#[thread_local]
static errno: c_int;
}
unsafe { errno as i32 }
}
/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
// cloudlibc's strerror() is guaranteed to be thread-safe. There is
// thus no need to use strerror_r().
str::from_utf8(unsafe { CStr::from_ptr(libc::strerror(errno)) }.to_bytes())
.unwrap()
.to_owned()
}
pub fn exit(code: i32) -> ! {
unsafe { libc::exit(code as c_int) }
}

237
ctr-std/src/sys/cloudabi/rwlock.rs

@ -0,0 +1,237 @@
// Copyright 2018 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 cell::UnsafeCell;
use mem;
use sync::atomic::{AtomicU32, Ordering};
use sys::cloudabi::abi;
extern "C" {
#[thread_local]
static __pthread_thread_id: abi::tid;
}
#[thread_local]
static mut RDLOCKS_ACQUIRED: u32 = 0;
pub struct RWLock {
lock: UnsafeCell<AtomicU32>,
}
pub unsafe fn raw(r: &RWLock) -> *mut AtomicU32 {
r.lock.get()
}
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
impl RWLock {
pub const fn new() -> RWLock {
RWLock {
lock: UnsafeCell::new(AtomicU32::new(abi::LOCK_UNLOCKED.0)),
}
}
pub unsafe fn try_read(&self) -> bool {
let lock = self.lock.get();
let mut old = abi::LOCK_UNLOCKED.0;
while let Err(cur) =
(*lock).compare_exchange_weak(old, old + 1, Ordering::Acquire, Ordering::Relaxed)
{
if (cur & abi::LOCK_WRLOCKED.0) != 0 {
// Another thread already has a write lock.
assert_ne!(
old & !abi::LOCK_KERNEL_MANAGED.0,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
"Attempted to acquire a read lock while holding a write lock"
);
return false;
} else if (old & abi::LOCK_KERNEL_MANAGED.0) != 0 && RDLOCKS_ACQUIRED == 0 {
// Lock has threads waiting for the lock. Only acquire
// the lock if we have already acquired read locks. In
// that case, it is justified to acquire this lock to
// prevent a deadlock.
return false;
}
old = cur;
}
RDLOCKS_ACQUIRED += 1;
true
}
pub unsafe fn read(&self) {
if !self.try_read() {
// Call into the kernel to acquire a read lock.
let lock = self.lock.get();
let subscription = abi::subscription {
type_: abi::eventtype::LOCK_RDLOCK,
union: abi::subscription_union {
lock: abi::subscription_lock {
lock: lock as *mut abi::lock,
lock_scope: abi::scope::PRIVATE,
},
},
..mem::zeroed()
};
let mut event: abi::event = mem::uninitialized();
let mut nevents: usize = mem::uninitialized();
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire read lock");
assert_eq!(
event.error,
abi::errno::SUCCESS,
"Failed to acquire read lock"
);
RDLOCKS_ACQUIRED += 1;
}
}
pub unsafe fn read_unlock(&self) {
// Perform a read unlock. We can do this in userspace, except when
// other threads are blocked and we are performing the last unlock.
// In that case, call into the kernel.
//
// Other threads may attempt to increment the read lock count,
// meaning that the call into the kernel could be spurious. To
// prevent this from happening, upgrade to a write lock first. This
// allows us to call into the kernel, having the guarantee that the
// lock value will not change in the meantime.
assert!(RDLOCKS_ACQUIRED > 0, "Bad lock count");
let mut old = 1;
loop {
let lock = self.lock.get();
if old == 1 | abi::LOCK_KERNEL_MANAGED.0 {
// Last read lock while threads are waiting. Attempt to upgrade
// to a write lock before calling into the kernel to unlock.
if let Err(cur) = (*lock).compare_exchange_weak(
old,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0 | abi::LOCK_KERNEL_MANAGED.0,
Ordering::Acquire,
Ordering::Relaxed,
) {
old = cur;
} else {
// Call into the kernel to unlock.
let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
break;
}
} else {
// No threads waiting or not the last read lock. Just decrement
// the read lock count.
assert_ne!(
old & !abi::LOCK_KERNEL_MANAGED.0,
0,
"This rwlock is not locked"
);
assert_eq!(
old & abi::LOCK_WRLOCKED.0,
0,
"Attempted to read-unlock a write-locked rwlock"
);
if let Err(cur) = (*lock).compare_exchange_weak(
old,
old - 1,
Ordering::Acquire,
Ordering::Relaxed,
) {
old = cur;
} else {
break;
}
}
}
RDLOCKS_ACQUIRED -= 1;
}
pub unsafe fn try_write(&self) -> bool {
// Attempt to acquire the lock.
let lock = self.lock.get();
if let Err(old) = (*lock).compare_exchange(
abi::LOCK_UNLOCKED.0,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
Ordering::Acquire,
Ordering::Relaxed,
) {
// Failure. Crash upon recursive acquisition.
assert_ne!(
old & !abi::LOCK_KERNEL_MANAGED.0,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
"Attempted to recursive write-lock a rwlock",
);
false
} else {
// Success.
true
}
}
pub unsafe fn write(&self) {
if !self.try_write() {
// Call into the kernel to acquire a write lock.
let lock = self.lock.get();
let subscription = abi::subscription {
type_: abi::eventtype::LOCK_WRLOCK,
union: abi::subscription_union {
lock: abi::subscription_lock {
lock: lock as *mut abi::lock,
lock_scope: abi::scope::PRIVATE,
},
},
..mem::zeroed()
};
let mut event: abi::event = mem::uninitialized();
let mut nevents: usize = mem::uninitialized();
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
assert_eq!(ret, abi::errno::SUCCESS, "Failed to acquire write lock");
assert_eq!(
event.error,
abi::errno::SUCCESS,
"Failed to acquire write lock"
);
}
}
pub unsafe fn write_unlock(&self) {
let lock = self.lock.get();
assert_eq!(
(*lock).load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0,
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
"This rwlock is not write-locked by this thread"
);
if !(*lock)
.compare_exchange(
__pthread_thread_id.0 | abi::LOCK_WRLOCKED.0,
abi::LOCK_UNLOCKED.0,
Ordering::Release,
Ordering::Relaxed,
)
.is_ok()
{
// Lock is managed by kernelspace. Call into the kernel
// to unblock waiting threads.
let ret = abi::lock_unlock(lock as *mut abi::lock, abi::scope::PRIVATE);
assert_eq!(ret, abi::errno::SUCCESS, "Failed to write unlock a rwlock");
}
}
pub unsafe fn destroy(&self) {
let lock = self.lock.get();
assert_eq!(
(*lock).load(Ordering::Relaxed),
abi::LOCK_UNLOCKED.0,
"Attempted to destroy locked rwlock"
);
}
}

45
ctr-std/src/sys/cloudabi/shims/args.rs

@ -0,0 +1,45 @@
// Copyright 2018 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;
pub struct Args(());
impl Args {
pub fn inner_debug(&self) -> &[OsString] {
&[]
}
}
impl Iterator for Args {
type Item = OsString;
fn next(&mut self) -> Option<OsString> {
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
(0, Some(0))
}
}
impl ExactSizeIterator for Args {
fn len(&self) -> usize {
0
}
}
impl DoubleEndedIterator for Args {
fn next_back(&mut self) -> Option<OsString> {
None
}
}
pub fn args() -> Args {
Args(())
}

19
ctr-std/src/sys/cloudabi/shims/env.rs

@ -0,0 +1,19 @@
// Copyright 2018 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 = "cloudabi";
pub const OS: &'static str = "cloudabi";
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 = "";
}

302
ctr-std/src/sys/cloudabi/shims/fs.rs

@ -0,0 +1,302 @@
// 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 fmt;
use hash::{Hash, Hasher};
use io::{self, SeekFrom};
use path::{Path, PathBuf};
use sys::time::SystemTime;
use sys::{unsupported, Void};
pub struct File(Void);
pub struct FileAttr(Void);
pub struct ReadDir(Void);
pub struct DirEntry(Void);
#[derive(Clone, Debug)]
pub struct OpenOptions {}
pub struct FilePermissions(Void);
pub struct FileType(Void);
#[derive(Debug)]
pub struct DirBuilder {}
impl FileAttr {
pub fn size(&self) -> u64 {
match self.0 {}
}
pub fn perm(&self) -> FilePermissions {
match self.0 {}
}
pub fn file_type(&self) -> FileType {
match self.0 {}
}
pub fn modified(&self) -> io::Result<SystemTime> {
match self.0 {}
}
pub fn accessed(&self) -> io::Result<SystemTime> {
match self.0 {}
}
pub fn created(&self) -> io::Result<SystemTime> {
match self.0 {}
}
}
impl Clone for FileAttr {
fn clone(&self) -> FileAttr {
match self.0 {}
}
}
impl FilePermissions {
pub fn readonly(&self) -> bool {
match self.0 {}
}
pub fn set_readonly(&mut self, _readonly: bool) {
match self.0 {}
}
}
impl Clone for FilePermissions {
fn clone(&self) -> FilePermissions {
match self.0 {}
}
}
impl PartialEq for FilePermissions {
fn eq(&self, _other: &FilePermissions) -> bool {
match self.0 {}
}
}
impl Eq for FilePermissions {}
impl fmt::Debug for FilePermissions {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
}
}
impl FileType {
pub fn is_dir(&self) -> bool {
match self.0 {}
}
pub fn is_file(&self) -> bool {
match self.0 {}
}
pub fn is_symlink(&self) -> bool {
match self.0 {}
}
}
impl Clone for FileType {
fn clone(&self) -> FileType {
match self.0 {}
}
}
impl Copy for FileType {}
impl PartialEq for FileType {
fn eq(&self, _other: &FileType) -> bool {
match self.0 {}
}
}
impl Eq for FileType {}
impl Hash for FileType {
fn hash<H: Hasher>(&self, _h: &mut H) {
match self.0 {}
}
}
impl fmt::Debug for FileType {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
}
}
impl fmt::Debug for ReadDir {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
}
}
impl Iterator for ReadDir {
type Item = io::Result<DirEntry>;
fn next(&mut self) -> Option<io::Result<DirEntry>> {
match self.0 {}
}
}
impl DirEntry {
pub fn path(&self) -> PathBuf {
match self.0 {}
}
pub fn file_name(&self) -> OsString {
match self.0 {}
}
pub fn metadata(&self) -> io::Result<FileAttr> {
match self.0 {}
}
pub fn file_type(&self) -> io::Result<FileType> {
match self.0 {}
}
}
impl OpenOptions {
pub fn new() -> OpenOptions {
OpenOptions {}
}
pub fn read(&mut self, _read: bool) {}
pub fn write(&mut self, _write: bool) {}
pub fn append(&mut self, _append: bool) {}
pub fn truncate(&mut self, _truncate: bool) {}
pub fn create(&mut self, _create: bool) {}
pub fn create_new(&mut self, _create_new: bool) {}
}
impl File {
pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result<File> {
unsupported()
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
match self.0 {}
}
pub fn fsync(&self) -> io::Result<()> {
match self.0 {}
}
pub fn datasync(&self) -> io::Result<()> {
match self.0 {}
}
pub fn truncate(&self, _size: u64) -> io::Result<()> {
match self.0 {}
}
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 flush(&self) -> io::Result<()> {
match self.0 {}
}
pub fn seek(&self, _pos: SeekFrom) -> io::Result<u64> {
match self.0 {}
}
pub fn duplicate(&self) -> io::Result<File> {
match self.0 {}
}
pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> {
match self.0 {}
}
pub fn diverge(&self) -> ! {
match self.0 {}
}
}
impl DirBuilder {
pub fn new() -> DirBuilder {
DirBuilder {}
}
pub fn mkdir(&self, _p: &Path) -> io::Result<()> {
unsupported()
}
}
impl fmt::Debug for File {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
}
}
pub fn readdir(_p: &Path) -> io::Result<ReadDir> {
unsupported()
}
pub fn unlink(_p: &Path) -> io::Result<()> {
unsupported()
}
pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> {
unsupported()
}
pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> {
match perm.0 {}
}
pub fn rmdir(_p: &Path) -> io::Result<()> {
unsupported()
}
pub fn remove_dir_all(_path: &Path) -> io::Result<()> {
unsupported()
}
pub fn readlink(_p: &Path) -> io::Result<PathBuf> {
unsupported()
}
pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> {
unsupported()
}
pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> {
unsupported()
}
pub fn stat(_p: &Path) -> io::Result<FileAttr> {
unsupported()
}
pub fn lstat(_p: &Path) -> io::Result<FileAttr> {
unsupported()
}
pub fn canonicalize(_p: &Path) -> io::Result<PathBuf> {
unsupported()
}
pub fn copy(_from: &Path, _to: &Path) -> io::Result<u64> {
unsupported()
}

32
ctr-std/src/sys/cloudabi/shims/mod.rs

@ -0,0 +1,32 @@
// Copyright 2018 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;
pub mod args;
pub mod env;
pub mod fs;
pub mod net;
#[path = "../../unix/path.rs"]
pub mod path;
pub mod pipe;
pub mod process;
pub mod os;
// 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 {}
pub fn unsupported<T>() -> io::Result<T> {
Err(io::Error::new(
io::ErrorKind::Other,
"This function is not available on CloudABI.",
))
}

296
ctr-std/src/sys/cloudabi/shims/net.rs

@ -0,0 +1,296 @@
// 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 fmt;
use io;
use net::{Ipv4Addr, Ipv6Addr, Shutdown, SocketAddr};
use time::Duration;
use sys::{unsupported, Void};
pub extern crate libc as netc;
pub struct TcpStream(Void);
impl TcpStream {
pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
unsupported()
}
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
unsupported()
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
match self.0 {}
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
match self.0 {}
}
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn nodelay(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn ttl(&self) -> io::Result<u32> {
match self.0 {}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match self.0 {}
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
}
impl fmt::Debug for TcpStream {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
}
}
pub struct TcpListener(Void);
impl TcpListener {
pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
unsupported()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
match self.0 {}
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
match self.0 {}
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn ttl(&self) -> io::Result<u32> {
match self.0 {}
}
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn only_v6(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match self.0 {}
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
}
impl fmt::Debug for TcpListener {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
}
}
pub struct UdpSocket(Void);
impl UdpSocket {
pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
unsupported()
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
match self.0 {}
}
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
match self.0 {}
}
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
match self.0 {}
}
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
match self.0 {}
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
match self.0 {}
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
match self.0 {}
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
match self.0 {}
}
pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn broadcast(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
match self.0 {}
}
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
match self.0 {}
}
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
match self.0 {}
}
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr) -> io::Result<()> {
match self.0 {}
}
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
match self.0 {}
}
pub fn ttl(&self) -> io::Result<u32> {
match self.0 {}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match self.0 {}
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
match self.0 {}
}
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn send(&self, _: &[u8]) -> io::Result<usize> {
match self.0 {}
}
pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
match self.0 {}
}
}
impl fmt::Debug for UdpSocket {
fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result {
match self.0 {}
}
}
pub struct LookupHost(Void);
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
match self.0 {}
}
}
pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
unsupported()
}

95
ctr-std/src/sys/cloudabi/shims/os.rs

@ -0,0 +1,95 @@
// Copyright 2018 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 error::Error as StdError;
use ffi::{OsStr, OsString};
use fmt;
use io;
use iter;
use path::{self, PathBuf};
use sys::{unsupported, Void};
pub fn getcwd() -> io::Result<PathBuf> {
unsupported()
}
pub fn chdir(_: &path::Path) -> io::Result<()> {
unsupported()
}
pub type Env = iter::Empty<(OsString, OsString)>;
pub fn env() -> Env {
iter::empty()
}
pub fn getenv(_: &OsStr) -> io::Result<Option<OsString>> {
Ok(None)
}
pub fn setenv(_: &OsStr, _: &OsStr) -> io::Result<()> {
unsupported()
}
pub fn unsetenv(_: &OsStr) -> io::Result<()> {
unsupported()
}
pub struct SplitPaths<'a>(&'a Void);
pub fn split_paths(_unparsed: &OsStr) -> SplitPaths {
panic!("unsupported")
}
impl<'a> Iterator for SplitPaths<'a> {
type Item = PathBuf;
fn next(&mut self) -> Option<PathBuf> {
match *self.0 {}
}
}
#[derive(Debug)]
pub struct JoinPathsError;
pub fn join_paths<I, T>(_paths: I) -> Result<OsString, JoinPathsError>
where
I: Iterator<Item = T>,
T: AsRef<OsStr>,
{
Err(JoinPathsError)
}
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
"not supported on CloudABI yet".fmt(f)
}
}
impl StdError for JoinPathsError {
fn description(&self) -> &str {
"not supported on CloudABI yet"
}
}
pub fn home_dir() -> Option<PathBuf> {
None
}
pub fn temp_dir() -> PathBuf {
PathBuf::from("/tmp")
}
pub fn current_exe() -> io::Result<PathBuf> {
unsupported()
}
pub fn getpid() -> u32 {
1
}

32
ctr-std/src/sys/cloudabi/shims/pipe.rs

@ -0,0 +1,32 @@
// 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 {}
}

159
ctr-std/src/sys/cloudabi/shims/process.rs

@ -0,0 +1,159 @@
// 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()
}
}
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 {}
}
}
#[derive(PartialEq, Eq, Clone, Copy, Debug)]
pub struct ExitCode(bool);
impl ExitCode {
pub const SUCCESS: ExitCode = ExitCode(false);
pub const FAILURE: ExitCode = ExitCode(true);
pub fn as_i32(&self) -> i32 {
self.0 as i32
}
}
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 {}
}
}

23
ctr-std/src/sys/cloudabi/stack_overflow.rs

@ -0,0 +1,23 @@
// 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.
#![cfg_attr(test, allow(dead_code))]
pub struct Handler;
impl Handler {
pub unsafe fn new() -> Handler {
Handler
}
}
pub unsafe fn init() {}
pub unsafe fn cleanup() {}

83
ctr-std/src/sys/cloudabi/stdio.rs

@ -0,0 +1,83 @@
// Copyright 2018 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::cloudabi::abi;
pub struct Stdin(());
pub struct Stdout(());
pub struct Stderr(());
impl Stdin {
pub fn new() -> io::Result<Stdin> {
Ok(Stdin(()))
}
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
Ok(0)
}
}
impl Stdout {
pub fn new() -> io::Result<Stdout> {
Ok(Stdout(()))
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
Err(io::Error::new(
io::ErrorKind::BrokenPipe,
"Stdout is not connected to any output in this environment",
))
}
pub fn flush(&self) -> io::Result<()> {
Ok(())
}
}
impl Stderr {
pub fn new() -> io::Result<Stderr> {
Ok(Stderr(()))
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
Err(io::Error::new(
io::ErrorKind::BrokenPipe,
"Stderr is not connected to any output in this environment",
))
}
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 fn is_ebadf(err: &io::Error) -> bool {
err.raw_os_error() == Some(abi::errno::BADF as i32)
}
pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE;
pub fn stderr_prints_nothing() -> bool {
false
}

126
ctr-std/src/sys/cloudabi/thread.rs

@ -0,0 +1,126 @@
// Copyright 2014-2018 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 boxed::FnBox;
use cmp;
use ffi::CStr;
use io;
use libc;
use mem;
use ptr;
use sys::cloudabi::abi;
use sys::time::dur2intervals;
use sys_common::thread::*;
use time::Duration;
pub const DEFAULT_MIN_STACK_SIZE: usize = 2 * 1024 * 1024;
pub struct Thread {
id: libc::pthread_t,
}
// CloudABI has 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 {}
impl Thread {
pub unsafe fn new<'a>(stack: usize, p: Box<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();
assert_eq!(libc::pthread_attr_init(&mut attr), 0);
let stack_size = cmp::max(stack, min_stack_size(&attr));
assert_eq!(libc::pthread_attr_setstacksize(&mut attr, stack_size), 0);
let ret = libc::pthread_create(&mut native, &attr, thread_start, &*p as *const _ as *mut _);
assert_eq!(libc::pthread_attr_destroy(&mut attr), 0);
return if ret != 0 {
Err(io::Error::from_raw_os_error(ret))
} else {
mem::forget(p); // ownership passed to pthread_create
Ok(Thread { id: native })
};
extern "C" fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void {
unsafe {
start_thread(main as *mut u8);
}
ptr::null_mut()
}
}
pub fn yield_now() {
let ret = unsafe { abi::thread_yield() };
debug_assert_eq!(ret, abi::errno::SUCCESS);
}
pub fn set_name(_name: &CStr) {
// CloudABI has no way to set a thread name.
}
pub fn sleep(dur: Duration) {
unsafe {
let subscription = abi::subscription {
type_: abi::eventtype::CLOCK,
union: abi::subscription_union {
clock: abi::subscription_clock {
clock_id: abi::clockid::MONOTONIC,
timeout: dur2intervals(&dur),
..mem::zeroed()
},
},
..mem::zeroed()
};
let mut event: abi::event = mem::uninitialized();
let mut nevents: usize = mem::uninitialized();
let ret = abi::poll(&subscription, &mut event, 1, &mut nevents);
assert_eq!(ret, abi::errno::SUCCESS);
assert_eq!(event.error, abi::errno::SUCCESS);
}
}
pub fn join(self) {
unsafe {
let ret = libc::pthread_join(self.id, ptr::null_mut());
mem::forget(self);
assert!(
ret == 0,
"failed to join thread: {}",
io::Error::from_raw_os_error(ret)
);
}
}
}
impl Drop for Thread {
fn drop(&mut self) {
let ret = unsafe { libc::pthread_detach(self.id) };
debug_assert_eq!(ret, 0);
}
}
#[cfg_attr(test, allow(dead_code))]
pub mod guard {
pub type Guard = !;
pub unsafe fn current() -> Option<Guard> {
None
}
pub unsafe fn init() -> Option<Guard> {
None
}
pub unsafe fn deinit() {}
}
fn min_stack_size(_: *const libc::pthread_attr_t) -> usize {
libc::PTHREAD_STACK_MIN
}

111
ctr-std/src/sys/cloudabi/time.rs

@ -0,0 +1,111 @@
// Copyright 2018 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 mem;
use sys::cloudabi::abi;
use time::Duration;
const NSEC_PER_SEC: abi::timestamp = 1_000_000_000;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant {
t: abi::timestamp,
}
pub fn dur2intervals(dur: &Duration) -> abi::timestamp {
dur.as_secs()
.checked_mul(NSEC_PER_SEC)
.and_then(|nanos| nanos.checked_add(dur.subsec_nanos() as abi::timestamp))
.expect("overflow converting duration to nanoseconds")
}
impl Instant {
pub fn now() -> Instant {
unsafe {
let mut t = mem::uninitialized();
let ret = abi::clock_time_get(abi::clockid::MONOTONIC, 0, &mut t);
assert_eq!(ret, abi::errno::SUCCESS);
Instant { t: t }
}
}
pub fn sub_instant(&self, other: &Instant) -> Duration {
let diff = self.t
.checked_sub(other.t)
.expect("second instant is later than self");
Duration::new(diff / NSEC_PER_SEC, (diff % NSEC_PER_SEC) as u32)
}
pub fn add_duration(&self, other: &Duration) -> Instant {
Instant {
t: self.t
.checked_add(dur2intervals(other))
.expect("overflow when adding duration to instant"),
}
}
pub fn sub_duration(&self, other: &Duration) -> Instant {
Instant {
t: self.t
.checked_sub(dur2intervals(other))
.expect("overflow when subtracting duration from instant"),
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct SystemTime {
t: abi::timestamp,
}
impl SystemTime {
pub fn now() -> SystemTime {
unsafe {
let mut t = mem::uninitialized();
let ret = abi::clock_time_get(abi::clockid::REALTIME, 0, &mut t);
assert_eq!(ret, abi::errno::SUCCESS);
SystemTime { t: t }
}
}
pub fn sub_time(&self, other: &SystemTime) -> Result<Duration, Duration> {
if self.t >= other.t {
let diff = self.t - other.t;
Ok(Duration::new(
diff / NSEC_PER_SEC,
(diff % NSEC_PER_SEC) as u32,
))
} else {
let diff = other.t - self.t;
Err(Duration::new(
diff / NSEC_PER_SEC,
(diff % NSEC_PER_SEC) as u32,
))
}
}
pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime {
t: self.t
.checked_add(dur2intervals(other))
.expect("overflow when adding duration to instant"),
}
}
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime {
t: self.t
.checked_sub(dur2intervals(other))
.expect("overflow when subtracting duration from instant"),
}
}
}
pub const UNIX_EPOCH: SystemTime = SystemTime { t: 0 };

170
ctr-std/src/sys/horizon/android.rs

@ -0,0 +1,170 @@
// 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.
//! Android ABI-compatibility module
//!
//! The ABI of Android has changed quite a bit over time, and libstd attempts to
//! be both forwards and backwards compatible as much as possible. We want to
//! always work with the most recent version of Android, but we also want to
//! work with older versions of Android for whenever projects need to.
//!
//! Our current minimum supported Android version is `android-9`, e.g. Android
//! with API level 9. We then in theory want to work on that and all future
//! versions of Android!
//!
//! Some of the detection here is done at runtime via `dlopen` and
//! introspection. Other times no detection is performed at all and we just
//! provide a fallback implementation as some versions of Android we support
//! don't have the function.
//!
//! You'll find more details below about why each compatibility shim is needed.
#![cfg(target_os = "android")]
use libc::{c_int, c_void, sighandler_t, size_t, ssize_t};
use libc::{ftruncate, pread, pwrite};
use io;
use super::{cvt, cvt_r};
// The `log2` and `log2f` functions apparently appeared in android-18, or at
// least you can see they're not present in the android-17 header [1] and they
// are present in android-18 [2].
//
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
// /android-17/arch-arm/usr/include/math.h
// [2]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
// /android-18/arch-arm/usr/include/math.h
//
// Note that these shims are likely less precise than directly calling `log2`,
// but hopefully that should be enough for now...
//
// Note that mathematically, for any arbitrary `y`:
//
// log_2(x) = log_y(x) / log_y(2)
// = log_y(x) / (1 / log_2(y))
// = log_y(x) * log_2(y)
//
// Hence because `ln` (log_e) is available on all Android we just choose `y = e`
// and get:
//
// log_2(x) = ln(x) * log_2(e)
#[cfg(not(test))]
pub fn log2f32(f: f32) -> f32 {
f.ln() * ::f32::consts::LOG2_E
}
#[cfg(not(test))]
pub fn log2f64(f: f64) -> f64 {
f.ln() * ::f64::consts::LOG2_E
}
// Back in the day [1] the `signal` function was just an inline wrapper
// around `bsd_signal`, but starting in API level android-20 the `signal`
// symbols was introduced [2]. Finally, in android-21 the API `bsd_signal` was
// removed [3].
//
// Basically this means that if we want to be binary compatible with multiple
// Android releases (oldest being 9 and newest being 21) then we need to check
// for both symbols and not actually link against either.
//
// [1]: https://chromium.googlesource.com/android_tools/+/20ee6d20/ndk/platforms
// /android-18/arch-arm/usr/include/signal.h
// [2]: https://chromium.googlesource.com/android_tools/+/fbd420/ndk_experimental
// /platforms/android-20/arch-arm
// /usr/include/signal.h
// [3]: https://chromium.googlesource.com/android_tools/+/20ee6d/ndk/platforms
// /android-21/arch-arm/usr/include/signal.h
pub unsafe fn signal(signum: c_int, handler: sighandler_t) -> sighandler_t {
weak!(fn signal(c_int, sighandler_t) -> sighandler_t);
weak!(fn bsd_signal(c_int, sighandler_t) -> sighandler_t);
let f = signal.get().or_else(|| bsd_signal.get());
let f = f.expect("neither `signal` nor `bsd_signal` symbols found");
f(signum, handler)
}
// The `ftruncate64` symbol apparently appeared in android-12, so we do some
// dynamic detection to see if we can figure out whether `ftruncate64` exists.
//
// If it doesn't we just fall back to `ftruncate`, generating an error for
// too-large values.
#[cfg(target_pointer_width = "32")]
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
weak!(fn ftruncate64(c_int, i64) -> c_int);
unsafe {
match ftruncate64.get() {
Some(f) => cvt_r(|| f(fd, size as i64)).map(|_| ()),
None => {
if size > i32::max_value() as u64 {
Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot truncate >2GB"))
} else {
cvt_r(|| ftruncate(fd, size as i32)).map(|_| ())
}
}
}
}
}
#[cfg(target_pointer_width = "64")]
pub fn ftruncate64(fd: c_int, size: u64) -> io::Result<()> {
unsafe {
cvt_r(|| ftruncate(fd, size as i64)).map(|_| ())
}
}
#[cfg(target_pointer_width = "32")]
pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
-> io::Result<ssize_t>
{
use convert::TryInto;
weak!(fn pread64(c_int, *mut c_void, size_t, i64) -> ssize_t);
pread64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
if let Ok(o) = offset.try_into() {
cvt(pread(fd, buf, count, o))
} else {
Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot pread >2GB"))
}
})
}
#[cfg(target_pointer_width = "32")]
pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
-> io::Result<ssize_t>
{
use convert::TryInto;
weak!(fn pwrite64(c_int, *const c_void, size_t, i64) -> ssize_t);
pwrite64.get().map(|f| cvt(f(fd, buf, count, offset))).unwrap_or_else(|| {
if let Ok(o) = offset.try_into() {
cvt(pwrite(fd, buf, count, o))
} else {
Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot pwrite >2GB"))
}
})
}
#[cfg(target_pointer_width = "64")]
pub unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: size_t, offset: i64)
-> io::Result<ssize_t>
{
cvt(pread(fd, buf, count, offset))
}
#[cfg(target_pointer_width = "64")]
pub unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: size_t, offset: i64)
-> io::Result<ssize_t>
{
cvt(pwrite(fd, buf, count, offset))
}

60
ctr-std/src/sys/horizon/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()
}
}

119
ctr-std/src/sys/horizon/backtrace/mod.rs

@ -0,0 +1,119 @@
// 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.
/// Backtrace support built on libgcc with some extra OS-specific support
///
/// Some methods of getting a backtrace:
///
/// * The backtrace() functions on unix. It turns out this doesn't work very
/// well for green threads on macOS, and the address to symbol portion of it
/// suffers problems that are described below.
///
/// * Using libunwind. This is more difficult than it sounds because libunwind
/// isn't installed everywhere by default. It's also a bit of a hefty library,
/// so possibly not the best option. When testing, libunwind was excellent at
/// getting both accurate backtraces and accurate symbols across platforms.
/// This route was not chosen in favor of the next option, however.
///
/// * We're already using libgcc_s for exceptions in rust (triggering thread
/// unwinding and running destructors on the stack), and it turns out that it
/// conveniently comes with a function that also gives us a backtrace. All of
/// these functions look like _Unwind_*, but it's not quite the full
/// repertoire of the libunwind API. Due to it already being in use, this was
/// the chosen route of getting a backtrace.
///
/// After choosing libgcc_s for backtraces, the sad part is that it will only
/// give us a stack trace of instruction pointers. Thankfully these instruction
/// pointers are accurate (they work for green and native threads), but it's
/// then up to us again to figure out how to translate these addresses to
/// symbols. As with before, we have a few options. Before, that, a little bit
/// of an interlude about symbols. This is my very limited knowledge about
/// symbol tables, and this information is likely slightly wrong, but the
/// general idea should be correct.
///
/// When talking about symbols, it's helpful to know a few things about where
/// symbols are located. Some symbols are located in the dynamic symbol table
/// of the executable which in theory means that they're available for dynamic
/// linking and lookup. Other symbols end up only in the local symbol table of
/// the file. This loosely corresponds to pub and priv functions in Rust.
///
/// Armed with this knowledge, we know that our solution for address to symbol
/// translation will need to consult both the local and dynamic symbol tables.
/// With that in mind, here's our options of translating an address to
/// a symbol.
///
/// * Use dladdr(). The original backtrace()-based idea actually uses dladdr()
/// behind the scenes to translate, and this is why backtrace() was not used.
/// Conveniently, this method works fantastically on macOS. It appears dladdr()
/// uses magic to consult the local symbol table, or we're putting everything
/// in the dynamic symbol table anyway. Regardless, for macOS, this is the
/// method used for translation. It's provided by the system and easy to do.o
///
/// Sadly, all other systems have a dladdr() implementation that does not
/// consult the local symbol table. This means that most functions are blank
/// because they don't have symbols. This means that we need another solution.
///
/// * Use unw_get_proc_name(). This is part of the libunwind api (not the
/// libgcc_s version of the libunwind api), but involves taking a dependency
/// to libunwind. We may pursue this route in the future if we bundle
/// libunwind, but libunwind was unwieldy enough that it was not chosen at
/// this time to provide this functionality.
///
/// * Shell out to a utility like `readelf`. Crazy though it may sound, it's a
/// semi-reasonable solution. The stdlib already knows how to spawn processes,
/// so in theory it could invoke readelf, parse the output, and consult the
/// local/dynamic symbol tables from there. This ended up not getting chosen
/// due to the craziness of the idea plus the advent of the next option.
///
/// * Use `libbacktrace`. It turns out that this is a small library bundled in
/// the gcc repository which provides backtrace and symbol translation
/// functionality. All we really need from it is the backtrace functionality,
/// and we only really need this on everything that's not macOS, so this is the
/// chosen route for now.
///
/// In summary, the current situation uses libgcc_s to get a trace of stack
/// pointers, and we use dladdr() or libbacktrace to translate these addresses
/// to symbols. This is a bit of a hokey implementation as-is, but it works for
/// all unix platforms we support right now, so it at least gets the job done.
pub use self::tracing::unwind_backtrace;
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
// tracing impls:
mod tracing;
// symbol resolvers:
mod printing;
#[cfg(not(target_os = "emscripten"))]
pub mod gnu {
use io;
use fs;
use libc::c_char;
#[cfg(not(any(target_os = "macos", target_os = "ios")))]
pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
Err(io::Error::new(io::ErrorKind::Other, "Not implemented"))
}
#[cfg(any(target_os = "macos", target_os = "ios"))]
pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
use env;
use os::unix::ffi::OsStrExt;
let filename = env::current_exe()?;
let file = fs::File::open(&filename)?;
let mut filename_cstr: Vec<_> = filename.as_os_str().as_bytes().iter()
.map(|&x| x as c_char).collect();
filename_cstr.push(0); // Null terminate
Ok((filename_cstr, file))
}
}
pub struct BacktraceContext;

45
ctr-std/src/sys/horizon/backtrace/printing/dladdr.rs

@ -0,0 +1,45 @@
// Copyright 2014-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 intrinsics;
use ffi::CStr;
use libc;
use sys::backtrace::BacktraceContext;
use sys_common::backtrace::Frame;
pub fn resolve_symname<F>(frame: Frame,
callback: F,
_: &BacktraceContext) -> io::Result<()>
where F: FnOnce(Option<&str>) -> io::Result<()>
{
unsafe {
let mut info: Dl_info = intrinsics::init();
let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 ||
info.dli_sname.is_null() {
None
} else {
CStr::from_ptr(info.dli_sname).to_str().ok()
};
callback(symname)
}
}
#[repr(C)]
struct Dl_info {
dli_fname: *const libc::c_char,
dli_fbase: *mut libc::c_void,
dli_sname: *const libc::c_char,
dli_saddr: *mut libc::c_void,
}
extern {
fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int;
}

43
ctr-std/src/sys/horizon/backtrace/printing/mod.rs

@ -0,0 +1,43 @@
// Copyright 2014-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.
mod dladdr;
use sys::backtrace::BacktraceContext;
use sys_common::backtrace::Frame;
use io;
#[cfg(target_os = "emscripten")]
pub use self::dladdr::resolve_symname;
#[cfg(target_os = "emscripten")]
pub fn foreach_symbol_fileline<F>(_: Frame, _: F, _: &BacktraceContext) -> io::Result<bool>
where
F: FnMut(&[u8], u32) -> io::Result<()>
{
Ok(false)
}
#[cfg(not(target_os = "emscripten"))]
pub use sys_common::gnu::libbacktrace::foreach_symbol_fileline;
#[cfg(not(target_os = "emscripten"))]
pub fn resolve_symname<F>(frame: Frame, callback: F, bc: &BacktraceContext) -> io::Result<()>
where
F: FnOnce(Option<&str>) -> io::Result<()>
{
::sys_common::gnu::libbacktrace::resolve_symname(frame, |symname| {
if symname.is_some() {
callback(symname)
} else {
dladdr::resolve_symname(frame, callback, bc)
}
}, bc)
}

49
ctr-std/src/sys/horizon/backtrace/tracing/backtrace_fn.rs

@ -0,0 +1,49 @@
// Copyright 2014-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.
/// As always - iOS on arm uses SjLj exceptions and
/// _Unwind_Backtrace is even not available there. Still,
/// backtraces could be extracted using a backtrace function,
/// which thanks god is public
///
/// As mentioned in a huge comment block in `super::super`, backtrace
/// doesn't play well with green threads, so while it is extremely nice and
/// simple to use it should be used only on iOS devices as the only viable
/// option.
use io;
use libc;
use sys::backtrace::BacktraceContext;
use sys_common::backtrace::Frame;
#[inline(never)] // if we know this is a function call, we can skip it when
// tracing
pub fn unwind_backtrace(frames: &mut [Frame])
-> io::Result<(usize, BacktraceContext)>
{
const FRAME_LEN: usize = 100;
assert!(FRAME_LEN >= frames.len());
let mut raw_frames = [::ptr::null_mut(); FRAME_LEN];
let nb_frames = unsafe {
backtrace(raw_frames.as_mut_ptr(), raw_frames.len() as libc::c_int)
} as usize;
for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) {
*to = Frame {
exact_position: *from as *mut u8,
symbol_addr: *from as *mut u8,
inline_context: 0,
};
}
Ok((nb_frames as usize, BacktraceContext))
}
extern {
fn backtrace(buf: *mut *mut libc::c_void, sz: libc::c_int) -> libc::c_int;
}

107
ctr-std/src/sys/horizon/backtrace/tracing/gcc_s.rs

@ -0,0 +1,107 @@
// Copyright 2014-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 error::Error;
use io;
use libc;
use sys::backtrace::BacktraceContext;
use sys_common::backtrace::Frame;
use unwind as uw;
struct Context<'a> {
idx: usize,
frames: &'a mut [Frame],
}
#[derive(Debug)]
struct UnwindError(uw::_Unwind_Reason_Code);
impl Error for UnwindError {
fn description(&self) -> &'static str {
"unexpected return value while unwinding"
}
}
impl ::fmt::Display for UnwindError {
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
write!(f, "{}: {:?}", self.description(), self.0)
}
}
#[inline(never)] // if we know this is a function call, we can skip it when
// tracing
pub fn unwind_backtrace(frames: &mut [Frame])
-> io::Result<(usize, BacktraceContext)>
{
let mut cx = Context {
idx: 0,
frames,
};
let result_unwind = unsafe {
uw::_Unwind_Backtrace(trace_fn,
&mut cx as *mut Context
as *mut libc::c_void)
};
// See libunwind:src/unwind/Backtrace.c for the return values.
// No, there is no doc.
match result_unwind {
// These return codes seem to be benign and need to be ignored for backtraces
// to show up properly on all tested platforms.
uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
Ok((cx.idx, BacktraceContext))
}
_ => {
Err(io::Error::new(io::ErrorKind::Other,
UnwindError(result_unwind)))
}
}
}
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) };
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 {
// this is a non-signaling frame, so `ip` refers to the address
// after the calling instruction. account for that.
ip = (ip as usize - 1) as *mut _;
}
// dladdr() on osx gets whiny when we use FindEnclosingFunction, and
// it appears to work fine without it, so we only use
// FindEnclosingFunction on non-osx platforms. In doing so, we get a
// slightly more accurate stack trace in the process.
//
// This is often because panic involves the last instruction of a
// function being "call std::rt::begin_unwind", with no ret
// instructions after it. This means that the return instruction
// pointer points *outside* of the calling function, and by
// unwinding it we go back to the original function.
let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
ip
} else {
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;
}
uw::_URC_NO_REASON
}

18
ctr-std/src/sys/horizon/backtrace/tracing/mod.rs

@ -0,0 +1,18 @@
// 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.
pub use self::imp::*;
#[cfg(not(all(target_os = "ios", target_arch = "arm")))]
#[path = "gcc_s.rs"]
mod imp;
#[cfg(all(target_os = "ios", target_arch = "arm"))]
#[path = "backtrace_fn.rs"]
mod imp;

43
ctr-std/src/sys/horizon/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;
}

139
ctr-std/src/sys/horizon/condvar.rs

@ -0,0 +1,139 @@
// 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.
// *Implementation adapted from `/sys/redox/condvar.rs`
use cell::UnsafeCell;
use intrinsics::atomic_cxchg;
use ptr;
use time::Duration;
use sys::mutex::{self, Mutex};
pub struct Condvar {
lock: UnsafeCell<*mut ::libctru::LightLock>,
}
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}
impl Condvar {
pub const fn new() -> Condvar {
Condvar {
lock: UnsafeCell::new(ptr::null_mut()),
}
}
#[inline]
pub unsafe fn init(&self) {
*self.lock.get() = ptr::null_mut();
}
#[inline]
pub fn notify_one(&self) {
unsafe {
let arbiter = ::libctru::__sync_get_arbiter();
::libctru::svcArbitrateAddress(arbiter,
*self.lock.get() as u32,
::libctru::ARBITRATION_SIGNAL,
1,
0);
}
}
#[inline]
pub fn notify_all(&self) {
unsafe {
let lock = self.lock.get();
if *lock == ptr::null_mut() {
return;
}
let arbiter = ::libctru::__sync_get_arbiter();
::libctru::svcArbitrateAddress(arbiter,
*self.lock.get() as u32,
::libctru::ARBITRATION_SIGNAL,
-1,
0);
}
}
#[inline]
pub fn wait(&self, mutex: &Mutex) {
unsafe {
let lock = self.lock.get();
if *lock != mutex::raw(mutex) as *mut i32 {
if *lock != ptr::null_mut() {
panic!("Condvar used with more than one Mutex");
}
atomic_cxchg(lock as *mut usize, 0, mutex::raw(mutex) as usize);
}
mutex.unlock();
let arbiter = ::libctru::__sync_get_arbiter();
::libctru::svcArbitrateAddress(arbiter,
*self.lock.get() as u32,
::libctru::ARBITRATION_WAIT_IF_LESS_THAN,
2,
0);
mutex.lock();
}
}
#[inline]
pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
use time::Instant;
unsafe {
let lock = self.lock.get();
if *lock != mutex::raw(mutex) as *mut i32 {
if *lock != ptr::null_mut() {
panic!("Condvar used with more than one Mutex");
}
atomic_cxchg(lock as *mut usize, 0, mutex::raw(mutex) as usize);
}
let now = Instant::now();
let nanos = dur.as_secs()
.saturating_mul(1_000_000_000)
.saturating_add(dur.subsec_nanos() as u64);
mutex.unlock();
let arbiter = ::libctru::__sync_get_arbiter();
::libctru::svcArbitrateAddress(arbiter,
*self.lock.get() as u32,
::libctru::ARBITRATION_WAIT_IF_LESS_THAN_TIMEOUT,
2,
nanos as i64);
mutex.lock();
now.elapsed() < dur
}
}
#[inline]
pub unsafe fn destroy(&self) {
*self.lock.get() = ptr::null_mut();
}
}

185
ctr-std/src/sys/horizon/env.rs

@ -0,0 +1,185 @@
// Copyright 2012-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.
#[cfg(target_os = "horizon")]
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";
}
#[cfg(target_os = "linux")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "linux";
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 = "";
}
#[cfg(target_os = "macos")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "macos";
pub const DLL_PREFIX: &'static str = "lib";
pub const DLL_SUFFIX: &'static str = ".dylib";
pub const DLL_EXTENSION: &'static str = "dylib";
pub const EXE_SUFFIX: &'static str = "";
pub const EXE_EXTENSION: &'static str = "";
}
#[cfg(target_os = "ios")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "ios";
pub const DLL_PREFIX: &'static str = "lib";
pub const DLL_SUFFIX: &'static str = ".dylib";
pub const DLL_EXTENSION: &'static str = "dylib";
pub const EXE_SUFFIX: &'static str = "";
pub const EXE_EXTENSION: &'static str = "";
}
#[cfg(target_os = "freebsd")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "freebsd";
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 = "";
}
#[cfg(target_os = "dragonfly")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "dragonfly";
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 = "";
}
#[cfg(target_os = "bitrig")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "bitrig";
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 = "";
}
#[cfg(target_os = "netbsd")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "netbsd";
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 = "";
}
#[cfg(target_os = "openbsd")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "openbsd";
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 = "";
}
#[cfg(target_os = "android")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "android";
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 = "";
}
#[cfg(target_os = "solaris")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "solaris";
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 = "";
}
#[cfg(target_os = "haiku")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "haiku";
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 = "";
}
#[cfg(all(target_os = "emscripten", target_arch = "asmjs"))]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "emscripten";
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 = ".js";
pub const EXE_EXTENSION: &'static str = "js";
}
#[cfg(all(target_os = "emscripten", target_arch = "wasm32"))]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "emscripten";
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 = ".js";
pub const EXE_EXTENSION: &'static str = "js";
}
#[cfg(target_os = "fuchsia")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "fuchsia";
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 = "";
}
#[cfg(target_os = "l4re")]
pub mod os {
pub const FAMILY: &'static str = "unix";
pub const OS: &'static str = "l4re";
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 = "";
}

119
ctr-std/src/sys/horizon/ext/ffi.rs

@ -0,0 +1,119 @@
// 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 extension to the primitives in the `std::ffi` module
#![stable(feature = "rust1", since = "1.0.0")]
use ffi::{OsStr, OsString};
use mem;
use sys::os_str::Buf;
use sys_common::{FromInner, IntoInner, AsInner};
/// Unix-specific extensions to [`OsString`].
///
/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// 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`].
///
/// # 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>;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl OsStringExt for OsString {
fn from_vec(vec: Vec<u8>) -> OsString {
FromInner::from_inner(Buf { inner: vec })
}
fn into_vec(self) -> Vec<u8> {
self.into_inner().inner
}
}
/// Unix-specific extensions to [`OsStr`].
///
/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[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.
///
/// # 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];
}
#[stable(feature = "rust1", since = "1.0.0")]
impl OsStrExt for OsStr {
fn from_bytes(slice: &[u8]) -> &OsStr {
unsafe { mem::transmute(slice) }
}
fn as_bytes(&self) -> &[u8] {
&self.as_inner().inner
}
}

736
ctr-std/src/sys/horizon/ext/fs.rs

@ -0,0 +1,736 @@
// 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 primitives in the `std::fs` module.
#![stable(feature = "rust1", since = "1.0.0")]
use fs::{self, Permissions, OpenOptions};
use io;
use libc;
use path::Path;
use sys;
use sys_common::{FromInner, AsInner, AsInnerMut};
use sys::platform::fs::MetadataExt as UnixMetadataExt;
/// Unix-specific extensions to [`File`].
///
/// [`File`]: ../../../../std/fs/struct.File.html
#[stable(feature = "file_offset", since = "1.15.0")]
pub trait FileExt {
/// Reads a number of bytes starting from a given offset.
///
/// Returns the number of bytes read.
///
/// 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.
///
/// Note that similar to [`File::read`], it is not an error to return with a
/// short read.
///
/// [`File::read`]: ../../../../std/fs/struct.File.html#method.read
///
/// # Examples
///
/// ```no_run
/// 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 8 bytes from the offset 10.
/// let num_bytes_read = file.read_at(&mut buf, 10)?;
/// println!("read {} bytes: {:?}", num_bytes_read, buf);
/// Ok(())
/// }
/// ```
#[stable(feature = "file_offset", since = "1.15.0")]
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>;
/// Writes a number of bytes starting from a given offset.
///
/// Returns the number of bytes written.
///
/// 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.
///
/// When writing beyond the end of the file, the file is appropriately
/// extended and the intermediate bytes are initialized with the value 0.
///
/// Note that similar to [`File::write`], it is not an error to return a
/// short write.
///
/// [`File::write`]: ../../../../std/fs/struct.File.html#write.v
///
/// # Examples
///
/// ```no_run
/// 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_at(b"sushi", 10)?;
/// Ok(())
/// }
/// ```
#[stable(feature = "file_offset", since = "1.15.0")]
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize>;
}
#[stable(feature = "file_offset", since = "1.15.0")]
impl FileExt for fs::File {
fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.as_inner().read_at(buf, offset)
}
fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.as_inner().write_at(buf, offset)
}
}
/// Unix-specific extensions to [`fs::Permissions`].
///
/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `st_mode` bits that contain the standard
/// Unix permissions for this file.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::os::unix::fs::PermissionsExt;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::create("foo.txt")?;
/// let metadata = f.metadata()?;
/// let permissions = metadata.permissions();
///
/// println!("permissions: {}", permissions.mode());
/// Ok(()) }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&self) -> u32;
/// Sets the underlying raw bits for this set of permissions.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::os::unix::fs::PermissionsExt;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::create("foo.txt")?;
/// let metadata = f.metadata()?;
/// let mut permissions = metadata.permissions();
///
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
/// assert_eq!(permissions.mode(), 0o644);
/// Ok(()) }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn set_mode(&mut self, mode: u32);
/// Creates a new instance of `Permissions` from the given set of Unix
/// permission bits.
///
/// # Examples
///
/// ```
/// use std::fs::Permissions;
/// use std::os::unix::fs::PermissionsExt;
///
/// // Read/write for owner and read for others.
/// let permissions = Permissions::from_mode(0o644);
/// assert_eq!(permissions.mode(), 0o644);
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn from_mode(mode: u32) -> Self;
}
#[stable(feature = "fs_ext", since = "1.1.0")]
impl PermissionsExt for Permissions {
fn mode(&self) -> u32 {
self.as_inner().mode()
}
fn set_mode(&mut self, mode: u32) {
*self = Permissions::from_inner(FromInner::from_inner(mode));
}
fn from_mode(mode: u32) -> Permissions {
Permissions::from_inner(FromInner::from_inner(mode))
}
}
/// Unix-specific extensions to [`fs::OpenOptions`].
///
/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
///
/// If a new file is created as part of a `File::open_opts` call then this
/// specified `mode` will be used as the permission bits for the new file.
/// If no `mode` is set, the default of `0o666` will be used.
/// The operating system masks out bits with the systems `umask`, to produce
/// the final permissions.
///
/// # Examples
///
/// ```no_run
/// use std::fs::OpenOptions;
/// use std::os::unix::fs::OpenOptionsExt;
///
/// # fn main() {
/// let mut options = OpenOptions::new();
/// options.mode(0o644); // Give read/write for owner and read for others.
/// let file = options.open("foo.txt");
/// # }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: u32) -> &mut Self;
/// Pass custom flags to the `flags` argument of `open`.
///
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
/// ensure they do not interfere with the access mode set by Rusts options.
///
/// Custom flags can only set flags, not remove flags set by Rusts options.
/// This options overwrites any previously set custom flags.
///
/// # Examples
///
/// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::fs::OpenOptions;
/// use std::os::unix::fs::OpenOptionsExt;
///
/// # fn main() {
/// let mut options = OpenOptions::new();
/// options.write(true);
/// if cfg!(unix) {
/// options.custom_flags(libc::O_NOFOLLOW);
/// }
/// let file = options.open("foo.txt");
/// # }
/// ```
#[stable(feature = "open_options_ext", since = "1.10.0")]
fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
#[stable(feature = "fs_ext", since = "1.1.0")]
impl OpenOptionsExt for OpenOptions {
fn mode(&mut self, mode: u32) -> &mut OpenOptions {
self.as_inner_mut().mode(mode); self
}
fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
self.as_inner_mut().custom_flags(flags); self
}
}
/// Unix-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
/// Returns the ID of the device containing the file.
///
/// # Examples
///
/// ```no_run
/// use std::io;
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let dev_id = meta.dev();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn dev(&self) -> u64;
/// Returns the inode number.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let inode = meta.ino();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ino(&self) -> u64;
/// Returns the rights applied to this file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let mode = meta.mode();
/// let user_has_write_access = mode & 0o200;
/// let user_has_read_write_access = mode & 0o600;
/// let group_has_read_access = mode & 0o040;
/// let others_have_exec_access = mode & 0o001;
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mode(&self) -> u32;
/// Returns the number of hard links pointing to this file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let nb_hard_links = meta.nlink();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn nlink(&self) -> u64;
/// Returns the user ID of the owner of this file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let user_id = meta.uid();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn uid(&self) -> u32;
/// Returns the group ID of the owner of this file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let group_id = meta.gid();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn gid(&self) -> u32;
/// Returns the device ID of this file (if it is a special one).
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let device_id = meta.rdev();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn rdev(&self) -> u64;
/// Returns the total size of this file in bytes.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let file_size = meta.size();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn size(&self) -> u64;
/// Returns the time of the last access to the file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let last_access_time = meta.atime();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn atime(&self) -> i64;
/// Returns the time of the last access to the file in nanoseconds.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let nano_last_access_time = meta.atime_nsec();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn atime_nsec(&self) -> i64;
/// Returns the time of the last modification of the file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let last_modification_time = meta.mtime();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mtime(&self) -> i64;
/// Returns the time of the last modification of the file in nanoseconds.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let nano_last_modification_time = meta.mtime_nsec();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mtime_nsec(&self) -> i64;
/// Returns the time of the last status change of the file.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let last_status_change_time = meta.ctime();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ctime(&self) -> i64;
/// Returns the time of the last status change of the file in nanoseconds.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let nano_last_status_change_time = meta.ctime_nsec();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ctime_nsec(&self) -> i64;
/// Returns the blocksize for filesystem I/O.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let blocksize = meta.blksize();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn blksize(&self) -> u64;
/// Returns the number of blocks allocated to the file, in 512-byte units.
///
/// Please note that this may be smaller than `st_size / 512` when the file has holes.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::MetadataExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("some_file")?;
/// let blocks = meta.blocks();
/// Ok(())
/// }
/// ```
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn blocks(&self) -> u64;
}
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for fs::Metadata {
fn dev(&self) -> u64 { self.st_dev() }
fn ino(&self) -> u64 { self.st_ino() }
fn mode(&self) -> u32 { self.st_mode() }
fn nlink(&self) -> u64 { self.st_nlink() }
fn uid(&self) -> u32 { self.st_uid() }
fn gid(&self) -> u32 { self.st_gid() }
fn rdev(&self) -> u64 { self.st_rdev() }
fn size(&self) -> u64 { self.st_size() }
fn atime(&self) -> i64 { self.st_atime() }
fn atime_nsec(&self) -> i64 { self.st_atime_nsec() }
fn mtime(&self) -> i64 { self.st_mtime() }
fn mtime_nsec(&self) -> i64 { self.st_mtime_nsec() }
fn ctime(&self) -> i64 { self.st_ctime() }
fn ctime_nsec(&self) -> i64 { self.st_ctime_nsec() }
fn blksize(&self) -> u64 { self.st_blksize() }
fn blocks(&self) -> u64 { self.st_blocks() }
}
/// Unix-specific extensions for [`FileType`].
///
/// Adds support for special Unix file types such as block/character devices,
/// pipes, and sockets.
///
/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::FileTypeExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("block_device_file")?;
/// let file_type = meta.file_type();
/// assert!(file_type.is_block_device());
/// Ok(())
/// }
/// ```
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_block_device(&self) -> bool;
/// Returns whether this file type is a char device.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::FileTypeExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("char_device_file")?;
/// let file_type = meta.file_type();
/// assert!(file_type.is_char_device());
/// Ok(())
/// }
/// ```
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_char_device(&self) -> bool;
/// Returns whether this file type is a fifo.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::FileTypeExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("fifo_file")?;
/// let file_type = meta.file_type();
/// assert!(file_type.is_fifo());
/// Ok(())
/// }
/// ```
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_fifo(&self) -> bool;
/// Returns whether this file type is a socket.
///
/// # Examples
///
/// ```no_run
/// use std::fs;
/// use std::os::unix::fs::FileTypeExt;
/// use std::io;
///
/// fn main() -> io::Result<()> {
/// let meta = fs::metadata("unix.socket")?;
/// let file_type = meta.file_type();
/// assert!(file_type.is_socket());
/// Ok(())
/// }
/// ```
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_socket(&self) -> bool;
}
#[stable(feature = "file_type_ext", since = "1.5.0")]
impl FileTypeExt for fs::FileType {
fn is_block_device(&self) -> bool { self.as_inner().is(libc::S_IFBLK) }
fn is_char_device(&self) -> bool { self.as_inner().is(libc::S_IFCHR) }
fn is_fifo(&self) -> bool { self.as_inner().is(libc::S_IFIFO) }
fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) }
}
/// Unix-specific extension methods for [`fs::DirEntry`].
///
/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
pub trait DirEntryExt {
/// Returns the underlying `d_ino` field in the contained `dirent`
/// structure.
///
/// # Examples
///
/// ```
/// use std::fs;
/// use std::os::unix::fs::DirEntryExt;
///
/// if let Ok(entries) = fs::read_dir(".") {
/// for entry in entries {
/// if let Ok(entry) = entry {
/// // Here, `entry` is a `DirEntry`.
/// println!("{:?}: {}", entry.file_name(), entry.ino());
/// }
/// }
/// }
/// ```
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
fn ino(&self) -> u64;
}
#[stable(feature = "dir_entry_ext", since = "1.1.0")]
impl DirEntryExt for fs::DirEntry {
fn ino(&self) -> u64 { 0u64 }
}
/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
/// # Note
///
/// On Windows, you must specify whether a symbolic link points to a file
/// or directory. Use `os::windows::fs::symlink_file` to create a
/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
/// symbolic link to a directory. Additionally, the process must have
/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
/// symbolic link.
///
/// # Examples
///
/// ```no_run
/// use std::os::unix::fs;
///
/// fn main() -> std::io::Result<()> {
/// fs::symlink("a.txt", "b.txt")?;
/// Ok(())
/// }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
sys::fs::symlink(src.as_ref(), dst.as_ref())
}
/// Unix-specific extensions to [`fs::DirBuilder`].
///
/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
#[stable(feature = "dir_builder", since = "1.6.0")]
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
///
/// # Examples
///
/// ```no_run
/// use std::fs::DirBuilder;
/// use std::os::unix::fs::DirBuilderExt;
///
/// let mut builder = DirBuilder::new();
/// builder.mode(0o755);
/// ```
#[stable(feature = "dir_builder", since = "1.6.0")]
fn mode(&mut self, mode: u32) -> &mut Self;
}
#[stable(feature = "dir_builder", since = "1.6.0")]
impl DirBuilderExt for fs::DirBuilder {
fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
self.as_inner_mut().set_mode(mode);
self
}
}

108
ctr-std/src/sys/horizon/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 }
}

59
ctr-std/src/sys/horizon/ext/mod.rs

@ -0,0 +1,59 @@
// Copyright 2014 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.
//! Experimental extensions to `std` for Unix platforms.
//!
//! 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.
//!
//! 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;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//! let f = File::create("foo.txt").unwrap();
//! let fd = f.as_raw_fd();
//!
//! // use fd with native unix bindings
//! }
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(unix))]
pub mod io;
pub mod ffi;
pub mod fs;
pub mod raw;
/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[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;
}

33
ctr-std/src/sys/horizon/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)]
#[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};

77
ctr-std/src/sys/horizon/fast_thread_local.rs

@ -0,0 +1,77 @@
// Copyright 2014-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.
#![cfg(target_thread_local)]
#![unstable(feature = "thread_local_internals", issue = "0")]
// Since what appears to be glibc 2.18 this symbol has been shipped which
// GCC and clang both use to invoke destructors in thread_local globals, so
// let's do the same!
//
// Note, however, that we run on lots older linuxes, as well as cross
// compiling from a newer linux to an older linux, so we also have a
// fallback implementation to use as well.
//
// Due to rust-lang/rust#18804, make sure this is not generic!
#[cfg(target_os = "linux")]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
use libc;
use mem;
use sys_common::thread_local::register_dtor_fallback;
extern {
#[linkage = "extern_weak"]
static __dso_handle: *mut u8;
#[linkage = "extern_weak"]
static __cxa_thread_atexit_impl: *const libc::c_void;
}
if !__cxa_thread_atexit_impl.is_null() {
type F = unsafe extern fn(dtor: unsafe extern fn(*mut u8),
arg: *mut u8,
dso_handle: *mut u8) -> libc::c_int;
mem::transmute::<*const libc::c_void, F>(__cxa_thread_atexit_impl)
(dtor, t, &__dso_handle as *const _ as *mut _);
return
}
register_dtor_fallback(t, dtor);
}
// macOS's analog of the above linux function is this _tlv_atexit function.
// The disassembly of thread_local globals in C++ (at least produced by
// clang) will have this show up in the output.
#[cfg(target_os = "macos")]
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
extern {
fn _tlv_atexit(dtor: unsafe extern fn(*mut u8),
arg: *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
// is running. Specifically if a TLS destructor re-accesses TLS it may
// trigger a re-initialization of all TLS variables, paving over at
// least some destroyed ones with initial values.
//
// This means that if we drop a TLS value in place on macOS that we could
// revert the value to its original state halfway through the
// destructor, which would be bad!
//
// Hence, we use `ptr::read` on macOS (to move to a "safe" location)
// instead of drop_in_place.
cfg!(target_os = "macos")
}

265
ctr-std/src/sys/horizon/fd.rs

@ -0,0 +1,265 @@
// 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.
#![unstable(reason = "not public", issue = "0", feature = "fd")]
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;
#[derive(Debug)]
pub struct FileDesc {
fd: c_int,
}
fn max_len() -> usize {
// The maximum read limit on most posix-like systems is `SSIZE_MAX`,
// with the man page quoting that if the count of bytes to read is
// greater than `SSIZE_MAX` the result is "unspecified".
//
// 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.
if cfg!(target_os = "macos") {
<c_int>::max_value() as usize - 1
} else {
<ssize_t>::max_value() as usize
}
}
impl FileDesc {
pub fn new(fd: c_int) -> FileDesc {
FileDesc { fd: fd }
}
pub fn raw(&self) -> c_int { self.fd }
/// Extracts the actual filedescriptor without closing it.
pub fn into_raw(self) -> c_int {
let fd = self.fd;
mem::forget(self);
fd
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::read(self.fd,
buf.as_mut_ptr() as *mut c_void,
cmp::min(buf.len(), max_len()))
})?;
Ok(ret as usize)
}
pub fn read_to_end(&self, buf: &mut Vec<u8>) -> io::Result<usize> {
let mut me = self;
(&mut me).read_to_end(buf)
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
#[cfg(target_os = "android")]
use super::android::cvt_pread64;
#[cfg(target_os = "emscripten")]
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
-> io::Result<isize>
{
use convert::TryInto;
use libc::pread64;
// pread64 on emscripten actually takes a 32 bit offset
if let Ok(o) = offset.try_into() {
cvt(pread64(fd, buf, count, o))
} else {
Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot pread >2GB"))
}
}
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
unsafe fn cvt_pread64(fd: c_int, buf: *mut c_void, count: usize, offset: i64)
-> io::Result<isize>
{
#[cfg(target_os = "linux")]
use libc::pread64;
#[cfg(not(target_os = "linux"))]
use libc::pread as pread64;
cvt(pread64(fd, buf, count, offset))
}
unsafe {
cvt_pread64(self.fd,
buf.as_mut_ptr() as *mut c_void,
cmp::min(buf.len(), max_len()),
offset as i64)
.map(|n| n as usize)
}
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
let ret = cvt(unsafe {
libc::write(self.fd,
buf.as_ptr() as *const c_void,
cmp::min(buf.len(), max_len()))
})?;
Ok(ret as usize)
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
#[cfg(target_os = "android")]
use super::android::cvt_pwrite64;
#[cfg(target_os = "emscripten")]
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
-> io::Result<isize>
{
use convert::TryInto;
use libc::pwrite64;
// pwrite64 on emscripten actually takes a 32 bit offset
if let Ok(o) = offset.try_into() {
cvt(pwrite64(fd, buf, count, o))
} else {
Err(io::Error::new(io::ErrorKind::InvalidInput,
"cannot pwrite >2GB"))
}
}
#[cfg(not(any(target_os = "android", target_os = "emscripten")))]
unsafe fn cvt_pwrite64(fd: c_int, buf: *const c_void, count: usize, offset: i64)
-> io::Result<isize>
{
#[cfg(target_os = "linux")]
use libc::pwrite64;
#[cfg(not(target_os = "linux"))]
use libc::pwrite as pwrite64;
cvt(pwrite64(fd, buf, count, offset))
}
unsafe {
cvt_pwrite64(self.fd,
buf.as_ptr() as *const c_void,
cmp::min(buf.len(), max_len()),
offset as i64)
.map(|n| n as usize)
}
}
// We don't have fork/exec on the 3DS, so this shouldn't need to do anything
#[cfg(target_os = "horizon")]
pub fn set_cloexec(&self) -> io::Result<()> {
Ok(())
}
#[cfg(target_os = "linux")]
pub fn get_cloexec(&self) -> io::Result<bool> {
unsafe {
Ok((cvt(libc::fcntl(self.fd, libc::F_GETFD))? & libc::FD_CLOEXEC) != 0)
}
}
#[cfg(target_os = "linux")]
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
unsafe {
let v = nonblocking as c_int;
cvt(libc::ioctl(self.fd, libc::FIONBIO, &v))?;
Ok(())
}
}
#[cfg(not(target_os = "linux"))]
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(())
}
}
pub fn duplicate(&self) -> io::Result<FileDesc> {
// 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)
}
}
impl<'a> Read for &'a FileDesc {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
(**self).read(buf)
}
}
impl AsInner<c_int> for FileDesc {
fn as_inner(&self) -> &c_int { &self.fd }
}
impl Drop for FileDesc {
fn drop(&mut self) {
// Note that errors are ignored when closing a file descriptor. The
// reason for this is that if an error occurs we don't actually know if
// the file descriptor was closed or not, and if we retried (for
// something like EINTR), we might close another valid file descriptor
// (opened after we closed ours.
let _ = unsafe { libc::close(self.fd) };
}
}

928
ctr-std/src/sys/horizon/fs.rs

@ -0,0 +1,928 @@
// Copyright 2013-2014 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 os::unix::prelude::*;
use ffi::{CString, CStr, OsString, OsStr};
use fmt;
use io::{self, Error, ErrorKind, SeekFrom};
use libc::{self, c_int, mode_t};
use mem;
use path::{Path, PathBuf};
use ptr;
use sync::Arc;
use sys::fd::FileDesc;
use sys::time::SystemTime;
use sys::{cvt, cvt_r};
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", target_os = "android"))]
use libc::{fstatat, dirfd};
#[cfg(target_os = "android")]
use libc::{stat as stat64, fstat as fstat64, lstat as lstat64, lseek64,
dirent as dirent64, open as open64};
#[cfg(not(any(target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
target_os = "android")))]
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};
#[cfg(not(any(target_os = "linux",
target_os = "emscripten",
target_os = "solaris",
target_os = "l4re",
target_os = "fuchsia")))]
use libc::{readdir_r as readdir64_r};
pub struct File(FileDesc);
#[derive(Clone)]
pub struct FileAttr {
stat: stat64,
}
// all DirEntry's will have a reference to this struct
struct InnerReadDir {
dirp: Dir,
root: PathBuf,
}
#[derive(Clone)]
pub struct ReadDir(Arc<InnerReadDir>);
struct Dir(*mut libc::DIR);
unsafe impl Send for Dir {}
unsafe impl Sync for Dir {}
pub struct DirEntry {
entry: dirent64,
dir: ReadDir,
// We need to store an owned copy of the entry 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)]
pub struct OpenOptions {
// generic
read: bool,
write: bool,
append: bool,
truncate: bool,
create: bool,
create_new: bool,
// system-specific
custom_flags: i32,
mode: mode_t,
}
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FilePermissions { mode: mode_t }
#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct FileType { mode: mode_t }
#[derive(Debug)]
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) }
}
pub fn file_type(&self) -> FileType {
FileType { mode: self.stat.st_mode as mode_t }
}
}
#[cfg(target_os = "netbsd")]
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: self.stat.st_mtimensec as libc::c_long,
}))
}
pub fn accessed(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timespec {
tv_sec: self.stat.st_atime as libc::time_t,
tv_nsec: self.stat.st_atimensec as libc::c_long,
}))
}
pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timespec {
tv_sec: self.stat.st_birthtime as libc::time_t,
tv_nsec: self.stat.st_birthtimensec as libc::c_long,
}))
}
}
#[cfg(not(target_os = "netbsd"))]
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 as _,
}))
}
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 as _,
}))
}
#[cfg(any(target_os = "bitrig",
target_os = "freebsd",
target_os = "openbsd",
target_os = "macos",
target_os = "ios"))]
pub fn created(&self) -> io::Result<SystemTime> {
Ok(SystemTime::from(libc::timespec {
tv_sec: self.stat.st_birthtime as libc::time_t,
tv_nsec: self.stat.st_birthtime_nsec as libc::c_long,
}))
}
#[cfg(not(any(target_os = "bitrig",
target_os = "freebsd",
target_os = "openbsd",
target_os = "macos",
target_os = "ios")))]
pub fn created(&self) -> io::Result<SystemTime> {
Err(io::Error::new(io::ErrorKind::Other,
"creation time is not available on this platform \
currently"))
}
}
impl AsInner<stat64> for FileAttr {
fn as_inner(&self) -> &stat64 { &self.stat }
}
impl FilePermissions {
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;
}
}
pub fn mode(&self) -> u32 { self.mode as u32 }
}
impl FileType {
pub fn is_dir(&self) -> bool { self.is(libc::S_IFDIR) }
pub fn is_file(&self) -> bool { self.is(libc::S_IFREG) }
pub fn is_symlink(&self) -> bool { self.is(libc::S_IFLNK) }
pub fn is(&self, mode: mode_t) -> bool { self.mode & libc::S_IFMT == mode }
}
impl FromInner<u32> for FilePermissions {
fn from_inner(mode: u32) -> FilePermissions {
FilePermissions { mode: mode as mode_t }
}
}
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)
}
}
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.0.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() as *const u8;
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(),
dir: self.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 {
entry: mem::zeroed(),
dir: self.clone(),
};
let mut entry_ptr = ptr::null_mut();
loop {
if readdir64_r(self.0.dirp.0, &mut ret.entry, &mut entry_ptr) != 0 {
return Some(Err(Error::last_os_error()))
}
if entry_ptr.is_null() {
return None
}
if ret.name_bytes() != b"." && ret.name_bytes() != b".." {
return Some(Ok(ret))
}
}
}
}
}
impl Drop for Dir {
fn drop(&mut self) {
let r = unsafe { libc::closedir(self.0) };
debug_assert_eq!(r, 0);
}
}
impl DirEntry {
pub fn path(&self) -> PathBuf {
self.dir.0.root.join(OsStr::from_bytes(self.name_bytes()))
}
pub fn file_name(&self) -> OsString {
OsStr::from_bytes(self.name_bytes()).to_os_string()
}
#[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 mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
fstatat(fd,
self.entry.d_name.as_ptr() as *const u8,
&mut stat as *mut _ as *mut _,
libc::AT_SYMLINK_NOFOLLOW)
})?;
Ok(FileAttr { stat: stat })
}
#[cfg(not(any(target_os = "linux", target_os = "emscripten", target_os = "android")))]
pub fn metadata(&self) -> io::Result<FileAttr> {
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 }),
libc::DT_FIFO => Ok(FileType { mode: libc::S_IFIFO }),
libc::DT_LNK => Ok(FileType { mode: libc::S_IFLNK }),
libc::DT_REG => Ok(FileType { mode: libc::S_IFREG }),
libc::DT_SOCK => Ok(FileType { mode: libc::S_IFSOCK }),
libc::DT_DIR => Ok(FileType { mode: libc::S_IFDIR }),
libc::DT_BLK => Ok(FileType { mode: libc::S_IFBLK }),
_ => lstat(&self.path()).map(|m| m.file_type()),
}
}
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "linux",
target_os = "emscripten",
target_os = "android",
target_os = "solaris",
target_os = "haiku",
target_os = "l4re",
target_os = "fuchsia"))]
pub fn ino(&self) -> u64 {
self.entry.d_ino as u64
}
#[cfg(any(target_os = "freebsd",
target_os = "openbsd",
target_os = "bitrig",
target_os = "netbsd",
target_os = "dragonfly"))]
pub fn ino(&self) -> u64 {
self.entry.d_fileno as u64
}
#[cfg(any(target_os = "macos",
target_os = "ios",
target_os = "netbsd",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "bitrig"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
::slice::from_raw_parts(self.entry.d_name.as_ptr() as *const u8 as *const u8,
self.entry.d_namlen as usize)
}
}
#[cfg(any(target_os = "android",
target_os = "linux",
target_os = "emscripten",
target_os = "l4re",
target_os = "haiku",
target_os = "horizon"))]
fn name_bytes(&self) -> &[u8] {
unsafe {
CStr::from_ptr(self.entry.d_name.as_ptr() as *const i8).to_bytes()
}
}
#[cfg(any(target_os = "solaris",
target_os = "fuchsia"))]
fn name_bytes(&self) -> &[u8] {
&*self.name
}
}
impl OpenOptions {
pub fn new() -> OpenOptions {
OpenOptions {
// generic
read: false,
write: false,
append: false,
truncate: false,
create: false,
create_new: false,
// system-specific
custom_flags: 0,
mode: 0o666,
}
}
pub fn read(&mut self, read: bool) { self.read = read; }
pub fn write(&mut self, write: bool) { self.write = write; }
pub fn append(&mut self, append: bool) { self.append = append; }
pub fn truncate(&mut self, truncate: bool) { self.truncate = truncate; }
pub fn create(&mut self, create: bool) { self.create = create; }
pub fn create_new(&mut self, create_new: bool) { self.create_new = create_new; }
pub fn custom_flags(&mut self, flags: i32) { self.custom_flags = flags; }
pub fn mode(&mut self, mode: u32) { self.mode = mode as mode_t; }
fn get_access_mode(&self) -> io::Result<c_int> {
match (self.read, self.write, self.append) {
(true, false, false) => Ok(libc::O_RDONLY),
(false, true, false) => Ok(libc::O_WRONLY),
(true, true, false) => Ok(libc::O_RDWR),
(false, _, true) => Ok(libc::O_WRONLY | libc::O_APPEND),
(true, _, true) => Ok(libc::O_RDWR | libc::O_APPEND),
(false, false, false) => Err(Error::from_raw_os_error(libc::EINVAL)),
}
}
fn get_creation_mode(&self) -> io::Result<c_int> {
match (self.write, self.append) {
(true, false) => {}
(false, false) =>
if self.truncate || self.create || self.create_new {
return Err(Error::from_raw_os_error(libc::EINVAL));
},
(_, true) =>
if self.truncate && !self.create_new {
return Err(Error::from_raw_os_error(libc::EINVAL));
},
}
Ok(match (self.create, self.truncate, self.create_new) {
(false, false, false) => 0,
(true, false, false) => libc::O_CREAT,
(false, true, false) => libc::O_TRUNC,
(true, true, false) => libc::O_CREAT | libc::O_TRUNC,
(_, _, true) => libc::O_CREAT | libc::O_EXCL,
})
}
}
impl File {
pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
let path = cstr(path)?;
File::open_c(&path, opts)
}
pub fn open_c(path: &CStr, opts: &OpenOptions) -> io::Result<File> {
let flags = libc::O_CLOEXEC |
opts.get_access_mode()? |
opts.get_creation_mode()? |
(opts.custom_flags as c_int & !libc::O_ACCMODE);
let fd = cvt_r(|| unsafe {
open64(path.as_ptr() as *const u8, flags, opts.mode as c_int)
})?;
let fd = FileDesc::new(fd);
// Currently the standard library supports Linux 2.6.18 which did not
// have the O_CLOEXEC flag (passed above). If we're running on an older
// Linux kernel then the flag is just ignored by the OS. After we open
// the first file, we check whether it has CLOEXEC set. If it doesn't,
// we will explicitly ask for a CLOEXEC fd for every further file we
// open, if it does, we will skip that step.
//
// The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc
// that we support, so we only do this on Linux currently.
#[cfg(target_os = "linux")]
fn ensure_cloexec(fd: &FileDesc) -> io::Result<()> {
use sync::atomic::{AtomicUsize, Ordering};
const OPEN_CLOEXEC_UNKNOWN: usize = 0;
const OPEN_CLOEXEC_SUPPORTED: usize = 1;
const OPEN_CLOEXEC_NOTSUPPORTED: usize = 2;
static OPEN_CLOEXEC: AtomicUsize = AtomicUsize::new(OPEN_CLOEXEC_UNKNOWN);
let need_to_set;
match OPEN_CLOEXEC.load(Ordering::Relaxed) {
OPEN_CLOEXEC_UNKNOWN => {
need_to_set = !fd.get_cloexec()?;
OPEN_CLOEXEC.store(if need_to_set {
OPEN_CLOEXEC_NOTSUPPORTED
} else {
OPEN_CLOEXEC_SUPPORTED
}, Ordering::Relaxed);
},
OPEN_CLOEXEC_SUPPORTED => need_to_set = false,
OPEN_CLOEXEC_NOTSUPPORTED => need_to_set = true,
_ => unreachable!(),
}
if need_to_set {
fd.set_cloexec()?;
}
Ok(())
}
#[cfg(not(target_os = "linux"))]
fn ensure_cloexec(_: &FileDesc) -> io::Result<()> {
Ok(())
}
ensure_cloexec(&fd)?;
Ok(File(fd))
}
pub fn file_attr(&self) -> io::Result<FileAttr> {
let mut stat: stat64 = unsafe { mem::zeroed() };
cvt(unsafe {
fstat64(self.0.raw(), &mut stat)
})?;
Ok(FileAttr { stat: stat })
}
pub fn fsync(&self) -> io::Result<()> {
cvt_r(|| unsafe { libc::fsync(self.0.raw()) })?;
Ok(())
}
pub fn datasync(&self) -> io::Result<()> {
cvt_r(|| unsafe { os_datasync(self.0.raw()) })?;
return Ok(());
#[cfg(any(target_os = "macos", target_os = "ios"))]
unsafe fn os_datasync(fd: c_int) -> c_int {
libc::fcntl(fd, libc::F_FULLFSYNC)
}
#[cfg(target_os = "linux")]
unsafe fn os_datasync(fd: c_int) -> c_int { libc::fdatasync(fd) }
#[cfg(not(any(target_os = "macos",
target_os = "ios",
target_os = "linux")))]
unsafe fn os_datasync(fd: c_int) -> c_int { libc::fsync(fd) }
}
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(|_| ());
}
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
pub fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result<usize> {
self.0.read_at(buf, offset)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
pub fn write_at(&self, buf: &[u8], offset: u64) -> io::Result<usize> {
self.0.write_at(buf, offset)
}
pub fn flush(&self) -> io::Result<()> { Ok(()) }
pub fn seek(&self, pos: SeekFrom) -> io::Result<u64> {
let (whence, pos) = match pos {
// Casting to `i64` is fine, too large values will end up as
// negative which will cause an error in `lseek64`.
SeekFrom::Start(off) => (libc::SEEK_SET, off as i64),
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)
}
pub fn duplicate(&self) -> io::Result<File> {
self.0.duplicate().map(File)
}
pub fn fd(&self) -> &FileDesc { &self.0 }
pub fn into_fd(self) -> FileDesc { self.0 }
pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> {
cvt_r(|| unsafe { libc::fchmod(self.0.raw(), perm.mode) })?;
Ok(())
}
}
impl DirBuilder {
pub fn new() -> DirBuilder {
DirBuilder { mode: 0o777 }
}
pub fn mkdir(&self, p: &Path) -> io::Result<()> {
let p = cstr(p)?;
cvt(unsafe { libc::mkdir(p.as_ptr() as *const u8, self.mode) })?;
Ok(())
}
pub fn set_mode(&mut self, mode: u32) {
self.mode = mode as mode_t;
}
}
fn cstr(path: &Path) -> io::Result<CString> {
Ok(CString::new(path.as_os_str().as_bytes())?)
}
impl FromInner<c_int> for File {
fn from_inner(fd: c_int) -> File {
File(FileDesc::new(fd))
}
}
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() as *const u8) };
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
}
let fd = self.0.raw();
let mut b = f.debug_struct("File");
b.field("fd", &fd);
if let Some(path) = get_path(fd) {
b.field("path", &path);
}
if let Some((read, write)) = get_mode(fd) {
b.field("read", &read).field("write", &write);
}
b.finish()
}
}
pub fn readdir(p: &Path) -> io::Result<ReadDir> {
let root = p.to_path_buf();
let p = cstr(p)?;
unsafe {
let ptr = libc::opendir(p.as_ptr() as *const u8);
if ptr.is_null() {
Err(Error::last_os_error())
} else {
let inner = InnerReadDir { dirp: Dir(ptr), root };
Ok(ReadDir(Arc::new(inner)))
}
}
}
pub fn unlink(p: &Path) -> io::Result<()> {
let p = cstr(p)?;
cvt(unsafe { libc::unlink(p.as_ptr() as *const u8) })?;
Ok(())
}
pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
let old = cstr(old)?;
let new = cstr(new)?;
cvt(unsafe { libc::rename(old.as_ptr() as *const u8, new.as_ptr() as *const u8) })?;
Ok(())
}
pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> {
let p = cstr(p)?;
cvt_r(|| unsafe { libc::chmod(p.as_ptr() as *const u8, perm.mode) })?;
Ok(())
}
pub fn rmdir(p: &Path) -> io::Result<()> {
let p = cstr(p)?;
cvt(unsafe { libc::rmdir(p.as_ptr() as *const u8) })?;
Ok(())
}
pub fn remove_dir_all(path: &Path) -> io::Result<()> {
let filetype = lstat(path)?.file_type();
if filetype.is_symlink() {
unlink(path)
} else {
remove_dir_all_recursive(path)
}
}
fn remove_dir_all_recursive(path: &Path) -> io::Result<()> {
for child in readdir(path)? {
let child = child?;
if child.file_type()?.is_dir() {
remove_dir_all_recursive(&child.path())?;
} else {
unlink(&child.path())?;
}
}
rmdir(path)
}
pub fn readlink(p: &Path) -> io::Result<PathBuf> {
let c_path = cstr(p)?;
let p = c_path.as_ptr() as *const u8;
let mut buf = Vec::with_capacity(256);
loop {
let buf_read = cvt(unsafe {
libc::readlink(p, buf.as_mut_ptr() as *mut _, buf.capacity())
})? as usize;
unsafe { buf.set_len(buf_read); }
if buf_read != buf.capacity() {
buf.shrink_to_fit();
return Ok(PathBuf::from(OsString::from_vec(buf)));
}
// Trigger the internal buffer resizing logic of `Vec` by requiring
// more space than the current capacity. The length is guaranteed to be
// the same as the capacity due to the if statement above.
buf.reserve(1);
}
}
pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
let src = cstr(src)?;
let dst = cstr(dst)?;
cvt(unsafe { libc::symlink(src.as_ptr() as *const u8, dst.as_ptr() as *const u8) })?;
Ok(())
}
pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
let src = cstr(src)?;
let dst = cstr(dst)?;
cvt(unsafe { libc::link(src.as_ptr() as *const u8, dst.as_ptr() as *const u8) })?;
Ok(())
}
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() as *const u8, &mut stat as *mut _ as *mut _)
})?;
Ok(FileAttr { stat: stat })
}
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() as *const u8, &mut stat as *mut _ as *mut _)
})?;
Ok(FileAttr { stat: stat })
}
pub fn canonicalize(p: &Path) -> io::Result<PathBuf> {
let path = CString::new(p.as_os_str().as_bytes())?;
let buf;
unsafe {
let r = libc::realpath(path.as_ptr() as *const u8, ptr::null_mut());
if r.is_null() {
return Err(io::Error::last_os_error())
}
buf = CStr::from_ptr(r as *const i8).to_bytes().to_vec();
libc::free(r as *mut _);
}
Ok(PathBuf::from(OsString::from_vec(buf)))
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use fs::File;
if !from.is_file() {
return Err(Error::new(ErrorKind::InvalidInput,
"the source path is not an existing regular file"))
}
let mut reader = File::open(from)?;
let mut writer = File::create(to)?;
let perm = reader.metadata()?.permissions();
let ret = io::copy(&mut reader, &mut writer)?;
writer.set_permissions(perm)?;
Ok(ret)
}
#[cfg(any(target_os = "linux", target_os = "android"))]
pub fn copy(from: &Path, to: &Path) -> io::Result<u64> {
use cmp;
use fs::File;
use sync::atomic::{AtomicBool, Ordering};
// Kernel prior to 4.5 don't have copy_file_range
// We store the availability in a global to avoid unneccessary syscalls
static HAS_COPY_FILE_RANGE: AtomicBool = AtomicBool::new(true);
unsafe fn copy_file_range(
fd_in: libc::c_int,
off_in: *mut libc::loff_t,
fd_out: libc::c_int,
off_out: *mut libc::loff_t,
len: libc::size_t,
flags: libc::c_uint,
) -> libc::c_long {
libc::syscall(
libc::SYS_copy_file_range,
fd_in,
off_in,
fd_out,
off_out,
len,
flags,
)
}
if !from.is_file() {
return Err(Error::new(ErrorKind::InvalidInput,
"the source path is not an existing regular file"))
}
let mut reader = File::open(from)?;
let mut writer = File::create(to)?;
let (perm, len) = {
let metadata = reader.metadata()?;
(metadata.permissions(), metadata.size())
};
let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed);
let mut written = 0u64;
while written < len {
let copy_result = if has_copy_file_range {
let bytes_to_copy = cmp::min(len - written, usize::max_value() as u64) as usize;
let copy_result = unsafe {
// We actually don't have to adjust the offsets,
// because copy_file_range adjusts the file offset automatically
cvt(copy_file_range(reader.as_raw_fd(),
ptr::null_mut(),
writer.as_raw_fd(),
ptr::null_mut(),
bytes_to_copy,
0)
)
};
if let Err(ref copy_err) = copy_result {
match copy_err.raw_os_error() {
Some(libc::ENOSYS) | Some(libc::EPERM) => {
HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed);
}
_ => {}
}
}
copy_result
} else {
Err(io::Error::from_raw_os_error(libc::ENOSYS))
};
match copy_result {
Ok(ret) => written += ret as u64,
Err(err) => {
match err.raw_os_error() {
Some(os_err) if os_err == libc::ENOSYS
|| os_err == libc::EXDEV
|| os_err == libc::EPERM => {
// Try fallback io::copy if either:
// - Kernel version is < 4.5 (ENOSYS)
// - Files are mounted on different fs (EXDEV)
// - copy_file_range is disallowed, for example by seccomp (EPERM)
assert_eq!(written, 0);
let ret = io::copy(&mut reader, &mut writer)?;
writer.set_permissions(perm)?;
return Ok(ret)
},
_ => return Err(err),
}
}
}
}
writer.set_permissions(perm)?;
Ok(written)
}

441
ctr-std/src/sys/horizon/l4re.rs

@ -0,0 +1,441 @@
// Copyright 2016-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.
macro_rules! unimpl {
() => (return Err(io::Error::new(io::ErrorKind::Other, "No networking available on L4Re."));)
}
pub mod net {
#![allow(warnings)]
use fmt;
use io;
use libc;
use net::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr};
use sys_common::{AsInner, FromInner, IntoInner};
use sys::fd::FileDesc;
use time::Duration;
pub extern crate libc as netc;
pub struct Socket(FileDesc);
impl Socket {
pub fn new(_: &SocketAddr, _: libc::c_int) -> io::Result<Socket> {
unimpl!();
}
pub fn new_raw(_: libc::c_int, _: libc::c_int) -> io::Result<Socket> {
unimpl!();
}
pub fn new_pair(_: libc::c_int, _: libc::c_int) -> io::Result<(Socket, Socket)> {
unimpl!();
}
pub fn connect_timeout(&self, _: &SocketAddr, _: Duration) -> io::Result<()> {
unimpl!();
}
pub fn accept(&self, _: *mut libc::sockaddr, _: *mut libc::socklen_t)
-> io::Result<Socket> {
unimpl!();
}
pub fn duplicate(&self) -> io::Result<Socket> {
unimpl!();
}
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
unimpl!();
}
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
unimpl!();
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
unimpl!();
}
pub fn set_timeout(&self, _: Option<Duration>, _: libc::c_int) -> io::Result<()> {
unimpl!();
}
pub fn timeout(&self, _: libc::c_int) -> io::Result<Option<Duration>> {
unimpl!();
}
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
unimpl!();
}
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
unimpl!();
}
pub fn nodelay(&self) -> io::Result<bool> {
unimpl!();
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
unimpl!();
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unimpl!();
}
}
impl AsInner<libc::c_int> for Socket {
fn as_inner(&self) -> &libc::c_int { self.0.as_inner() }
}
impl FromInner<libc::c_int> for Socket {
fn from_inner(fd: libc::c_int) -> Socket { Socket(FileDesc::new(fd)) }
}
impl IntoInner<libc::c_int> for Socket {
fn into_inner(self) -> libc::c_int { self.0.into_raw() }
}
pub struct TcpStream {
inner: Socket,
}
impl TcpStream {
pub fn connect(_: &SocketAddr) -> io::Result<TcpStream> {
unimpl!();
}
pub fn connect_timeout(_: &SocketAddr, _: Duration) -> io::Result<TcpStream> {
unimpl!();
}
pub fn socket(&self) -> &Socket { &self.inner }
pub fn into_socket(self) -> Socket { self.inner }
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
unimpl!();
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
unimpl!();
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
unimpl!();
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
unimpl!();
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
pub fn read(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
pub fn write(&self, _: &[u8]) -> io::Result<usize> {
unimpl!();
}
pub fn peer_addr(&self) -> io::Result<SocketAddr> {
unimpl!();
}
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
unimpl!();
}
pub fn shutdown(&self, _: Shutdown) -> io::Result<()> {
unimpl!();
}
pub fn duplicate(&self) -> io::Result<TcpStream> {
unimpl!();
}
pub fn set_nodelay(&self, _: bool) -> io::Result<()> {
unimpl!();
}
pub fn nodelay(&self) -> io::Result<bool> {
unimpl!();
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
unimpl!();
}
pub fn ttl(&self) -> io::Result<u32> {
unimpl!();
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unimpl!();
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
unimpl!();
}
}
impl FromInner<Socket> for TcpStream {
fn from_inner(socket: Socket) -> TcpStream {
TcpStream { inner: socket }
}
}
impl fmt::Debug for TcpStream {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "No networking support available on L4Re")
}
}
pub struct TcpListener {
inner: Socket,
}
impl TcpListener {
pub fn bind(_: &SocketAddr) -> io::Result<TcpListener> {
unimpl!();
}
pub fn socket(&self) -> &Socket { &self.inner }
pub fn into_socket(self) -> Socket { self.inner }
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
unimpl!();
}
pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
unimpl!();
}
pub fn duplicate(&self) -> io::Result<TcpListener> {
unimpl!();
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
unimpl!();
}
pub fn ttl(&self) -> io::Result<u32> {
unimpl!();
}
pub fn set_only_v6(&self, _: bool) -> io::Result<()> {
unimpl!();
}
pub fn only_v6(&self) -> io::Result<bool> {
unimpl!();
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unimpl!();
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
unimpl!();
}
}
impl FromInner<Socket> for TcpListener {
fn from_inner(socket: Socket) -> TcpListener {
TcpListener { inner: socket }
}
}
impl fmt::Debug for TcpListener {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "No networking support available on L4Re.")
}
}
pub struct UdpSocket {
inner: Socket,
}
impl UdpSocket {
pub fn bind(_: &SocketAddr) -> io::Result<UdpSocket> {
unimpl!();
}
pub fn socket(&self) -> &Socket { &self.inner }
pub fn into_socket(self) -> Socket { self.inner }
pub fn socket_addr(&self) -> io::Result<SocketAddr> {
unimpl!();
}
pub fn recv_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
unimpl!();
}
pub fn peek_from(&self, _: &mut [u8]) -> io::Result<(usize, SocketAddr)> {
unimpl!();
}
pub fn send_to(&self, _: &[u8], _: &SocketAddr) -> io::Result<usize> {
unimpl!();
}
pub fn duplicate(&self) -> io::Result<UdpSocket> {
unimpl!();
}
pub fn set_read_timeout(&self, _: Option<Duration>) -> io::Result<()> {
unimpl!();
}
pub fn set_write_timeout(&self, _: Option<Duration>) -> io::Result<()> {
unimpl!();
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
unimpl!();
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
unimpl!();
}
pub fn set_broadcast(&self, _: bool) -> io::Result<()> {
unimpl!();
}
pub fn broadcast(&self) -> io::Result<bool> {
unimpl!();
}
pub fn set_multicast_loop_v4(&self, _: bool) -> io::Result<()> {
unimpl!();
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
unimpl!();
}
pub fn set_multicast_ttl_v4(&self, _: u32) -> io::Result<()> {
unimpl!();
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
unimpl!();
}
pub fn set_multicast_loop_v6(&self, _: bool) -> io::Result<()> {
unimpl!();
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
unimpl!();
}
pub fn join_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
-> io::Result<()> {
unimpl!();
}
pub fn join_multicast_v6(&self, _: &Ipv6Addr, _: u32)
-> io::Result<()> {
unimpl!();
}
pub fn leave_multicast_v4(&self, _: &Ipv4Addr, _: &Ipv4Addr)
-> io::Result<()> {
unimpl!();
}
pub fn leave_multicast_v6(&self, _: &Ipv6Addr, _: u32)
-> io::Result<()> {
unimpl!();
}
pub fn set_ttl(&self, _: u32) -> io::Result<()> {
unimpl!();
}
pub fn ttl(&self) -> io::Result<u32> {
unimpl!();
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
unimpl!();
}
pub fn set_nonblocking(&self, _: bool) -> io::Result<()> {
unimpl!();
}
pub fn recv(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
pub fn peek(&self, _: &mut [u8]) -> io::Result<usize> {
unimpl!();
}
pub fn send(&self, _: &[u8]) -> io::Result<usize> {
unimpl!();
}
pub fn connect(&self, _: &SocketAddr) -> io::Result<()> {
unimpl!();
}
}
impl FromInner<Socket> for UdpSocket {
fn from_inner(socket: Socket) -> UdpSocket {
UdpSocket { inner: socket }
}
}
impl fmt::Debug for UdpSocket {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "No networking support on L4Re available.")
}
}
pub struct LookupHost {
original: *mut libc::addrinfo,
cur: *mut libc::addrinfo,
}
impl Iterator for LookupHost {
type Item = SocketAddr;
fn next(&mut self) -> Option<SocketAddr> {
None
}
}
unsafe impl Sync for LookupHost {}
unsafe impl Send for LookupHost {}
pub fn lookup_host(_: &str) -> io::Result<LookupHost> {
unimpl!();
}
}

57
ctr-std/src/sys/horizon/memchr.rs

@ -0,0 +1,57 @@
// 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.
//
// Original implementation taken from rust-memchr
// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch
pub fn memchr(needle: u8, haystack: &[u8]) -> Option<usize> {
use libc;
let p = unsafe {
libc::memchr(
haystack.as_ptr() as *const libc::c_void,
needle as libc::c_int,
haystack.len())
};
if p.is_null() {
None
} else {
Some(p as usize - (haystack.as_ptr() as usize))
}
}
pub fn memrchr(needle: u8, haystack: &[u8]) -> Option<usize> {
#[cfg(target_os = "linux")]
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
use libc;
// GNU's memrchr() will - unlike memchr() - error if haystack is empty.
if haystack.is_empty() {return None}
let p = unsafe {
libc::memrchr(
haystack.as_ptr() as *const libc::c_void,
needle as libc::c_int,
haystack.len())
};
if p.is_null() {
None
} else {
Some(p as usize - (haystack.as_ptr() as usize))
}
}
#[cfg(not(target_os = "linux"))]
fn memrchr_specific(needle: u8, haystack: &[u8]) -> Option<usize> {
::core::slice::memchr::memrchr(needle, haystack)
}
memrchr_specific(needle, haystack)
}

179
ctr-std/src/sys/horizon/mod.rs

@ -0,0 +1,179 @@
// Copyright 2014 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(missing_docs, bad_style)]
use io::{self, ErrorKind};
use libc;
#[cfg(any(dox, target_os = "linux"))] pub use os::linux as platform;
#[cfg(all(not(dox), target_os = "android"))] pub use os::android as platform;
#[cfg(all(not(dox), target_os = "bitrig"))] pub use os::bitrig as platform;
#[cfg(all(not(dox), target_os = "dragonfly"))] pub use os::dragonfly as platform;
#[cfg(all(not(dox), target_os = "freebsd"))] pub use os::freebsd as platform;
#[cfg(all(not(dox), target_os = "haiku"))] pub use os::haiku as platform;
#[cfg(all(not(dox), target_os = "ios"))] pub use os::ios as platform;
#[cfg(all(not(dox), target_os = "macos"))] pub use os::macos as platform;
#[cfg(all(not(dox), target_os = "netbsd"))] pub use os::netbsd as platform;
#[cfg(all(not(dox), target_os = "openbsd"))] pub use os::openbsd as platform;
#[cfg(all(not(dox), target_os = "solaris"))] pub use os::solaris as platform;
#[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 = "horizon"))] pub use os::horizon as platform;
pub use self::rand::hashmap_random_keys;
pub use libc::strlen;
#[macro_use]
pub mod weak;
pub mod args;
pub mod android;
#[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 memchr;
pub mod mutex;
#[cfg(not(target_os = "l4re"))]
pub mod net;
#[cfg(target_os = "l4re")]
mod l4re;
#[cfg(target_os = "l4re")]
pub use self::l4re::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 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();
}
#[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))]
unsafe fn reset_sigpipe() {
assert!(signal(0 as _, libc::SIG_IGN) != libc::SIG_ERR);
}
#[cfg(any(target_os = "emscripten", target_os = "fuchsia"))]
unsafe fn reset_sigpipe() {}
}
#[cfg(target_os = "android")]
pub use sys::android::signal;
#[cfg(not(target_os = "android"))]
pub use libc::signal;
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")
}
#[derive(Copy,Clone)]
pub enum Void {}
pub fn decode_error_kind(errno: i32) -> ErrorKind {
match errno as libc::c_int {
libc::ECONNREFUSED => ErrorKind::ConnectionRefused,
libc::ECONNRESET => ErrorKind::ConnectionReset,
libc::EPERM | libc::EACCES => ErrorKind::PermissionDenied,
libc::EPIPE => ErrorKind::BrokenPipe,
libc::ENOTCONN => ErrorKind::NotConnected,
libc::ECONNABORTED => ErrorKind::ConnectionAborted,
libc::EADDRNOTAVAIL => ErrorKind::AddrNotAvailable,
libc::EADDRINUSE => ErrorKind::AddrInUse,
libc::ENOENT => ErrorKind::NotFound,
libc::EINTR => ErrorKind::Interrupted,
libc::EINVAL => ErrorKind::InvalidInput,
libc::ETIMEDOUT => ErrorKind::TimedOut,
libc::EEXIST => ErrorKind::AlreadyExists,
// These two constants can have the same value on some systems,
// but different values on others, so we can't use a match
// clause
x if x == libc::EAGAIN || x == libc::EWOULDBLOCK =>
ErrorKind::WouldBlock,
_ => ErrorKind::Other,
}
}
#[doc(hidden)]
pub trait IsMinusOne {
fn is_minus_one(&self) -> bool;
}
macro_rules! impl_is_minus_one {
($($t:ident)*) => ($(impl IsMinusOne for $t {
fn is_minus_one(&self) -> bool {
*self == -1
}
})*)
}
impl_is_minus_one! { i8 i16 i32 i64 isize }
pub fn cvt<T: IsMinusOne>(t: T) -> io::Result<T> {
if t.is_minus_one() {
Err(io::Error::last_os_error())
} else {
Ok(t)
}
}
pub fn cvt_r<T, F>(mut f: F) -> io::Result<T>
where T: IsMinusOne,
F: FnMut() -> T
{
loop {
match cvt(f()) {
Err(ref e) if e.kind() == ErrorKind::Interrupted => {}
other => return other,
}
}
}
// 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()
}

90
ctr-std/src/sys/horizon/mutex.rs

@ -0,0 +1,90 @@
// 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 cell::UnsafeCell;
use mem;
pub struct Mutex {
inner: UnsafeCell<::libctru::LightLock>,
}
#[inline]
pub unsafe fn raw(m: &Mutex) -> *mut ::libctru::LightLock {
m.inner.get()
}
unsafe impl Send for Mutex {}
unsafe impl Sync for Mutex {}
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()) {
0 => false,
_ => true,
}
}
#[inline]
pub unsafe fn destroy(&self) {
}
}
pub struct ReentrantMutex { inner: UnsafeCell<::libctru::RecursiveLock> }
unsafe impl Send for ReentrantMutex {}
unsafe impl Sync for ReentrantMutex {}
impl ReentrantMutex {
pub unsafe fn uninitialized() -> ReentrantMutex {
ReentrantMutex { inner: mem::uninitialized() }
}
pub unsafe fn init(&mut self) {
::libctru::RecursiveLock_Init(self.inner.get());
}
pub unsafe fn lock(&self) {
::libctru::RecursiveLock_Lock(self.inner.get());
}
#[inline]
pub unsafe fn try_lock(&self) -> bool {
match ::libctru::RecursiveLock_TryLock(self.inner.get()) {
0 => false,
_ => true,
}
}
pub unsafe fn unlock(&self) {
::libctru::RecursiveLock_Unlock(self.inner.get());
}
pub unsafe fn destroy(&self) {}
}

428
ctr-std/src/sys/horizon/net.rs

@ -0,0 +1,428 @@
// 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, 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;
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;
const EAI_SYSTEM: c_int = 0;
pub struct Socket(FileDesc);
pub fn init() {}
pub fn cvt_gai(err: c_int) -> io::Result<()> {
if err == 0 {
return Ok(())
}
// We may need to trigger a glibc workaround. See on_resolver_failure() for details.
on_resolver_failure();
if err == EAI_SYSTEM {
return Err(io::Error::last_os_error())
}
let detail = unsafe {
str::from_utf8(CStr::from_ptr(libc::gai_strerror(err) as *const i8).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> {
// Unfortunately the only known way right now to accept a socket and
// atomically set the CLOEXEC flag is to use the `accept4` syscall on
// Linux. This was added in 2.6.28, however, and because we support
// 2.6.18 we must detect this support dynamically.
if cfg!(target_os = "linux") {
weak! {
fn accept4(c_int, *mut sockaddr, *mut socklen_t, c_int) -> c_int
}
if let Some(accept) = accept4.get() {
let res = cvt_r(|| unsafe {
accept(self.0.raw(), storage, len, SOCK_CLOEXEC)
});
match res {
Ok(fd) => return Ok(Socket(FileDesc::new(fd))),
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {}
Err(e) => return Err(e),
}
}
}
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)
}
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).
#[cfg(target_env = "gnu")]
fn on_resolver_failure() {
use sys;
// If the version fails to parse, we treat it the same as "not glibc".
if let Some(version) = sys::os::glibc_version() {
if version < (2, 26) {
unsafe { libc::res_init() };
}
}
}
#[cfg(not(target_env = "gnu"))]
fn on_resolver_failure() {}
#[cfg(all(test, taget_env = "gnu"))]
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));
}
}
}

191
ctr-std/src/sys/horizon/os.rs

@ -0,0 +1,191 @@
// 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 error::Error as StdError;
use ffi::{CString, CStr, OsString, OsStr};
use fmt;
use io;
use iter;
use libc::{self, c_int, c_char};
use path::{self, PathBuf};
use slice;
use str;
use sys::{unsupported, Void};
use sys::horizon::ext::ffi::{OsStrExt, OsStringExt};
const TMPBUF_SZ: usize = 128;
extern "C" {
fn __errno() -> *mut c_int;
}
/// Returns the platform-specific value of errno
pub fn errno() -> i32 {
unsafe {
(*__errno()) as i32
}
}
/// Gets a detailed string description for the given error number.
pub fn error_string(errno: i32) -> String {
extern {
#[cfg_attr(any(target_os = "linux", target_env = "newlib"),
link_name = "__xpg_strerror_r")]
fn strerror_r(errnum: c_int, buf: *mut c_char,
buflen: libc::size_t) -> c_int;
}
let mut buf = [0 as c_char; TMPBUF_SZ];
let p = buf.as_mut_ptr();
unsafe {
if strerror_r(errno as c_int, p, buf.len()) < 0 {
panic!("strerror_r failure");
}
let p = p as *const _;
str::from_utf8(CStr::from_ptr(p).to_bytes()).unwrap().to_owned()
}
}
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 i8).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() as *const u8) == (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>,
fn(&'a [u8]) -> PathBuf>,
}
pub fn split_paths(unparsed: &OsStr) -> SplitPaths {
fn bytes_to_path(b: &[u8]) -> PathBuf {
PathBuf::from(<OsStr as OsStrExt>::from_bytes(b))
}
fn is_colon(b: &u8) -> bool { *b == b':' }
let unparsed = unparsed.as_bytes();
SplitPaths {
iter: unparsed.split(is_colon as fn(&u8) -> bool)
.map(bytes_to_path as fn(&[u8]) -> PathBuf)
}
}
impl<'a> Iterator for SplitPaths<'a> {
type Item = PathBuf;
fn next(&mut self) -> Option<PathBuf> { self.iter.next() }
fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
}
#[derive(Debug)]
pub struct JoinPathsError;
pub fn join_paths<I, T>(paths: I) -> Result<OsString, JoinPathsError>
where I: Iterator<Item=T>, T: AsRef<OsStr>
{
let mut joined = Vec::new();
let sep = b':';
for (i, path) in paths.enumerate() {
let path = path.as_ref().as_bytes();
if i > 0 { joined.push(sep) }
if path.contains(&sep) {
return Err(JoinPathsError)
}
joined.extend_from_slice(path);
}
Ok(OsStringExt::from_vec(joined))
}
impl fmt::Display for JoinPathsError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
"path segment contains separator `:`".fmt(f)
}
}
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")
}

189
ctr-std/src/sys/horizon/os_str.rs

@ -0,0 +1,189 @@
// 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.
/// The underlying OsString/OsStr implementation on Unix systems: just
/// a `Vec<u8>`/`[u8]`.
use borrow::Cow;
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 core::str::lossy::Utf8Lossy;
#[derive(Clone, Hash)]
pub struct Buf {
pub inner: Vec<u8>
}
pub struct Slice {
pub inner: [u8]
}
impl fmt::Debug for Slice {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
debug_fmt_bytestring(&self.inner, 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)
}
}
impl IntoInner<Vec<u8>> for Buf {
fn into_inner(self) -> Vec<u8> {
self.inner
}
}
impl AsInner<[u8]> for Buf {
fn as_inner(&self) -> &[u8] {
&self.inner
}
}
impl Buf {
pub fn from_string(s: String) -> Buf {
Buf { inner: s.into_bytes() }
}
#[inline]
pub fn with_capacity(capacity: usize) -> Buf {
Buf {
inner: Vec::with_capacity(capacity)
}
}
#[inline]
pub fn clear(&mut self) {
self.inner.clear()
}
#[inline]
pub fn capacity(&self) -> usize {
self.inner.capacity()
}
#[inline]
pub fn reserve(&mut self, additional: usize) {
self.inner.reserve(additional)
}
#[inline]
pub fn reserve_exact(&mut self, additional: usize) {
self.inner.reserve_exact(additional)
}
#[inline]
pub fn shrink_to_fit(&mut self) {
self.inner.shrink_to_fit()
}
#[inline]
pub fn shrink_to(&mut self, min_capacity: usize) {
self.inner.shrink_to(min_capacity)
}
pub fn as_slice(&self) -> &Slice {
unsafe { mem::transmute(&*self.inner) }
}
pub fn into_string(self) -> Result<String, Buf> {
String::from_utf8(self.inner).map_err(|p| Buf { inner: p.into_bytes() } )
}
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 {
fn from_u8_slice(s: &[u8]) -> &Slice {
unsafe { mem::transmute(s) }
}
pub fn from_str(s: &str) -> &Slice {
Slice::from_u8_slice(s.as_bytes())
}
pub fn to_str(&self) -> Option<&str> {
str::from_utf8(&self.inner).ok()
}
pub fn to_string_lossy(&self) -> Cow<str> {
String::from_utf8_lossy(&self.inner)
}
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) }
}
}

29
ctr-std/src/sys/horizon/path.rs

@ -0,0 +1,29 @@
// 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 path::Prefix;
use ffi::OsStr;
#[inline]
pub fn is_sep_byte(b: u8) -> bool {
b == b'/'
}
#[inline]
pub fn is_verbatim_sep(b: u8) -> bool {
b == b'/'
}
pub fn parse_prefix(_: &OsStr) -> Option<Prefix> {
None
}
pub const MAIN_SEP_STR: &'static str = "/";
pub const MAIN_SEP: char = '/';

137
ctr-std/src/sys/horizon/pipe.rs

@ -0,0 +1,137 @@
// 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 io;
use libc::{self, c_int};
use mem;
use sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT, Ordering};
use sys::fd::FileDesc;
use sys::{cvt, cvt_r};
////////////////////////////////////////////////////////////////////////////////
// Anonymous pipes
////////////////////////////////////////////////////////////////////////////////
pub struct AnonPipe(FileDesc);
pub fn anon_pipe() -> io::Result<(AnonPipe, AnonPipe)> {
weak! { fn pipe2(*mut c_int, c_int) -> c_int }
static INVALID: AtomicBool = ATOMIC_BOOL_INIT;
let mut fds = [0; 2];
// Unfortunately the only known way right now to create atomically set the
// CLOEXEC flag is to use the `pipe2` syscall on Linux. This was added in
// 2.6.27, however, and because we support 2.6.18 we must detect this
// support dynamically.
if cfg!(any(target_os = "dragonfly",
target_os = "freebsd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd")) &&
!INVALID.load(Ordering::SeqCst)
{
if let Some(pipe) = pipe2.get() {
// Note that despite calling a glibc function here we may still
// get ENOSYS. Glibc has `pipe2` since 2.9 and doesn't try to
// emulate on older kernels, so if you happen to be running on
// an older kernel you may see `pipe2` as a symbol but still not
// see the syscall.
match cvt(unsafe { pipe(fds.as_mut_ptr(), libc::O_CLOEXEC) }) {
Ok(_) => {
return Ok((AnonPipe(FileDesc::new(fds[0])),
AnonPipe(FileDesc::new(fds[1]))));
}
Err(ref e) if e.raw_os_error() == Some(libc::ENOSYS) => {
INVALID.store(true, Ordering::SeqCst);
}
Err(e) => return Err(e),
}
}
}
cvt(unsafe { libc::pipe(fds.as_mut_ptr()) })?;
let fd0 = FileDesc::new(fds[0]);
let fd1 = FileDesc::new(fds[1]);
fd0.set_cloexec()?;
fd1.set_cloexec()?;
Ok((AnonPipe(fd0), AnonPipe(fd1)))
}
impl AnonPipe {
pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> {
self.0.read(buf)
}
pub fn write(&self, buf: &[u8]) -> io::Result<usize> {
self.0.write(buf)
}
pub fn fd(&self) -> &FileDesc { &self.0 }
pub fn into_fd(self) -> FileDesc { self.0 }
pub fn diverge(&self) -> ! {
panic!()
}
}
pub fn read2(p1: AnonPipe,
v1: &mut Vec<u8>,
p2: AnonPipe,
v2: &mut Vec<u8>) -> io::Result<()> {
// Set both pipes into nonblocking mode as we're gonna be reading from both
// in the `select` loop below, and we wouldn't want one to block the other!
let p1 = p1.into_fd();
let p2 = p2.into_fd();
p1.set_nonblocking(true)?;
p2.set_nonblocking(true)?;
let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
fds[0].fd = p1.raw();
fds[0].events = libc::POLLIN;
fds[1].fd = p2.raw();
fds[1].events = libc::POLLIN;
loop {
// wait for either pipe to become readable using `poll`
cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?;
if fds[0].revents != 0 && read(&p1, v1)? {
p2.set_nonblocking(false)?;
return p2.read_to_end(v2).map(|_| ());
}
if fds[1].revents != 0 && read(&p2, v2)? {
p1.set_nonblocking(false)?;
return p1.read_to_end(v1).map(|_| ());
}
}
// Read as much as we can from each pipe, ignoring EWOULDBLOCK or
// EAGAIN. If we hit EOF, then this will happen because the underlying
// reader will return Ok(0), in which case we'll see `Ok` ourselves. In
// this case we flip the other fd back into blocking mode and read
// whatever's leftover on that file descriptor.
fn read(fd: &FileDesc, dst: &mut Vec<u8>) -> Result<bool, io::Error> {
match fd.read_to_end(dst) {
Ok(_) => Ok(true),
Err(e) => {
if e.raw_os_error() == Some(libc::EWOULDBLOCK) ||
e.raw_os_error() == Some(libc::EAGAIN) {
Ok(false)
} else {
Err(e)
}
}
}
}
}

151
ctr-std/src/sys/horizon/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 {}
}
}

241
ctr-std/src/sys/horizon/rand.rs

@ -0,0 +1,241 @@
// Copyright 2013-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 mem;
use slice;
pub fn hashmap_random_keys() -> (u64, u64) {
let mut v = (0, 0);
unsafe {
let view = slice::from_raw_parts_mut(&mut v as *mut _ as *mut u8,
mem::size_of_val(&v));
imp::fill_bytes(view);
}
return v
}
#[cfg(target_os = "horizon")]
mod imp {
use libctru;
pub fn fill_bytes(v: &mut [u8]) {
unsafe {
// Initializing and de-initializing the sslC subsystem every time
// we initialize a hashmap is pretty dumb, but I can't think of a
// better method at the moment.
//
// lazy_static won't work because
// destructors (for closing the subsystem on exit) won't run.
//
// Perhaps overriding __appInit() and __appExit() will work,
// but that's an experiment for another time.
libctru::sslcInit(0);
libctru::sslcGenerateRandomData(v.as_ptr() as _, v.len() as u32);
libctru::sslcExit();
}
}
}
#[cfg(all(unix,
not(target_os = "ios"),
not(target_os = "openbsd"),
not(target_os = "freebsd"),
not(target_os = "fuchsia"),
not(target_os = "horizon")
))]
mod imp {
use fs::File;
use io::Read;
use libc;
use sys::os::errno;
#[cfg(any(target_os = "linux", target_os = "android"))]
fn getrandom(buf: &mut [u8]) -> libc::c_long {
unsafe {
libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK)
}
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }
fn getrandom_fill_bytes(v: &mut [u8]) -> bool {
let mut read = 0;
while read < v.len() {
let result = getrandom(&mut v[read..]);
if result == -1 {
let err = errno() as libc::c_int;
if err == libc::EINTR {
continue;
} else if err == libc::EAGAIN {
return false
} else {
panic!("unexpected getrandom error: {}", err);
}
} else {
read += result as usize;
}
}
return true
}
#[cfg(any(target_os = "linux", target_os = "android"))]
fn is_getrandom_available() -> bool {
use io;
use sync::atomic::{AtomicBool, Ordering};
use sync::Once;
static CHECKER: Once = Once::new();
static AVAILABLE: AtomicBool = AtomicBool::new(false);
CHECKER.call_once(|| {
let mut buf: [u8; 0] = [];
let result = getrandom(&mut buf);
let available = if result == -1 {
let err = io::Error::last_os_error().raw_os_error();
err != Some(libc::ENOSYS)
} else {
true
};
AVAILABLE.store(available, Ordering::Relaxed);
});
AVAILABLE.load(Ordering::Relaxed)
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
fn is_getrandom_available() -> bool { false }
pub fn fill_bytes(v: &mut [u8]) {
// getrandom_fill_bytes here can fail if getrandom() returns EAGAIN,
// meaning it would have blocked because the non-blocking pool (urandom)
// has not initialized in the kernel yet due to a lack of entropy the
// fallback we do here is to avoid blocking applications which could
// depend on this call without ever knowing they do and don't have a
// work around. The PRNG of /dev/urandom will still be used but not
// over a completely full entropy pool
if is_getrandom_available() && getrandom_fill_bytes(v) {
return
}
let mut file = File::open("/dev/urandom")
.expect("failed to open /dev/urandom");
file.read_exact(v).expect("failed to read /dev/urandom");
}
}
#[cfg(target_os = "openbsd")]
mod imp {
use libc;
use sys::os::errno;
pub fn fill_bytes(v: &mut [u8]) {
// getentropy(2) permits a maximum buffer size of 256 bytes
for s in v.chunks_mut(256) {
let ret = unsafe {
libc::getentropy(s.as_mut_ptr() as *mut libc::c_void, s.len())
};
if ret == -1 {
panic!("unexpected getentropy error: {}", errno());
}
}
}
}
#[cfg(target_os = "ios")]
mod imp {
use io;
use libc::{c_int, size_t};
use ptr;
enum SecRandom {}
#[allow(non_upper_case_globals)]
const kSecRandomDefault: *const SecRandom = ptr::null();
extern {
fn SecRandomCopyBytes(rnd: *const SecRandom,
count: size_t,
bytes: *mut u8) -> c_int;
}
pub fn fill_bytes(v: &mut [u8]) {
let ret = unsafe {
SecRandomCopyBytes(kSecRandomDefault,
v.len(),
v.as_mut_ptr())
};
if ret == -1 {
panic!("couldn't generate random bytes: {}",
io::Error::last_os_error());
}
}
}
#[cfg(target_os = "freebsd")]
mod imp {
use libc;
use ptr;
pub fn fill_bytes(v: &mut [u8]) {
let mib = [libc::CTL_KERN, libc::KERN_ARND];
// kern.arandom permits a maximum buffer size of 256 bytes
for s in v.chunks_mut(256) {
let mut s_len = s.len();
let ret = unsafe {
libc::sysctl(mib.as_ptr(), mib.len() as libc::c_uint,
s.as_mut_ptr() as *mut _, &mut s_len,
ptr::null(), 0)
};
if ret == -1 || s_len != s.len() {
panic!("kern.arandom sysctl failed! (returned {}, s.len() {}, oldlenp {})",
ret, s.len(), s_len);
}
}
}
}
#[cfg(target_os = "fuchsia")]
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)
}
}
}
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)..];
}
}
}
}
}

127
ctr-std/src/sys/horizon/rwlock.rs

@ -0,0 +1,127 @@
// 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.
use cell::UnsafeCell;
use super::mutex::Mutex;
use super::condvar::Condvar;
// A simple read-preferring RWLock implementation that I found on wikipedia <.<
pub struct RWLock {
mutex: Mutex,
cvar: Condvar,
reader_count: UnsafeCell<u32>,
writer_active: UnsafeCell<bool>,
}
unsafe impl Send for RWLock {}
unsafe impl Sync for RWLock {}
impl RWLock {
pub const fn new() -> RWLock {
RWLock {
mutex: Mutex::new(),
cvar: Condvar::new(),
reader_count: UnsafeCell::new(0),
writer_active: UnsafeCell::new(false),
}
}
#[inline]
pub unsafe fn read(&self) {
self.mutex.lock();
while *self.writer_active.get() {
self.cvar.wait(&self.mutex);
}
assert!(*self.reader_count.get() != u32::max_value());
*self.reader_count.get() += 1;
self.mutex.unlock();
}
#[inline]
pub unsafe fn try_read(&self) -> bool {
if !self.mutex.try_lock() {
return false
}
while *self.writer_active.get() {
self.cvar.wait(&self.mutex);
}
assert!(*self.reader_count.get() != u32::max_value());
*self.reader_count.get() += 1;
self.mutex.unlock();
true
}
#[inline]
pub unsafe fn write(&self) {
self.mutex.lock();
while *self.writer_active.get() || *self.reader_count.get() > 0 {
self.cvar.wait(&self.mutex);
}
*self.writer_active.get() = true;
self.mutex.unlock();
}
#[inline]
pub unsafe fn try_write(&self) -> bool {
if !self.mutex.try_lock() {
return false;
}
while *self.writer_active.get() || *self.reader_count.get() > 0 {
self.cvar.wait(&self.mutex);
}
*self.writer_active.get() = true;
self.mutex.unlock();
true
}
#[inline]
pub unsafe fn read_unlock(&self) {
self.mutex.lock();
*self.reader_count.get() -= 1;
if *self.reader_count.get() == 0 {
self.cvar.notify_one()
}
self.mutex.unlock();
}
#[inline]
pub unsafe fn write_unlock(&self) {
self.mutex.lock();
*self.writer_active.get() = false;
self.cvar.notify_all();
self.mutex.unlock();
}
#[inline]
pub unsafe fn destroy(&self) {
self.mutex.destroy();
self.cvar.destroy();
*self.reader_count.get() = 0;
*self.writer_active.get() = false;
}
}

220
ctr-std/src/sys/horizon/stack_overflow.rs

@ -0,0 +1,220 @@
// Copyright 2014-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.
#![cfg_attr(test, allow(dead_code))]
use libc;
use self::imp::{make_handler, drop_handler};
pub use self::imp::cleanup;
pub use self::imp::init;
pub struct Handler {
_data: *mut libc::c_void
}
impl Handler {
pub unsafe fn new() -> Handler {
make_handler()
}
}
impl Drop for Handler {
fn drop(&mut self) {
unsafe {
drop_handler(self);
}
}
}
#[cfg(any(target_os = "linux",
target_os = "macos",
target_os = "bitrig",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "solaris",
all(target_os = "netbsd", not(target_vendor = "rumprun")),
target_os = "openbsd"))]
mod imp {
use super::Handler;
use mem;
use ptr;
use libc::{sigaltstack, SIGSTKSZ, SS_DISABLE};
use libc::{sigaction, SIGBUS, SIG_DFL,
SA_SIGINFO, SA_ONSTACK, sighandler_t};
use libc;
use libc::{mmap, munmap};
use libc::{SIGSEGV, PROT_READ, PROT_WRITE, MAP_PRIVATE, MAP_ANON};
use libc::MAP_FAILED;
use sys_common::thread_info;
#[cfg(any(target_os = "linux", target_os = "android"))]
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
#[repr(C)]
struct siginfo_t {
a: [libc::c_int; 3], // si_signo, si_errno, si_code
si_addr: *mut libc::c_void,
}
(*(info as *const siginfo_t)).si_addr as usize
}
#[cfg(not(any(target_os = "linux", target_os = "android")))]
unsafe fn siginfo_si_addr(info: *mut libc::siginfo_t) -> usize {
(*info).si_addr as usize
}
// Signal handler for the SIGSEGV and SIGBUS handlers. We've got guard pages
// (unmapped pages) at the end of every thread's stack, so if a thread ends
// up running into the guard page it'll trigger this handler. We want to
// detect these cases and print out a helpful error saying that the stack
// has overflowed. All other signals, however, should go back to what they
// were originally supposed to do.
//
// This handler currently exists purely to print an informative message
// whenever a thread overflows its stack. We then abort to exit and
// indicate a crash, but to avoid a misleading SIGSEGV that might lead
// users to believe that unsafe code has accessed an invalid pointer; the
// SIGSEGV encountered when overflowing the stack is expected and
// well-defined.
//
// If this is not a stack overflow, the handler un-registers itself and
// then returns (to allow the original signal to be delivered again).
// Returning from this kind of signal handler is technically not defined
// to work when reading the POSIX spec strictly, but in practice it turns
// out many large systems and all implementations allow returning from a
// signal handler to work. For a more detailed explanation see the
// comments on #26458.
unsafe extern fn signal_handler(signum: libc::c_int,
info: *mut libc::siginfo_t,
_data: *mut libc::c_void) {
use sys_common::util::report_overflow;
let guard = thread_info::stack_guard().unwrap_or(0..0);
let addr = siginfo_si_addr(info);
// If the faulting address is within the guard page, then we print a
// message saying so and abort.
if guard.start <= addr && addr < guard.end {
report_overflow();
rtabort!("stack overflow");
} else {
// Unregister ourselves by reverting back to the default behavior.
let mut action: sigaction = mem::zeroed();
action.sa_sigaction = SIG_DFL;
sigaction(signum, &action, ptr::null_mut());
// See comment above for why this function returns.
}
}
static mut MAIN_ALTSTACK: *mut libc::c_void = ptr::null_mut();
pub unsafe fn init() {
let mut action: sigaction = mem::zeroed();
action.sa_flags = SA_SIGINFO | SA_ONSTACK;
action.sa_sigaction = signal_handler as sighandler_t;
sigaction(SIGSEGV, &action, ptr::null_mut());
sigaction(SIGBUS, &action, ptr::null_mut());
let handler = make_handler();
MAIN_ALTSTACK = handler._data;
mem::forget(handler);
}
pub unsafe fn cleanup() {
Handler { _data: MAIN_ALTSTACK };
}
unsafe fn get_stackp() -> *mut libc::c_void {
let stackp = mmap(ptr::null_mut(),
SIGSTKSZ,
PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANON,
-1,
0);
if stackp == MAP_FAILED {
panic!("failed to allocate an alternative stack");
}
stackp
}
#[cfg(any(target_os = "linux",
target_os = "macos",
target_os = "bitrig",
target_os = "netbsd",
target_os = "openbsd",
target_os = "solaris"))]
unsafe fn get_stack() -> libc::stack_t {
libc::stack_t { ss_sp: get_stackp(), ss_flags: 0, ss_size: SIGSTKSZ }
}
#[cfg(any(target_os = "freebsd",
target_os = "dragonfly"))]
unsafe fn get_stack() -> libc::stack_t {
libc::stack_t { ss_sp: get_stackp() as *mut i8, ss_flags: 0, ss_size: SIGSTKSZ }
}
pub unsafe fn make_handler() -> Handler {
let mut stack = mem::zeroed();
sigaltstack(ptr::null(), &mut stack);
// Configure alternate signal stack, if one is not already set.
if stack.ss_flags & SS_DISABLE != 0 {
stack = get_stack();
sigaltstack(&stack, ptr::null_mut());
Handler { _data: stack.ss_sp as *mut libc::c_void }
} else {
Handler { _data: ptr::null_mut() }
}
}
pub unsafe fn drop_handler(handler: &mut Handler) {
if !handler._data.is_null() {
let stack = libc::stack_t {
ss_sp: ptr::null_mut(),
ss_flags: SS_DISABLE,
// Workaround for bug in macOS implementation of sigaltstack
// UNIX2003 which returns ENOMEM when disabling a stack while
// passing ss_size smaller than MINSIGSTKSZ. According to POSIX
// both ss_sp and ss_size should be ignored in this case.
ss_size: SIGSTKSZ,
};
sigaltstack(&stack, ptr::null_mut());
munmap(handler._data, SIGSTKSZ);
}
}
}
#[cfg(not(any(target_os = "linux",
target_os = "macos",
target_os = "bitrig",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "solaris",
all(target_os = "netbsd", not(target_vendor = "rumprun")),
target_os = "openbsd")))]
mod imp {
use ptr;
pub unsafe fn init() {
}
pub unsafe fn cleanup() {
}
pub unsafe fn make_handler() -> super::Handler {
super::Handler { _data: ptr::null_mut() }
}
pub unsafe fn drop_handler(_handler: &mut super::Handler) {
}
}

81
ctr-std/src/sys/horizon/stdio.rs

@ -0,0 +1,81 @@
// 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
}
}
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 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;
pub fn stderr_prints_nothing() -> bool {
false
}

106
ctr-std/src/sys/horizon/thread.rs

@ -0,0 +1,106 @@
// 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 alloc_crate::boxed::FnBox;
use libc;
use cmp;
use ffi::CStr;
use io;
use mem;
use ptr;
use sys_common::thread::start_thread;
use time::Duration;
use libctru::Thread as ThreadHandle;
pub struct Thread {
handle: ThreadHandle,
}
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, DEFAULT_MIN_STACK_SIZE);
let mut priority = 0;
::libctru::svcGetThreadPriority(&mut priority, 0xFFFF8000);
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))
} else {
mem::forget(p); // ownership passed to the new thread
Ok(Thread { handle: handle })
};
extern "C" fn thread_func(start: *mut libc::c_void) {
unsafe { start_thread(start as *mut u8) }
}
}
pub fn yield_now() {
unsafe {
::libctru::svcSleepThread(0)
}
}
pub fn set_name(_name: &CStr) {
// threads aren't named in libctru
}
pub fn sleep(dur: Duration) {
unsafe {
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 = ::libctru::threadJoin(self.handle, u64::max_value());
::libctru::threadFree(self.handle);
mem::forget(self);
debug_assert_eq!(ret, 0);
}
}
#[allow(dead_code)]
pub fn id(&self) -> ThreadHandle {
self.handle
}
#[allow(dead_code)]
pub fn into_id(self) -> ThreadHandle {
let handle = self.handle;
mem::forget(self);
handle
}
}
impl Drop for Thread {
fn drop(&mut self) {
unsafe { ::libctru::threadDetach(self.handle) }
}
}
pub mod guard {
pub unsafe fn current() -> Option<usize> { None }
pub unsafe fn init() -> Option<usize> { None }
}

71
ctr-std/src/sys/horizon/thread_local.rs

@ -0,0 +1,71 @@
// 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.
#![allow(dead_code)] // not used on all platforms
use collections::BTreeMap;
use ptr;
use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
pub type Key = usize;
type Dtor = unsafe extern fn(*mut u8);
static NEXT_KEY: AtomicUsize = ATOMIC_USIZE_INIT;
static mut KEYS: *mut BTreeMap<Key, Option<Dtor>> = ptr::null_mut();
#[thread_local]
static mut LOCALS: *mut BTreeMap<Key, *mut u8> = ptr::null_mut();
unsafe fn keys() -> &'static mut BTreeMap<Key, Option<Dtor>> {
if KEYS == ptr::null_mut() {
KEYS = Box::into_raw(Box::new(BTreeMap::new()));
}
&mut *KEYS
}
unsafe fn locals() -> &'static mut BTreeMap<Key, *mut u8> {
if LOCALS == ptr::null_mut() {
LOCALS = Box::into_raw(Box::new(BTreeMap::new()));
}
&mut *LOCALS
}
#[inline]
pub unsafe fn create(dtor: Option<Dtor>) -> Key {
let key = NEXT_KEY.fetch_add(1, Ordering::SeqCst);
keys().insert(key, dtor);
key
}
#[inline]
pub unsafe fn get(key: Key) -> *mut u8 {
if let Some(&entry) = locals().get(&key) {
entry
} else {
ptr::null_mut()
}
}
#[inline]
pub unsafe fn set(key: Key, value: *mut u8) {
locals().insert(key, value);
}
#[inline]
pub unsafe fn destroy(key: Key) {
keys().remove(&key);
}
#[inline]
pub fn requires_synchronized_create() -> bool {
false
}

285
ctr-std/src/sys/horizon/time.rs

@ -0,0 +1,285 @@
// 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 cmp::Ordering;
use libc;
use time::Duration;
use core::hash::{Hash, Hasher};
pub use self::inner::{Instant, SystemTime, UNIX_EPOCH};
const NSEC_PER_SEC: u64 = 1_000_000_000;
#[derive(Copy, Clone)]
struct Timespec {
t: libc::timespec,
}
impl Timespec {
fn sub_timespec(&self, other: &Timespec) -> Result<Duration, Duration> {
if self >= other {
Ok(if self.t.tv_nsec >= other.t.tv_nsec {
Duration::new((self.t.tv_sec - other.t.tv_sec) as u64,
(self.t.tv_nsec - other.t.tv_nsec) as u32)
} else {
Duration::new((self.t.tv_sec - 1 - other.t.tv_sec) as u64,
self.t.tv_nsec as u32 + (NSEC_PER_SEC as u32) -
other.t.tv_nsec as u32)
})
} else {
match other.sub_timespec(self) {
Ok(d) => Err(d),
Err(d) => Ok(d),
}
}
}
fn add_duration(&self, other: &Duration) -> Timespec {
let secs = (self.t.tv_sec as i64).checked_add(other.as_secs() as i64);
let mut secs = secs.expect("overflow when adding duration to time");
// Nano calculations can't overflow because nanos are <1B which fit
// in a u32.
let mut nsec = other.subsec_nanos() + self.t.tv_nsec as u32;
if nsec >= NSEC_PER_SEC as u32 {
nsec -= NSEC_PER_SEC as u32;
secs = secs.checked_add(1).expect("overflow when adding \
duration to time");
}
Timespec {
t: libc::timespec {
tv_sec: secs as libc::time_t,
tv_nsec: nsec as libc::c_long,
},
}
}
fn sub_duration(&self, other: &Duration) -> Timespec {
let secs = (self.t.tv_sec as i64).checked_sub(other.as_secs() as i64);
let mut secs = secs.expect("overflow when subtracting duration \
from time");
// Similar to above, nanos can't overflow.
let mut nsec = self.t.tv_nsec as i32 - other.subsec_nanos() as i32;
if nsec < 0 {
nsec += NSEC_PER_SEC as i32;
secs = secs.checked_sub(1).expect("overflow when subtracting \
duration from time");
}
Timespec {
t: libc::timespec {
tv_sec: secs as libc::time_t,
tv_nsec: nsec as libc::c_long,
},
}
}
}
impl PartialEq for Timespec {
fn eq(&self, other: &Timespec) -> bool {
self.t.tv_sec == other.t.tv_sec && self.t.tv_nsec == other.t.tv_nsec
}
}
impl Eq for Timespec {}
impl PartialOrd for Timespec {
fn partial_cmp(&self, other: &Timespec) -> Option<Ordering> {
Some(self.cmp(other))
}
}
impl Ord for Timespec {
fn cmp(&self, other: &Timespec) -> Ordering {
let me = (self.t.tv_sec, self.t.tv_nsec);
let other = (other.t.tv_sec, other.t.tv_nsec);
me.cmp(&other)
}
}
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;
use sync::Once;
use sys::cvt;
use sys_common::mul_div_u64;
use time::Duration;
use super::NSEC_PER_SEC;
use super::Timespec;
use libctru;
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)]
pub struct Instant {
t: u64
}
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SystemTime {
t: Timespec,
}
pub const UNIX_EPOCH: SystemTime = SystemTime {
t: Timespec {
t: libc::timespec {
tv_sec: 0,
tv_nsec: 0,
},
},
};
impl Instant {
pub fn now() -> Instant {
Instant { t: ctr_absolute_time() }
}
pub fn sub_instant(&self, other: &Instant) -> Duration {
let info = info();
let diff = self.t.checked_sub(other.t)
.expect("second instant is later than self");
let nanos = mul_div_u64(diff, info.numer as u64, info.denom as u64);
Duration::new(nanos / NSEC_PER_SEC, (nanos % NSEC_PER_SEC) as u32)
}
pub fn add_duration(&self, other: &Duration) -> Instant {
Instant {
t: self.t.checked_add(dur2intervals(other))
.expect("overflow when adding duration to instant"),
}
}
pub fn sub_duration(&self, other: &Duration) -> Instant {
Instant {
t: self.t.checked_sub(dur2intervals(other))
.expect("overflow when adding duration to instant"),
}
}
}
// The initial system tick after which all Instants occur
static mut TICK: u64 = 0;
// A source of monotonic time based on ticks of the 3DS CPU. Returns the
// number of system ticks elapsed since an arbitrary point in the past
fn ctr_absolute_time() -> u64 {
let first_tick = get_first_tick();
let current_tick = get_system_tick();
current_tick - first_tick
}
// The first time this function is called, it generates and returns the
// initial system tick used to create Instants
//
// subsequent calls to this function return the previously generated
// tick value
fn get_first_tick() -> u64 {
static ONCE: Once = Once::new();
unsafe {
ONCE.call_once(|| {
TICK = get_system_tick();
});
TICK
}
}
// Gets the current system tick
#[inline]
fn get_system_tick() -> u64 {
unsafe { libctru::svcGetSystemTick() }
}
// A struct representing the clock speed of the 3DS
struct CtrClockInfo {
numer: u32,
denom: u32,
}
// Initializes the CtrClockInfo struct
//
// Note that svcGetSystemTick always runs at 268MHz (268,111,856Hz), even
// on a New 3DS running in 804MHz mode
//
// See https://www.3dbrew.org/wiki/Hardware#Common_hardware
fn info() -> &'static CtrClockInfo {
static INFO: CtrClockInfo = CtrClockInfo {
numer: 1_000_000_000,
denom: 268_111_856,
};
&INFO
}
fn dur2intervals(dur: &Duration) -> u64 {
let info = info();
let nanos = dur.as_secs().checked_mul(NSEC_PER_SEC).and_then(|nanos| {
nanos.checked_add(dur.subsec_nanos() as u64)
}).expect("overflow converting duration to nanoseconds");
mul_div_u64(nanos, info.denom as u64, info.numer as u64)
}
impl SystemTime {
pub fn now() -> SystemTime {
use ptr;
let mut s = libc::timeval {
tv_sec: 0,
tv_usec: 0,
};
cvt(unsafe {
libc::gettimeofday(&mut s, ptr::null_mut())
}).unwrap();
return SystemTime::from(s)
}
pub fn sub_time(&self, other: &SystemTime)
-> Result<Duration, Duration> {
self.t.sub_timespec(&other.t)
}
pub fn add_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.add_duration(other) }
}
pub fn sub_duration(&self, other: &Duration) -> SystemTime {
SystemTime { t: self.t.sub_duration(other) }
}
}
impl From<libc::timeval> for SystemTime {
fn from(t: libc::timeval) -> SystemTime {
SystemTime::from(libc::timespec {
tv_sec: t.tv_sec,
tv_nsec: (t.tv_usec * 1000) as libc::c_long,
})
}
}
impl From<libc::timespec> for SystemTime {
fn from(t: libc::timespec) -> SystemTime {
SystemTime { t: Timespec { t: t } }
}
}
impl fmt::Debug for SystemTime {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("SystemTime")
.field("tv_sec", &self.t.t.tv_sec)
.field("tv_nsec", &self.t.t.tv_nsec)
.finish()
}
}
}

79
ctr-std/src/sys/horizon/weak.rs

@ -0,0 +1,79 @@
// 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.
//! Support for "weak linkage" to symbols on Unix
//!
//! Some I/O operations we do in libstd require newer versions of OSes but we
//! need to maintain binary compatibility with older releases for now. In order
//! to use the new functionality when available we use this module for
//! detection.
//!
//! One option to use here is weak linkage, but that is unfortunately only
//! really workable on Linux. Hence, use dlsym to get the symbol value at
//! runtime. This is also done for compatibility with older versions of glibc,
//! and to avoid creating dependencies on GLIBC_PRIVATE symbols. It assumes that
//! we've been dynamically linked to the library the symbol comes from, but that
//! is currently always the case for things like libpthread/libc.
//!
//! A long time ago this used weak linkage for the __pthread_get_minstack
//! symbol, but that caused Debian to detect an unnecessarily strict versioned
//! dependency on libc6 (#23628).
use libc;
use ffi::CString;
use marker;
use mem;
use sync::atomic::{AtomicUsize, Ordering};
macro_rules! weak {
(fn $name:ident($($t:ty),*) -> $ret:ty) => (
static $name: ::sys::weak::Weak<unsafe extern fn($($t),*) -> $ret> =
::sys::weak::Weak::new(stringify!($name));
)
}
pub struct Weak<F> {
name: &'static str,
addr: AtomicUsize,
_marker: marker::PhantomData<F>,
}
impl<F> Weak<F> {
pub const fn new(name: &'static str) -> Weak<F> {
Weak {
name,
addr: AtomicUsize::new(1),
_marker: marker::PhantomData,
}
}
pub fn get(&self) -> Option<&F> {
assert_eq!(mem::size_of::<F>(), mem::size_of::<usize>());
unsafe {
if self.addr.load(Ordering::SeqCst) == 1 {
self.addr.store(fetch(self.name), Ordering::SeqCst);
}
if self.addr.load(Ordering::SeqCst) == 0 {
None
} else {
mem::transmute::<&AtomicUsize, Option<&F>>(&self.addr)
}
}
}
}
unsafe fn fetch(name: &str) -> usize {
let name = match CString::new(name) {
Ok(cstr) => cstr,
Err(..) => return 0,
};
libc::dlsym(0 as _, name.as_ptr() as *const u8) as usize
}

17
ctr-std/src/sys/mod.rs

@ -33,9 +33,24 @@
#![allow(missing_debug_implementations)] #![allow(missing_debug_implementations)]
cfg_if! { cfg_if! {
if #[cfg(unix)] { if #[cfg(target_os = "horizon")] {
mod horizon;
pub use self::horizon::*;
} else if #[cfg(unix)] {
mod unix; mod unix;
pub use self::unix::*; pub use self::unix::*;
} else if #[cfg(windows)] {
mod windows;
pub use self::windows::*;
} else if #[cfg(target_os = "cloudabi")] {
mod cloudabi;
pub use self::cloudabi::*;
} else if #[cfg(target_os = "redox")] {
mod redox;
pub use self::redox::*;
} else if #[cfg(target_arch = "wasm32")] {
mod wasm;
pub use self::wasm::*;
} else { } else {
compile_error!("libstd doesn't compile for this platform yet"); compile_error!("libstd doesn't compile for this platform yet");
} }

111
ctr-std/src/sys/redox/args.rs

@ -0,0 +1,111 @@
// 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.
//! Global initialization and retrieval of command line arguments.
//!
//! On some platforms these are stored during runtime startup,
//! and on some they are retrieved from the system on demand.
#![allow(dead_code)] // runtime init functions not used during testing
use ffi::OsString;
use marker::PhantomData;
use vec;
/// One-time global initialization.
pub unsafe fn init(argc: isize, argv: *const *const u8) { imp::init(argc, argv) }
/// One-time global cleanup.
pub unsafe fn cleanup() { imp::cleanup() }
/// Returns the command line arguments
pub fn args() -> Args {
imp::args()
}
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() }
}
mod imp {
use os::unix::prelude::*;
use mem;
use ffi::{CStr, OsString};
use marker::PhantomData;
use libc;
use super::Args;
use sys_common::mutex::Mutex;
static mut GLOBAL_ARGS_PTR: usize = 0;
static LOCK: Mutex = Mutex::new();
pub unsafe fn init(argc: isize, argv: *const *const u8) {
let args = (0..argc).map(|i| {
CStr::from_ptr(*argv.offset(i) as *const libc::c_char).to_bytes().to_vec()
}).collect();
LOCK.lock();
let ptr = get_global_ptr();
assert!((*ptr).is_none());
(*ptr) = Some(box args);
LOCK.unlock();
}
pub unsafe fn cleanup() {
LOCK.lock();
*get_global_ptr() = None;
LOCK.unlock();
}
pub fn args() -> Args {
let bytes = clone().unwrap_or(Vec::new());
let v: Vec<OsString> = bytes.into_iter().map(|v| {
OsStringExt::from_vec(v)
}).collect();
Args { iter: v.into_iter(), _dont_send_or_sync_me: PhantomData }
}
fn clone() -> Option<Vec<Vec<u8>>> {
unsafe {
LOCK.lock();
let ptr = get_global_ptr();
let ret = (*ptr).as_ref().map(|s| (**s).clone());
LOCK.unlock();
return ret
}
}
fn get_global_ptr() -> *mut Option<Box<Vec<Vec<u8>>>> {
unsafe { mem::transmute(&GLOBAL_ARGS_PTR) }
}
}

42
ctr-std/src/sys/redox/backtrace/mod.rs

@ -0,0 +1,42 @@
// 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.
/// See sys/unix/backtrace/mod.rs for an explanation of the method used here.
pub use self::tracing::unwind_backtrace;
pub use self::printing::{foreach_symbol_fileline, resolve_symname};
// tracing impls:
mod tracing;
// symbol resolvers:
mod printing;
pub mod gnu {
use io;
use fs;
use libc::c_char;
use vec::Vec;
use ffi::OsStr;
use os::unix::ffi::OsStrExt;
use io::Read;
pub fn get_executable_filename() -> io::Result<(Vec<c_char>, fs::File)> {
let mut exefile = fs::File::open("sys:exe")?;
let mut exename = Vec::new();
exefile.read_to_end(&mut exename)?;
if exename.last() == Some(&b'\n') {
exename.pop();
}
let file = fs::File::open(OsStr::from_bytes(&exename))?;
Ok((exename.into_iter().map(|c| c as c_char).collect(), file))
}
}
pub struct BacktraceContext;

11
ctr-std/src/sys/redox/backtrace/printing.rs

@ -0,0 +1,11 @@
// Copyright 2014-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.
pub use sys_common::gnu::libbacktrace::{foreach_symbol_fileline, resolve_symname};

107
ctr-std/src/sys/redox/backtrace/tracing.rs

@ -0,0 +1,107 @@
// Copyright 2014-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 error::Error;
use io;
use libc;
use sys::backtrace::BacktraceContext;
use sys_common::backtrace::Frame;
use unwind as uw;
struct Context<'a> {
idx: usize,
frames: &'a mut [Frame],
}
#[derive(Debug)]
struct UnwindError(uw::_Unwind_Reason_Code);
impl Error for UnwindError {
fn description(&self) -> &'static str {
"unexpected return value while unwinding"
}
}
impl ::fmt::Display for UnwindError {
fn fmt(&self, f: &mut ::fmt::Formatter) -> ::fmt::Result {
write!(f, "{}: {:?}", self.description(), self.0)
}
}
#[inline(never)] // if we know this is a function call, we can skip it when
// tracing
pub fn unwind_backtrace(frames: &mut [Frame])
-> io::Result<(usize, BacktraceContext)>
{
let mut cx = Context {
idx: 0,
frames: frames,
};
let result_unwind = unsafe {
uw::_Unwind_Backtrace(trace_fn,
&mut cx as *mut Context
as *mut libc::c_void)
};
// See libunwind:src/unwind/Backtrace.c for the return values.
// No, there is no doc.
match result_unwind {
// These return codes seem to be benign and need to be ignored for backtraces
// to show up properly on all tested platforms.
uw::_URC_END_OF_STACK | uw::_URC_FATAL_PHASE1_ERROR | uw::_URC_FAILURE => {
Ok((cx.idx, BacktraceContext))
}
_ => {
Err(io::Error::new(io::ErrorKind::Other,
UnwindError(result_unwind)))
}
}
}
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) };
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 {
// this is a non-signaling frame, so `ip` refers to the address
// after the calling instruction. account for that.
ip = (ip as usize - 1) as *mut _;
}
// dladdr() on osx gets whiny when we use FindEnclosingFunction, and
// it appears to work fine without it, so we only use
// FindEnclosingFunction on non-osx platforms. In doing so, we get a
// slightly more accurate stack trace in the process.
//
// This is often because panic involves the last instruction of a
// function being "call std::rt::begin_unwind", with no ret
// instructions after it. This means that the return instruction
// pointer points *outside* of the calling function, and by
// unwinding it we go back to the original function.
let symaddr = if cfg!(target_os = "macos") || cfg!(target_os = "ios") {
ip
} else {
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;
}
uw::_URC_NO_REASON
}

43
ctr-std/src/sys/redox/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;
}

121
ctr-std/src/sys/redox/condvar.rs

@ -0,0 +1,121 @@
// 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.
use cell::UnsafeCell;
use intrinsics::{atomic_cxchg, atomic_load, atomic_xadd, atomic_xchg};
use ptr;
use time::Duration;
use sys::mutex::{mutex_unlock, Mutex};
use sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE};
pub struct Condvar {
lock: UnsafeCell<*mut i32>,
seq: UnsafeCell<i32>
}
impl Condvar {
pub const fn new() -> Condvar {
Condvar {
lock: UnsafeCell::new(ptr::null_mut()),
seq: UnsafeCell::new(0)
}
}
#[inline]
pub unsafe fn init(&self) {
*self.lock.get() = ptr::null_mut();
*self.seq.get() = 0;
}
#[inline]
pub fn notify_one(&self) {
unsafe {
let seq = self.seq.get();
atomic_xadd(seq, 1);
let _ = futex(seq, FUTEX_WAKE, 1, 0, ptr::null_mut());
}
}
#[inline]
pub fn notify_all(&self) {
unsafe {
let lock = self.lock.get();
let seq = self.seq.get();
if *lock == ptr::null_mut() {
return;
}
atomic_xadd(seq, 1);
let _ = futex(seq, FUTEX_REQUEUE, 1, ::usize::MAX, *lock);
}
}
#[inline]
unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool {
let lock = self.lock.get();
let seq = self.seq.get();
if *lock != mutex.lock.get() {
if *lock != ptr::null_mut() {
panic!("Condvar used with more than one Mutex");
}
atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize);
}
mutex_unlock(*lock);
let seq_before = atomic_load(seq);
let _ = futex(seq, FUTEX_WAIT, seq_before, timeout_ptr as usize, ptr::null_mut());
let seq_after = atomic_load(seq);
while atomic_xchg(*lock, 2) != 0 {
let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut());
}
seq_before != seq_after
}
#[inline]
pub fn wait(&self, mutex: &Mutex) {
unsafe {
assert!(self.wait_inner(mutex, ptr::null()));
}
}
#[inline]
pub fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool {
unsafe {
let timeout = TimeSpec {
tv_sec: dur.as_secs() as i64,
tv_nsec: dur.subsec_nanos() as i32
};
self.wait_inner(mutex, &timeout as *const TimeSpec)
}
}
#[inline]
pub unsafe fn destroy(&self) {
*self.lock.get() = ptr::null_mut();
*self.seq.get() = 0;
}
}
unsafe impl Send for Condvar {}
unsafe impl Sync for Condvar {}

19
ctr-std/src/sys/redox/env.rs

@ -0,0 +1,19 @@
// 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.
pub mod os {
pub const FAMILY: &'static str = "redox";
pub const OS: &'static str = "redox";
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 = "";
}

65
ctr-std/src/sys/redox/ext/ffi.rs

@ -0,0 +1,65 @@
// 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.
//! Redox-specific extension to the primitives in the `std::ffi` module.
#![stable(feature = "rust1", since = "1.0.0")]
use ffi::{OsStr, OsString};
use mem;
use sys::os_str::Buf;
use sys_common::{FromInner, IntoInner, AsInner};
/// Redox-specific extensions to [`OsString`].
///
/// [`OsString`]: ../../../../std/ffi/struct.OsString.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStringExt {
/// Creates an `OsString` from a byte vector.
#[stable(feature = "rust1", since = "1.0.0")]
fn from_vec(vec: Vec<u8>) -> Self;
/// Yields the underlying byte vector of this `OsString`.
#[stable(feature = "rust1", since = "1.0.0")]
fn into_vec(self) -> Vec<u8>;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl OsStringExt for OsString {
fn from_vec(vec: Vec<u8>) -> OsString {
FromInner::from_inner(Buf { inner: vec })
}
fn into_vec(self) -> Vec<u8> {
self.into_inner().inner
}
}
/// Redox-specific extensions to [`OsStr`].
///
/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait OsStrExt {
#[stable(feature = "rust1", since = "1.0.0")]
fn from_bytes(slice: &[u8]) -> &Self;
/// Gets the underlying byte view of the `OsStr` slice.
#[stable(feature = "rust1", since = "1.0.0")]
fn as_bytes(&self) -> &[u8];
}
#[stable(feature = "rust1", since = "1.0.0")]
impl OsStrExt for OsStr {
fn from_bytes(slice: &[u8]) -> &OsStr {
unsafe { mem::transmute(slice) }
}
fn as_bytes(&self) -> &[u8] {
&self.as_inner().inner
}
}

349
ctr-std/src/sys/redox/ext/fs.rs

@ -0,0 +1,349 @@
// 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.
//! Redox-specific extensions to primitives in the `std::fs` module.
#![stable(feature = "rust1", since = "1.0.0")]
use fs::{self, Permissions, OpenOptions};
use io;
use path::Path;
use sys;
use sys_common::{FromInner, AsInner, AsInnerMut};
/// Redox-specific extensions to [`fs::Permissions`].
///
/// [`fs::Permissions`]: ../../../../std/fs/struct.Permissions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait PermissionsExt {
/// Returns the underlying raw `mode_t` bits that are the standard Redox
/// permissions for this file.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::os::redox::fs::PermissionsExt;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::create("foo.txt")?;
/// let metadata = f.metadata()?;
/// let permissions = metadata.permissions();
///
/// println!("permissions: {}", permissions.mode());
/// Ok(())
/// }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&self) -> u32;
/// Sets the underlying raw bits for this set of permissions.
///
/// # Examples
///
/// ```no_run
/// use std::fs::File;
/// use std::os::redox::fs::PermissionsExt;
///
/// fn main() -> std::io::Result<()> {
/// let f = File::create("foo.txt")?;
/// let metadata = f.metadata()?;
/// let mut permissions = metadata.permissions();
///
/// permissions.set_mode(0o644); // Read/write for owner and read for others.
/// assert_eq!(permissions.mode(), 0o644);
/// Ok(())
/// }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn set_mode(&mut self, mode: u32);
/// Creates a new instance of `Permissions` from the given set of Redox
/// permission bits.
///
/// # Examples
///
/// ```
/// use std::fs::Permissions;
/// use std::os::redox::fs::PermissionsExt;
///
/// // Read/write for owner and read for others.
/// let permissions = Permissions::from_mode(0o644);
/// assert_eq!(permissions.mode(), 0o644);
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn from_mode(mode: u32) -> Self;
}
#[stable(feature = "fs_ext", since = "1.1.0")]
impl PermissionsExt for Permissions {
fn mode(&self) -> u32 {
self.as_inner().mode()
}
fn set_mode(&mut self, mode: u32) {
*self = Permissions::from_inner(FromInner::from_inner(mode));
}
fn from_mode(mode: u32) -> Permissions {
Permissions::from_inner(FromInner::from_inner(mode))
}
}
/// Redox-specific extensions to [`fs::OpenOptions`].
///
/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html
#[stable(feature = "fs_ext", since = "1.1.0")]
pub trait OpenOptionsExt {
/// Sets the mode bits that a new file will be created with.
///
/// If a new file is created as part of a `File::open_opts` call then this
/// specified `mode` will be used as the permission bits for the new file.
/// If no `mode` is set, the default of `0o666` will be used.
/// The operating system masks out bits with the systems `umask`, to produce
/// the final permissions.
///
/// # Examples
///
/// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::fs::OpenOptions;
/// use std::os::redox::fs::OpenOptionsExt;
///
/// # fn main() {
/// let mut options = OpenOptions::new();
/// options.mode(0o644); // Give read/write for owner and read for others.
/// let file = options.open("foo.txt");
/// # }
/// ```
#[stable(feature = "fs_ext", since = "1.1.0")]
fn mode(&mut self, mode: u32) -> &mut Self;
/// Pass custom flags to the `flags` argument of `open`.
///
/// The bits that define the access mode are masked out with `O_ACCMODE`, to
/// ensure they do not interfere with the access mode set by Rusts options.
///
/// Custom flags can only set flags, not remove flags set by Rusts options.
/// This options overwrites any previously set custom flags.
///
/// # Examples
///
/// ```no_run
/// # #![feature(libc)]
/// extern crate libc;
/// use std::fs::OpenOptions;
/// use std::os::redox::fs::OpenOptionsExt;
///
/// # fn main() {
/// let mut options = OpenOptions::new();
/// options.write(true);
/// if cfg!(target_os = "redox") {
/// options.custom_flags(libc::O_NOFOLLOW);
/// }
/// let file = options.open("foo.txt");
/// # }
/// ```
#[stable(feature = "open_options_ext", since = "1.10.0")]
fn custom_flags(&mut self, flags: i32) -> &mut Self;
}
#[stable(feature = "fs_ext", since = "1.1.0")]
impl OpenOptionsExt for OpenOptions {
fn mode(&mut self, mode: u32) -> &mut OpenOptions {
self.as_inner_mut().mode(mode); self
}
fn custom_flags(&mut self, flags: i32) -> &mut OpenOptions {
self.as_inner_mut().custom_flags(flags); self
}
}
/// Redox-specific extensions to [`fs::Metadata`].
///
/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html
#[stable(feature = "metadata_ext", since = "1.1.0")]
pub trait MetadataExt {
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn dev(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ino(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mode(&self) -> u32;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn nlink(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn uid(&self) -> u32;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn gid(&self) -> u32;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn size(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn atime(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn atime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mtime(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn mtime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ctime(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn ctime_nsec(&self) -> i64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn blksize(&self) -> u64;
#[stable(feature = "metadata_ext", since = "1.1.0")]
fn blocks(&self) -> u64;
}
// Hm, why are there casts here to the returned type, shouldn't the types always
// be the same? Right you are! Turns out, however, on android at least the types
// in the raw `stat` structure are not the same as the types being returned. Who
// knew!
//
// As a result to make sure this compiles for all platforms we do the manual
// casts and rely on manual lowering to `stat` if the raw type is desired.
#[stable(feature = "metadata_ext", since = "1.1.0")]
impl MetadataExt for fs::Metadata {
fn dev(&self) -> u64 {
self.as_inner().as_inner().st_dev as u64
}
fn ino(&self) -> u64 {
self.as_inner().as_inner().st_ino as u64
}
fn mode(&self) -> u32 {
self.as_inner().as_inner().st_mode as u32
}
fn nlink(&self) -> u64 {
self.as_inner().as_inner().st_nlink as u64
}
fn uid(&self) -> u32 {
self.as_inner().as_inner().st_uid as u32
}
fn gid(&self) -> u32 {
self.as_inner().as_inner().st_gid as u32
}
fn size(&self) -> u64 {
self.as_inner().as_inner().st_size as u64
}
fn atime(&self) -> i64 {
self.as_inner().as_inner().st_atime as i64
}
fn atime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_atime_nsec as i64
}
fn mtime(&self) -> i64 {
self.as_inner().as_inner().st_mtime as i64
}
fn mtime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_mtime_nsec as i64
}
fn ctime(&self) -> i64 {
self.as_inner().as_inner().st_ctime as i64
}
fn ctime_nsec(&self) -> i64 {
self.as_inner().as_inner().st_ctime_nsec as i64
}
fn blksize(&self) -> u64 {
self.as_inner().as_inner().st_blksize as u64
}
fn blocks(&self) -> u64 {
self.as_inner().as_inner().st_blocks as u64
}
}
/// Redox-specific extensions for [`FileType`].
///
/// Adds support for special Unix file types such as block/character devices,
/// pipes, and sockets.
///
/// [`FileType`]: ../../../../std/fs/struct.FileType.html
#[stable(feature = "file_type_ext", since = "1.5.0")]
pub trait FileTypeExt {
/// Returns whether this file type is a block device.
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_block_device(&self) -> bool;
/// Returns whether this file type is a char device.
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_char_device(&self) -> bool;
/// Returns whether this file type is a fifo.
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_fifo(&self) -> bool;
/// Returns whether this file type is a socket.
#[stable(feature = "file_type_ext", since = "1.5.0")]
fn is_socket(&self) -> bool;
}
#[stable(feature = "file_type_ext", since = "1.5.0")]
impl FileTypeExt for fs::FileType {
fn is_block_device(&self) -> bool { false /*FIXME: Implement block device mode*/ }
fn is_char_device(&self) -> bool { false /*FIXME: Implement char device mode*/ }
fn is_fifo(&self) -> bool { false /*FIXME: Implement fifo mode*/ }
fn is_socket(&self) -> bool { false /*FIXME: Implement socket mode*/ }
}
/// Creates a new symbolic link on the filesystem.
///
/// The `dst` path will be a symbolic link pointing to the `src` path.
///
/// # Note
///
/// On Windows, you must specify whether a symbolic link points to a file
/// or directory. Use `os::windows::fs::symlink_file` to create a
/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a
/// symbolic link to a directory. Additionally, the process must have
/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a
/// symbolic link.
///
/// # Examples
///
/// ```no_run
/// use std::os::redox::fs;
///
/// fn main() -> std::io::Result<()> {
/// fs::symlink("a.txt", "b.txt")?;
/// Ok(())
/// }
/// ```
#[stable(feature = "symlink", since = "1.1.0")]
pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()>
{
sys::fs::symlink(src.as_ref(), dst.as_ref())
}
/// Redox-specific extensions to [`fs::DirBuilder`].
///
/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html
#[stable(feature = "dir_builder", since = "1.6.0")]
pub trait DirBuilderExt {
/// Sets the mode to create new directories with. This option defaults to
/// 0o777.
///
/// # Examples
///
/// ```no_run
/// use std::fs::DirBuilder;
/// use std::os::redox::fs::DirBuilderExt;
///
/// let mut builder = DirBuilder::new();
/// builder.mode(0o755);
/// ```
#[stable(feature = "dir_builder", since = "1.6.0")]
fn mode(&mut self, mode: u32) -> &mut Self;
}
#[stable(feature = "dir_builder", since = "1.6.0")]
impl DirBuilderExt for fs::DirBuilder {
fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder {
self.as_inner_mut().set_mode(mode);
self
}
}

167
ctr-std/src/sys/redox/ext/io.rs

@ -0,0 +1,167 @@
// 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.
//! Unix-specific extensions to general I/O primitives
#![stable(feature = "rust1", since = "1.0.0")]
use fs;
use net;
use sys;
use io;
use sys_common::{self, AsInner, FromInner, IntoInner};
/// Raw file descriptors.
#[stable(feature = "rust1", since = "1.0.0")]
pub type RawFd = usize;
/// 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 instances 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 = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpStream {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::TcpListener {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "rust1", since = "1.0.0")]
impl AsRawFd for net::UdpSocket {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().as_inner().fd().raw()
}
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stdin {
fn as_raw_fd(&self) -> RawFd { 0 }
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stdout {
fn as_raw_fd(&self) -> RawFd { 1 }
}
#[stable(feature = "asraw_stdio", since = "1.21.0")]
impl AsRawFd for io::Stderr {
fn as_raw_fd(&self) -> RawFd { 2 }
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::TcpStream {
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpStream {
let file = sys::fs::File::from_inner(fd);
net::TcpStream::from_inner(sys_common::net::TcpStream::from_inner(file))
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::TcpListener {
unsafe fn from_raw_fd(fd: RawFd) -> net::TcpListener {
let file = sys::fs::File::from_inner(fd);
net::TcpListener::from_inner(sys_common::net::TcpListener::from_inner(file))
}
}
#[stable(feature = "from_raw_os", since = "1.1.0")]
impl FromRawFd for net::UdpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> net::UdpSocket {
let file = sys::fs::File::from_inner(fd);
net::UdpSocket::from_inner(sys_common::net::UdpSocket::from_inner(file))
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::TcpStream {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::TcpListener {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for net::UdpSocket {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_inner().into_fd().into_raw()
}
}

54
ctr-std/src/sys/redox/ext/mod.rs

@ -0,0 +1,54 @@
// 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.
//! Experimental extensions to `std` for Unix platforms.
//!
//! For now, this module is limited to extracting file descriptors,
//! but its functionality will grow over time.
//!
//! # Examples
//!
//! ```no_run
//! use std::fs::File;
//! use std::os::unix::prelude::*;
//!
//! fn main() {
//! let f = File::create("foo.txt").unwrap();
//! let fd = f.as_raw_fd();
//!
//! // use fd with native unix bindings
//! }
//! ```
#![stable(feature = "rust1", since = "1.0.0")]
#![doc(cfg(target_os = "redox"))]
pub mod ffi;
pub mod fs;
pub mod io;
pub mod process;
pub mod thread;
/// A prelude for conveniently writing platform-specific code.
///
/// Includes all extension traits, and some important type definitions.
#[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::{FileTypeExt, PermissionsExt, OpenOptionsExt, MetadataExt};
#[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};
}

187
ctr-std/src/sys/redox/ext/process.rs

@ -0,0 +1,187 @@
// 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.
//! Redox-specific extensions to primitives in the `std::process` module.
#![stable(feature = "rust1", since = "1.0.0")]
use io;
use os::unix::io::{FromRawFd, RawFd, AsRawFd, IntoRawFd};
use process;
use sys;
use sys_common::{AsInnerMut, AsInner, FromInner, IntoInner};
/// Redox-specific extensions to the [`process::Command`] builder,
///
/// [`process::Command`]: ../../../../std/process/struct.Command.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait CommandExt {
/// Sets the child process's user id. This translates to a
/// `setuid` call in the child process. Failure in the `setuid`
/// call will cause the spawn to fail.
#[stable(feature = "rust1", since = "1.0.0")]
fn uid(&mut self, id: u32) -> &mut process::Command;
/// Similar to `uid`, but sets the group id of the child process. This has
/// the same semantics as the `uid` field.
#[stable(feature = "rust1", since = "1.0.0")]
fn gid(&mut self, id: u32) -> &mut process::Command;
/// Schedules a closure to be run just before the `exec` function is
/// invoked.
///
/// The closure is allowed to return an I/O error whose OS error code will
/// be communicated back to the parent and returned as an error from when
/// the spawn was requested.
///
/// Multiple closures can be registered and they will be called in order of
/// their registration. If a closure returns `Err` then no further closures
/// will be called and the spawn operation will immediately return with a
/// failure.
///
/// # Notes
///
/// This closure will be run in the context of the child process after a
/// `fork`. This primarily means that any modifications made to memory on
/// behalf of this closure will **not** be visible to the parent process.
/// This is often a very constrained environment where normal operations
/// like `malloc` or acquiring a mutex are not guaranteed to work (due to
/// other threads perhaps still running when the `fork` was run).
///
/// When this closure is run, aspects such as the stdio file descriptors and
/// working directory have successfully been changed, so output to these
/// locations may not appear where intended.
#[stable(feature = "process_exec", since = "1.15.0")]
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static;
/// Performs all the required setup by this `Command`, followed by calling
/// the `execvp` syscall.
///
/// On success this function will not return, and otherwise it will return
/// an error indicating why the exec (or another part of the setup of the
/// `Command`) failed.
///
/// This function, unlike `spawn`, will **not** `fork` the process to create
/// a new child. Like spawn, however, the default behavior for the stdio
/// descriptors will be to inherited from the current process.
///
/// # Notes
///
/// The process may be in a "broken state" if this function returns in
/// error. For example the working directory, environment variables, signal
/// handling settings, various user/group information, or aspects of stdio
/// file descriptors may have changed. If a "transactional spawn" is
/// required to gracefully handle errors it is recommended to use the
/// cross-platform `spawn` instead.
#[stable(feature = "process_exec2", since = "1.9.0")]
fn exec(&mut self) -> io::Error;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl CommandExt for process::Command {
fn uid(&mut self, id: u32) -> &mut process::Command {
self.as_inner_mut().uid(id);
self
}
fn gid(&mut self, id: u32) -> &mut process::Command {
self.as_inner_mut().gid(id);
self
}
fn before_exec<F>(&mut self, f: F) -> &mut process::Command
where F: FnMut() -> io::Result<()> + Send + Sync + 'static
{
self.as_inner_mut().before_exec(Box::new(f));
self
}
fn exec(&mut self) -> io::Error {
self.as_inner_mut().exec(sys::process::Stdio::Inherit)
}
}
/// Redox-specific extensions to [`process::ExitStatus`].
///
/// [`process::ExitStatus`]: ../../../../std/process/struct.ExitStatus.html
#[stable(feature = "rust1", since = "1.0.0")]
pub trait ExitStatusExt {
/// Creates a new `ExitStatus` from the raw underlying `i32` return value of
/// a process.
#[stable(feature = "exit_status_from", since = "1.12.0")]
fn from_raw(raw: i32) -> Self;
/// If the process was terminated by a signal, returns that signal.
#[stable(feature = "rust1", since = "1.0.0")]
fn signal(&self) -> Option<i32>;
}
#[stable(feature = "rust1", since = "1.0.0")]
impl ExitStatusExt for process::ExitStatus {
fn from_raw(raw: i32) -> Self {
process::ExitStatus::from_inner(From::from(raw))
}
fn signal(&self) -> Option<i32> {
self.as_inner().signal()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl FromRawFd for process::Stdio {
unsafe fn from_raw_fd(fd: RawFd) -> process::Stdio {
let fd = sys::fd::FileDesc::new(fd);
let io = sys::process::Stdio::Fd(fd);
process::Stdio::from_inner(io)
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdin {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStdout {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "process_extensions", since = "1.2.0")]
impl AsRawFd for process::ChildStderr {
fn as_raw_fd(&self) -> RawFd {
self.as_inner().fd().raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdin {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStdout {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}
#[stable(feature = "into_raw_os", since = "1.4.0")]
impl IntoRawFd for process::ChildStderr {
fn into_raw_fd(self) -> RawFd {
self.into_inner().into_fd().into_raw()
}
}

49
ctr-std/src/sys/redox/ext/thread.rs

@ -0,0 +1,49 @@
// 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.
//! Redox-specific extensions to primitives in the `std::thread` module.
#![stable(feature = "thread_extensions", since = "1.9.0")]
use sys_common::{AsInner, IntoInner};
use thread::JoinHandle;
#[stable(feature = "thread_extensions", since = "1.9.0")]
#[allow(deprecated)]
pub type RawPthread = usize;
/// Redox-specific extensions to [`thread::JoinHandle`].
///
/// [`thread::JoinHandle`]: ../../../../std/thread/struct.JoinHandle.html
#[stable(feature = "thread_extensions", since = "1.9.0")]
pub trait JoinHandleExt {
/// Extracts the raw pthread_t without taking ownership
#[stable(feature = "thread_extensions", since = "1.9.0")]
fn as_pthread_t(&self) -> RawPthread;
/// Consumes the thread, returning the raw pthread_t
///
/// This function **transfers ownership** of the underlying pthread_t to
/// the caller. Callers are then the unique owners of the pthread_t and
/// must either detach or join the pthread_t once it's no longer needed.
#[stable(feature = "thread_extensions", since = "1.9.0")]
fn into_pthread_t(self) -> RawPthread;
}
#[stable(feature = "thread_extensions", since = "1.9.0")]
impl<T> JoinHandleExt for JoinHandle<T> {
fn as_pthread_t(&self) -> RawPthread {
self.as_inner().id() as RawPthread
}
fn into_pthread_t(self) -> RawPthread {
self.into_inner().into_id() as RawPthread
}
}

121
ctr-std/src/sys/redox/fast_thread_local.rs

@ -0,0 +1,121 @@
// 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.
#![cfg(target_thread_local)]
#![unstable(feature = "thread_local_internals", issue = "0")]
use cell::{Cell, UnsafeCell};
use mem;
use ptr;
pub struct Key<T> {
inner: UnsafeCell<Option<T>>,
// Metadata to keep track of the state of the destructor. Remember that
// these variables are thread-local, not global.
dtor_registered: Cell<bool>,
dtor_running: Cell<bool>,
}
unsafe impl<T> ::marker::Sync for Key<T> { }
impl<T> Key<T> {
pub const fn new() -> Key<T> {
Key {
inner: UnsafeCell::new(None),
dtor_registered: Cell::new(false),
dtor_running: Cell::new(false)
}
}
pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> {
unsafe {
if mem::needs_drop::<T>() && self.dtor_running.get() {
return None
}
self.register_dtor();
}
Some(&self.inner)
}
unsafe fn register_dtor(&self) {
if !mem::needs_drop::<T>() || self.dtor_registered.get() {
return
}
register_dtor(self as *const _ as *mut u8,
destroy_value::<T>);
self.dtor_registered.set(true);
}
}
pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
// The fallback implementation uses a vanilla OS-based TLS key to track
// the list of destructors that need to be run for this thread. The key
// then has its own destructor which runs all the other destructors.
//
// The destructor for DTORS is a little special in that it has a `while`
// loop to continuously drain the list of registered destructors. It
// *should* be the case that this loop always terminates because we
// provide the guarantee that a TLS key cannot be set after it is
// flagged for destruction.
use sys_common::thread_local as os;
static DTORS: os::StaticKey = os::StaticKey::new(Some(run_dtors));
type List = Vec<(*mut u8, unsafe extern fn(*mut u8))>;
if DTORS.get().is_null() {
let v: Box<List> = box Vec::new();
DTORS.set(Box::into_raw(v) as *mut u8);
}
let list: &mut List = &mut *(DTORS.get() as *mut List);
list.push((t, dtor));
unsafe extern fn run_dtors(mut ptr: *mut u8) {
while !ptr.is_null() {
let list: Box<List> = Box::from_raw(ptr as *mut List);
for (ptr, dtor) in list.into_iter() {
dtor(ptr);
}
ptr = DTORS.get();
DTORS.set(ptr::null_mut());
}
}
}
pub unsafe extern fn destroy_value<T>(ptr: *mut u8) {
let ptr = ptr as *mut Key<T>;
// Right before we run the user destructor be sure to flag the
// destructor as running for this thread so calls to `get` will return
// `None`.
(*ptr).dtor_running.set(true);
// The macOS implementation of TLS apparently had an odd aspect to it
// where the pointer we have may be overwritten while this destructor
// is running. Specifically if a TLS destructor re-accesses TLS it may
// trigger a re-initialization of all TLS variables, paving over at
// least some destroyed ones with initial values.
//
// This means that if we drop a TLS value in place on macOS that we could
// revert the value to its original state halfway through the
// destructor, which would be bad!
//
// Hence, we use `ptr::read` on macOS (to move to a "safe" location)
// instead of drop_in_place.
if cfg!(target_os = "macos") {
ptr::read((*ptr).inner.get());
} else {
ptr::drop_in_place((*ptr).inner.get());
}
}
pub fn requires_move_before_drop() -> bool {
false
}

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save