diff options
Diffstat (limited to 'src/libstd/sys')
73 files changed, 3166 insertions, 552 deletions
diff --git a/src/libstd/sys/mod.rs b/src/libstd/sys/mod.rs index d91c2073a23..be8cb88416b 100644 --- a/src/libstd/sys/mod.rs +++ b/src/libstd/sys/mod.rs @@ -32,46 +32,66 @@ #![allow(missing_debug_implementations)] -pub use self::imp::*; - -#[cfg(unix)] -#[path = "unix/mod.rs"] -mod imp; - -#[cfg(windows)] -#[path = "windows/mod.rs"] -mod imp; - -#[cfg(target_os = "redox")] -#[path = "redox/mod.rs"] -mod imp; - - -// Import essential modules from both platforms when documenting. - -#[cfg(all(dox, not(unix)))] -use os::linux as platform; - -#[cfg(all(dox, not(any(unix, target_os = "redox"))))] -#[path = "unix/ext/mod.rs"] -pub mod unix_ext; - -#[cfg(all(dox, any(unix, target_os = "redox")))] -pub use self::ext as unix_ext; - - -#[cfg(all(dox, not(windows)))] -#[macro_use] -#[path = "windows/compat.rs"] -mod compat; - -#[cfg(all(dox, not(windows)))] -#[path = "windows/c.rs"] -mod c; - -#[cfg(all(dox, not(windows)))] -#[path = "windows/ext/mod.rs"] -pub mod windows_ext; - -#[cfg(all(dox, windows))] -pub use self::ext as windows_ext; +cfg_if! { + if #[cfg(unix)] { + mod unix; + pub use self::unix::*; + } else if #[cfg(windows)] { + mod windows; + pub use self::windows::*; + } 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 { + compile_error!("libstd doesn't compile for this platform yet"); + } +} + +// Import essential modules from both platforms when documenting. These are +// then later used in the `std::os` module when documenting, for example, +// Windows when we're compiling for Linux. + +#[cfg(dox)] +cfg_if! { + if #[cfg(any(unix, target_os = "redox"))] { + // On unix we'll document what's already available + pub use self::ext as unix_ext; + } else if #[cfg(target_arch = "wasm32")] { + // On wasm right now the module below doesn't compile (missing things + // in `libc` which is empty) so just omit everything with an empty module + #[unstable(issue = "0", feature = "std_internals")] + pub mod unix_ext {} + } else { + // On other platforms like Windows document the bare bones of unix + use os::linux as platform; + #[path = "unix/ext/mod.rs"] + pub mod unix_ext; + } +} + +#[cfg(dox)] +cfg_if! { + if #[cfg(windows)] { + // On windows we'll just be documenting what's already available + pub use self::ext as windows_ext; + } else if #[cfg(target_arch = "wasm32")] { + // On wasm right now the shim below doesn't compile, so just omit it + #[unstable(issue = "0", feature = "std_internals")] + pub mod windows_ext {} + } else { + // On all other platforms (aka linux/osx/etc) then pull in a "minimal" + // amount of windows goop which ends up compiling + #[macro_use] + #[path = "windows/compat.rs"] + mod compat; + + #[path = "windows/c.rs"] + mod c; + + #[path = "windows/ext/mod.rs"] + pub mod windows_ext; + } +} diff --git a/src/libstd/sys/redox/backtrace/tracing.rs b/src/libstd/sys/redox/backtrace/tracing.rs index cfeabaddda9..0a174b3c3f5 100644 --- a/src/libstd/sys/redox/backtrace/tracing.rs +++ b/src/libstd/sys/redox/backtrace/tracing.rs @@ -96,8 +96,8 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, if cx.idx < cx.frames.len() { cx.frames[cx.idx] = Frame { - symbol_addr: symaddr, - exact_position: ip, + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, }; cx.idx += 1; } diff --git a/src/libstd/sys/redox/cmath.rs b/src/libstd/sys/redox/cmath.rs new file mode 100644 index 00000000000..2bc96651b0c --- /dev/null +++ b/src/libstd/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; +} diff --git a/src/libstd/sys/redox/condvar.rs b/src/libstd/sys/redox/condvar.rs index fe4a89c6f3e..2a611ed7dab 100644 --- a/src/libstd/sys/redox/condvar.rs +++ b/src/libstd/sys/redox/condvar.rs @@ -9,12 +9,12 @@ // except according to those terms. use cell::UnsafeCell; -use intrinsics::{atomic_cxchg, atomic_xadd, atomic_xchg}; +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, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; +use sys::syscall::{futex, TimeSpec, FUTEX_WAIT, FUTEX_WAKE, FUTEX_REQUEUE}; pub struct Condvar { lock: UnsafeCell<*mut i32>, @@ -63,33 +63,50 @@ impl Condvar { } #[inline] - pub fn wait(&self, mutex: &Mutex) { - unsafe { - 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"); - } + unsafe fn wait_inner(&self, mutex: &Mutex, timeout_ptr: *const TimeSpec) -> bool { + let lock = self.lock.get(); + let seq = self.seq.get(); - atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize); + if *lock != mutex.lock.get() { + if *lock != ptr::null_mut() { + panic!("Condvar used with more than one Mutex"); } - mutex_unlock(*lock); + atomic_cxchg(lock as *mut usize, 0, mutex.lock.get() as usize); + } - let _ = futex(seq, FUTEX_WAIT, *seq, 0, ptr::null_mut()); + mutex_unlock(*lock); - while atomic_xchg(*lock, 2) != 0 { - let _ = futex(*lock, FUTEX_WAIT, 2, 0, ptr::null_mut()); - } + 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 { - ::sys_common::util::dumb_print(format_args!("condvar wait_timeout\n")); - unimplemented!(); + 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] diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs index 9f0eee024d5..6a007e98827 100644 --- a/src/libstd/sys/redox/fast_thread_local.rs +++ b/src/libstd/sys/redox/fast_thread_local.rs @@ -81,7 +81,7 @@ pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { 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.iter() { + for (ptr, dtor) in list.into_iter() { dtor(ptr); } ptr = DTORS.get(); diff --git a/src/libstd/sys/redox/fs.rs b/src/libstd/sys/redox/fs.rs index 918893097f8..3483477d40c 100644 --- a/src/libstd/sys/redox/fs.rs +++ b/src/libstd/sys/redox/fs.rs @@ -437,8 +437,7 @@ pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> { } pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - ::sys_common::util::dumb_print(format_args!("Link\n")); - unimplemented!(); + Err(Error::from_raw_os_error(syscall::ENOSYS)) } pub fn stat(p: &Path) -> io::Result<FileAttr> { diff --git a/src/libstd/sys/redox/mod.rs b/src/libstd/sys/redox/mod.rs index 7c728ebb1af..4352b72c307 100644 --- a/src/libstd/sys/redox/mod.rs +++ b/src/libstd/sys/redox/mod.rs @@ -12,9 +12,13 @@ use io::{self, ErrorKind}; +pub use libc::strlen; +pub use self::rand::hashmap_random_keys; + pub mod args; #[cfg(feature = "backtrace")] pub mod backtrace; +pub mod cmath; pub mod condvar; pub mod env; pub mod ext; diff --git a/src/libstd/sys/redox/os.rs b/src/libstd/sys/redox/os.rs index efddd5f0294..480765b77a0 100644 --- a/src/libstd/sys/redox/os.rs +++ b/src/libstd/sys/redox/os.rs @@ -209,3 +209,11 @@ pub fn exit(code: i32) -> ! { let _ = syscall::exit(code as usize); unreachable!(); } + +pub fn getpid() -> u32 { + syscall::getpid().unwrap() as u32 +} + +pub fn getppid() -> u32 { + syscall::getppid().unwrap() as u32 +} diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index c54286353a9..5c40d42fa0a 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -15,6 +15,8 @@ use borrow::Cow; use fmt; use str; use mem; +use rc::Rc; +use sync::Arc; use sys_common::{AsInner, IntoInner}; use std_unicode::lossy::Utf8Lossy; @@ -123,6 +125,16 @@ impl 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 { @@ -156,4 +168,16 @@ impl Slice { let boxed: Box<[u8]> = Default::default(); unsafe { mem::transmute(boxed) } } + + #[inline] + pub fn into_arc(&self) -> Arc<Slice> { + let arc: Arc<[u8]> = Arc::from(&self.inner); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } + } + + #[inline] + pub fn into_rc(&self) -> Rc<Slice> { + let rc: Rc<[u8]> = Rc::from(&self.inner); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } + } } diff --git a/src/libstd/sys/redox/rand.rs b/src/libstd/sys/redox/rand.rs index eb28eca38bc..3b378f53429 100644 --- a/src/libstd/sys/redox/rand.rs +++ b/src/libstd/sys/redox/rand.rs @@ -8,50 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use io; -use rand::Rng; - -// FIXME: Use rand: -pub struct OsRng { - state: [u64; 2] -} - -impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { - state: [0xBADF00D1, 0xDEADBEEF] - }) - } -} - -impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - self.next_u64() as u32 - } - fn next_u64(&mut self) -> u64 { - // Store the first and second part. - let mut x = self.state[0]; - let y = self.state[1]; - - // Put the second part into the first slot. - self.state[0] = y; - // Twist the first slot. - x ^= x << 23; - // Update the second slot. - self.state[1] = x ^ y ^ (x >> 17) ^ (y >> 26); - - // Generate the final integer. - self.state[1].wrapping_add(y) - - } - fn fill_bytes(&mut self, buf: &mut [u8]) { - for chunk in buf.chunks_mut(8) { - let mut rand: u64 = self.next_u64(); - for b in chunk.iter_mut() { - *b = rand as u8; - rand = rand >> 8; - } - } - } +pub fn hashmap_random_keys() -> (u64, u64) { + (0, 0) } diff --git a/src/libstd/sys/redox/stdio.rs b/src/libstd/sys/redox/stdio.rs index c839531cc26..3abb094ac34 100644 --- a/src/libstd/sys/redox/stdio.rs +++ b/src/libstd/sys/redox/stdio.rs @@ -70,5 +70,8 @@ impl io::Write for Stderr { } } -pub const EBADF_ERR: i32 = ::sys::syscall::EBADF; +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(::sys::syscall::EBADF as i32) +} + pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; diff --git a/src/libstd/sys/unix/backtrace/printing/dladdr.rs b/src/libstd/sys/unix/backtrace/printing/dladdr.rs index 21f0b3724c1..bc56fd6594e 100644 --- a/src/libstd/sys/unix/backtrace/printing/dladdr.rs +++ b/src/libstd/sys/unix/backtrace/printing/dladdr.rs @@ -22,7 +22,7 @@ pub fn resolve_symname<F>(frame: Frame, { unsafe { let mut info: Dl_info = intrinsics::init(); - let symname = if dladdr(frame.exact_position, &mut info) == 0 || + let symname = if dladdr(frame.exact_position as *mut _, &mut info) == 0 || info.dli_sname.is_null() { None } else { @@ -41,6 +41,5 @@ struct Dl_info { } extern { - fn dladdr(addr: *const libc::c_void, - info: *mut Dl_info) -> libc::c_int; + fn dladdr(addr: *const libc::c_void, info: *mut Dl_info) -> libc::c_int; } diff --git a/src/libstd/sys/unix/backtrace/printing/mod.rs b/src/libstd/sys/unix/backtrace/printing/mod.rs index 8bd2d9eccd8..caa60712b1d 100644 --- a/src/libstd/sys/unix/backtrace/printing/mod.rs +++ b/src/libstd/sys/unix/backtrace/printing/mod.rs @@ -20,7 +20,7 @@ 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], ::libc::c_int) -> io::Result<()> + F: FnMut(&[u8], u32) -> io::Result<()> { Ok(false) } diff --git a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs index ecd32aa9462..400d39cd4bd 100644 --- a/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs +++ b/src/libstd/sys/unix/backtrace/tracing/backtrace_fn.rs @@ -36,8 +36,8 @@ pub fn unwind_backtrace(frames: &mut [Frame]) } as usize; for (from, to) in raw_frames.iter().zip(frames.iter_mut()).take(nb_frames) { *to = Frame { - exact_position: *from, - symbol_addr: *from, + exact_position: *from as *mut u8, + symbol_addr: *from as *mut u8, }; } Ok((nb_frames as usize, BacktraceContext)) diff --git a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs index e3ffbe88acd..000c08d2e0d 100644 --- a/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs +++ b/src/libstd/sys/unix/backtrace/tracing/gcc_s.rs @@ -96,8 +96,8 @@ extern fn trace_fn(ctx: *mut uw::_Unwind_Context, if cx.idx < cx.frames.len() { cx.frames[cx.idx] = Frame { - symbol_addr: symaddr, - exact_position: ip, + symbol_addr: symaddr as *mut u8, + exact_position: ip as *mut u8, }; cx.idx += 1; } diff --git a/src/libstd/sys/unix/cmath.rs b/src/libstd/sys/unix/cmath.rs new file mode 100644 index 00000000000..2bc96651b0c --- /dev/null +++ b/src/libstd/sys/unix/cmath.rs @@ -0,0 +1,43 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +#![cfg(not(test))] + +use libc::{c_float, c_double}; + +#[link_name = "m"] +extern { + pub fn acos(n: c_double) -> c_double; + pub fn acosf(n: c_float) -> c_float; + pub fn asin(n: c_double) -> c_double; + pub fn asinf(n: c_float) -> c_float; + pub fn atan(n: c_double) -> c_double; + pub fn atan2(a: c_double, b: c_double) -> c_double; + pub fn atan2f(a: c_float, b: c_float) -> c_float; + pub fn atanf(n: c_float) -> c_float; + pub fn cbrt(n: c_double) -> c_double; + pub fn cbrtf(n: c_float) -> c_float; + pub fn cosh(n: c_double) -> c_double; + pub fn coshf(n: c_float) -> c_float; + pub fn expm1(n: c_double) -> c_double; + pub fn expm1f(n: c_float) -> c_float; + pub fn fdim(a: c_double, b: c_double) -> c_double; + pub fn fdimf(a: c_float, b: c_float) -> c_float; + pub fn hypot(x: c_double, y: c_double) -> c_double; + pub fn hypotf(x: c_float, y: c_float) -> c_float; + pub fn log1p(n: c_double) -> c_double; + pub fn log1pf(n: c_float) -> c_float; + pub fn sinh(n: c_double) -> c_double; + pub fn sinhf(n: c_float) -> c_float; + pub fn tan(n: c_double) -> c_double; + pub fn tanf(n: c_float) -> c_float; + pub fn tanh(n: c_double) -> c_double; + pub fn tanhf(n: c_float) -> c_float; +} diff --git a/src/libstd/sys/unix/condvar.rs b/src/libstd/sys/unix/condvar.rs index 89a44b97657..4f878d8ad1f 100644 --- a/src/libstd/sys/unix/condvar.rs +++ b/src/libstd/sys/unix/condvar.rs @@ -92,14 +92,15 @@ impl Condvar { assert_eq!(r, 0); // Nanosecond calculations can't overflow because both values are below 1e9. - let nsec = dur.subsec_nanos() as libc::c_long + now.tv_nsec as libc::c_long; + let nsec = dur.subsec_nanos() + now.tv_nsec as u32; + let sec = saturating_cast_to_time_t(dur.as_secs()) .checked_add((nsec / 1_000_000_000) as libc::time_t) .and_then(|s| s.checked_add(now.tv_sec)); let nsec = nsec % 1_000_000_000; let timeout = sec.map(|s| { - libc::timespec { tv_sec: s, tv_nsec: nsec } + libc::timespec { tv_sec: s, tv_nsec: nsec as _} }).unwrap_or(TIMESPEC_MAX); let r = libc::pthread_cond_timedwait(self.inner.get(), mutex::raw(mutex), diff --git a/src/libstd/sys/unix/env.rs b/src/libstd/sys/unix/env.rs index 3d9a06bedd5..00cf7eca75d 100644 --- a/src/libstd/sys/unix/env.rs +++ b/src/libstd/sys/unix/env.rs @@ -118,27 +118,6 @@ pub mod os { pub const EXE_EXTENSION: &'static str = ""; } -#[cfg(all(target_os = "nacl", not(target_arch = "le32")))] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "nacl"; - 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 = ".nexe"; - pub const EXE_EXTENSION: &'static str = "nexe"; -} -#[cfg(all(target_os = "nacl", target_arch = "le32"))] -pub mod os { - pub const FAMILY: &'static str = "unix"; - pub const OS: &'static str = "pnacl"; - pub const DLL_PREFIX: &'static str = "lib"; - pub const DLL_SUFFIX: &'static str = ".pso"; - pub const DLL_EXTENSION: &'static str = "pso"; - pub const EXE_SUFFIX: &'static str = ".pexe"; - pub const EXE_EXTENSION: &'static str = "pexe"; -} - #[cfg(target_os = "haiku")] pub mod os { pub const FAMILY: &'static str = "unix"; diff --git a/src/libstd/sys/unix/ext/fs.rs b/src/libstd/sys/unix/ext/fs.rs index 3e631ad40ac..2e17fd58e0a 100644 --- a/src/libstd/sys/unix/ext/fs.rs +++ b/src/libstd/sys/unix/ext/fs.rs @@ -20,7 +20,9 @@ use sys; use sys_common::{FromInner, AsInner, AsInnerMut}; use sys::platform::fs::MetadataExt as UnixMetadataExt; -/// Unix-specific extensions to `File` +/// 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. @@ -32,8 +34,28 @@ pub trait FileExt { /// /// 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 + /// 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 + /// + /// ``` + /// use std::os::unix::prelude::FileExt; + /// use std::fs::File; + /// + /// # use std::io; + /// # fn f() -> 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>; @@ -49,8 +71,26 @@ pub trait FileExt { /// 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 + /// 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 + /// + /// ``` + /// use std::os::unix::prelude::FileExt; + /// use std::fs::File; + /// + /// # use std::io; + /// # fn f() -> 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>; } @@ -215,36 +255,282 @@ impl OpenOptionsExt for OpenOptions { // casts and rely on manual lowering to `stat` if the raw type is desired. #[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::fs; + /// use std::os::unix::fs::MetadataExt; + /// + /// # use std::io; + /// # fn f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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 f() -> 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; } @@ -269,19 +555,79 @@ impl MetadataExt for fs::Metadata { fn blocks(&self) -> u64 { self.st_blocks() } } -/// Add special unix types (block/char device, fifo and socket) +/// Add support for special unix types (block/char device, fifo and socket). #[stable(feature = "file_type_ext", since = "1.5.0")] pub trait FileTypeExt { /// Returns whether this file type is a block device. + /// + /// # Examples + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::FileTypeExt; + /// + /// # use std::io; + /// # fn f() -> 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 + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::FileTypeExt; + /// + /// # use std::io; + /// # fn f() -> 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 + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::FileTypeExt; + /// + /// # use std::io; + /// # fn f() -> 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 + /// + /// ``` + /// use std::fs; + /// use std::os::unix::fs::FileTypeExt; + /// + /// # use std::io; + /// # fn f() -> 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; } @@ -294,7 +640,9 @@ impl FileTypeExt for fs::FileType { fn is_socket(&self) -> bool { self.as_inner().is(libc::S_IFSOCK) } } -/// Unix-specific extension methods for `fs::DirEntry` +/// 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` @@ -354,7 +702,9 @@ pub fn symlink<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) -> io::Result<()> } #[stable(feature = "dir_builder", since = "1.6.0")] -/// An extension trait for `fs::DirBuilder` for unix-specific options. +/// An extension trait for [`fs::DirBuilder`] for unix-specific options. +/// +/// [`fs::DirBuilder`]: ../../../../std/fs/struct.DirBuilder.html pub trait DirBuilderExt { /// Sets the mode to create new directories with. This option defaults to /// 0o777. diff --git a/src/libstd/sys/unix/ext/mod.rs b/src/libstd/sys/unix/ext/mod.rs index 98bc90dd4e1..c221f7c8cfe 100644 --- a/src/libstd/sys/unix/ext/mod.rs +++ b/src/libstd/sys/unix/ext/mod.rs @@ -10,8 +10,14 @@ //! Experimental extensions to `std` for Unix platforms. //! -//! For now, this module is limited to extracting file descriptors, -//! but its functionality will grow over time. +//! Provides access to platform-level information on Unix platforms, and +//! exposes Unix-specific functions that would otherwise be inappropriate as +//! part of the core `std` library. +//! +//! 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 //! diff --git a/src/libstd/sys/unix/ext/process.rs b/src/libstd/sys/unix/ext/process.rs index cde21b089a2..60309bec6d4 100644 --- a/src/libstd/sys/unix/ext/process.rs +++ b/src/libstd/sys/unix/ext/process.rs @@ -191,3 +191,9 @@ impl IntoRawFd for process::ChildStderr { self.into_inner().into_fd().into_raw() } } + +/// Returns the OS-assigned process identifier associated with this process's parent. +#[unstable(feature = "unix_ppid", issue = "46104")] +pub fn parent_id() -> u32 { + ::sys::os::getppid() +} diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index c4616c3b395..a1ca839dc18 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -132,14 +132,14 @@ 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_mtime_nsec as libc::c_long, + tv_nsec: self.stat.st_mtime_nsec 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: self.stat.st_atime_nsec as libc::c_long, + tv_nsec: self.stat.st_atime_nsec as _, })) } diff --git a/src/libstd/sys/unix/l4re.rs b/src/libstd/sys/unix/l4re.rs index 21218489679..c3e8d0b7d95 100644 --- a/src/libstd/sys/unix/l4re.rs +++ b/src/libstd/sys/unix/l4re.rs @@ -437,5 +437,9 @@ pub mod net { pub fn lookup_host(_: &str) -> io::Result<LookupHost> { unimpl!(); } + + pub fn res_init_if_glibc_before_2_26() -> io::Result<()> { + unimpl!(); + } } diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index 1b3f1000b77..9bdea945ea4 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -22,7 +22,6 @@ use libc; #[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 = "nacl"))] pub use os::nacl 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; @@ -30,6 +29,9 @@ use libc; #[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; +pub use self::rand::hashmap_random_keys; +pub use libc::strlen; + #[macro_use] pub mod weak; @@ -37,6 +39,7 @@ pub mod args; pub mod android; #[cfg(feature = "backtrace")] pub mod backtrace; +pub mod cmath; pub mod condvar; pub mod env; pub mod ext; @@ -77,11 +80,11 @@ pub fn init() { reset_sigpipe(); } - #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] + #[cfg(not(any(target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } - #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))] + #[cfg(any(target_os = "emscripten", target_os="fuchsia"))] unsafe fn reset_sigpipe() {} } diff --git a/src/libstd/sys/unix/net.rs b/src/libstd/sys/unix/net.rs index 668b2f92aba..e775f857f2b 100644 --- a/src/libstd/sys/unix/net.rs +++ b/src/libstd/sys/unix/net.rs @@ -176,11 +176,16 @@ impl Socket { } 0 => {} _ => { - if pollfd.revents & libc::POLLOUT == 0 { - if let Some(e) = self.take_error()? { - return Err(e); - } + // 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(()); } } @@ -355,3 +360,82 @@ impl FromInner<c_int> for Socket { impl IntoInner<c_int> for Socket { fn into_inner(self) -> c_int { self.0.into_raw() } } + +// In versions of glibc prior to 2.26, there's a bug where the DNS resolver +// will cache the contents of /etc/resolv.conf, so changes to that file on disk +// can be ignored by a long-running program. That can break DNS lookups on e.g. +// laptops where the network comes and goes. See +// https://sourceware.org/bugzilla/show_bug.cgi?id=984. Note however that some +// distros including Debian have patched glibc to fix this for a long time. +// +// A workaround for this bug is to call the res_init libc function, to clear +// the cached configs. Unfortunately, while we believe glibc's implementation +// of res_init is thread-safe, we know that other implementations are not +// (https://github.com/rust-lang/rust/issues/43592). Code here in libstd could +// try to synchronize its res_init calls with a Mutex, but that wouldn't +// protect programs that call into libc in other ways. So instead of calling +// res_init unconditionally, we call it only when we detect we're linking +// against glibc version < 2.26. (That is, when we both know its needed and +// believe it's thread-safe). +pub fn res_init_if_glibc_before_2_26() -> io::Result<()> { + // If the version fails to parse, we treat it the same as "not glibc". + if let Some(Ok(version_str)) = glibc_version_cstr().map(CStr::to_str) { + if let Some(version) = parse_glibc_version(version_str) { + if version < (2, 26) { + let ret = unsafe { libc::res_init() }; + if ret != 0 { + return Err(io::Error::last_os_error()); + } + } + } + } + Ok(()) +} + +fn glibc_version_cstr() -> Option<&'static CStr> { + weak! { + fn gnu_get_libc_version() -> *const libc::c_char + } + if let Some(f) = gnu_get_libc_version.get() { + unsafe { Some(CStr::from_ptr(f())) } + } else { + None + } +} + +// Returns Some((major, minor)) if the string is a valid "x.y" version, +// ignoring any extra dot-separated parts. Otherwise return None. +fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { + let mut parsed_ints = version.split(".").map(str::parse::<usize>).fuse(); + match (parsed_ints.next(), parsed_ints.next()) { + (Some(Ok(major)), Some(Ok(minor))) => Some((major, minor)), + _ => None + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn test_res_init() { + // This mostly just tests that the weak linkage doesn't panic wildly... + res_init_if_glibc_before_2_26().unwrap(); + } + + #[test] + fn test_parse_glibc_version() { + let cases = [ + ("0.0", Some((0, 0))), + ("01.+2", Some((1, 2))), + ("3.4.5.six", Some((3, 4))), + ("1", None), + ("1.-2", None), + ("1.foo", None), + ("foo.1", None), + ]; + for &(version_str, parsed) in cases.iter() { + assert_eq!(parsed, parse_glibc_version(version_str)); + } + } +} diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 5ef98d24710..4f33a2b12fe 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -223,7 +223,34 @@ pub fn current_exe() -> io::Result<PathBuf> { #[cfg(target_os = "netbsd")] pub fn current_exe() -> io::Result<PathBuf> { - ::fs::read_link("/proc/curproc/exe") + fn sysctl() -> io::Result<PathBuf> { + unsafe { + let mib = [libc::CTL_KERN, libc::KERN_PROC_ARGS, -1, libc::KERN_PROC_PATHNAME]; + let mut path_len: usize = 0; + cvt(libc::sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint, + ptr::null_mut(), &mut path_len, + ptr::null(), 0))?; + if path_len <= 1 { + return Err(io::Error::new(io::ErrorKind::Other, + "KERN_PROC_PATHNAME sysctl returned zero-length string")) + } + let mut path: Vec<u8> = Vec::with_capacity(path_len); + cvt(libc::sysctl(mib.as_ptr(), mib.len() as ::libc::c_uint, + path.as_ptr() as *mut libc::c_void, &mut path_len, + ptr::null(), 0))?; + path.set_len(path_len - 1); // chop off NUL + Ok(PathBuf::from(OsString::from_vec(path))) + } + } + fn procfs() -> io::Result<PathBuf> { + let curproc_exe = path::Path::new("/proc/curproc/exe"); + if curproc_exe.is_file() { + return ::fs::read_link(curproc_exe); + } + Err(io::Error::new(io::ErrorKind::Other, + "/proc/curproc/exe doesn't point to regular file.")) + } + sysctl().or_else(|_| procfs()) } #[cfg(any(target_os = "bitrig", target_os = "openbsd"))] @@ -483,12 +510,10 @@ pub fn home_dir() -> Option<PathBuf> { #[cfg(any(target_os = "android", target_os = "ios", - target_os = "nacl", target_os = "emscripten"))] unsafe fn fallback() -> Option<OsString> { None } #[cfg(not(any(target_os = "android", target_os = "ios", - target_os = "nacl", target_os = "emscripten")))] unsafe fn fallback() -> Option<OsString> { let amt = match libc::sysconf(libc::_SC_GETPW_R_SIZE_MAX) { @@ -513,3 +538,11 @@ pub fn home_dir() -> Option<PathBuf> { pub fn exit(code: i32) -> ! { unsafe { libc::exit(code as c_int) } } + +pub fn getpid() -> u32 { + unsafe { libc::getpid() as u32 } +} + +pub fn getppid() -> u32 { + unsafe { libc::getppid() as u32 } +} diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index 777db17e3e1..a27e76a0e3b 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -15,6 +15,8 @@ use borrow::Cow; use fmt; use str; use mem; +use rc::Rc; +use sync::Arc; use sys_common::{AsInner, IntoInner}; use std_unicode::lossy::Utf8Lossy; @@ -123,6 +125,16 @@ impl 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 { @@ -156,4 +168,16 @@ impl Slice { let boxed: Box<[u8]> = Default::default(); unsafe { mem::transmute(boxed) } } + + #[inline] + pub fn into_arc(&self) -> Arc<Slice> { + let arc: Arc<[u8]> = Arc::from(&self.inner); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } + } + + #[inline] + pub fn into_rc(&self) -> Rc<Slice> { + let rc: Rc<[u8]> = Rc::from(&self.inner); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } + } } diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index 689ccd78524..383434b1cd8 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -464,7 +464,6 @@ mod tests { // test from being flaky we ignore it on macOS. #[test] #[cfg_attr(target_os = "macos", ignore)] - #[cfg_attr(target_os = "nacl", ignore)] // no signals on NaCl. // When run under our current QEMU emulation test suite this test fails, // although the reason isn't very clear as to why. For now this test is // ignored there. diff --git a/src/libstd/sys/unix/process/process_fuchsia.rs b/src/libstd/sys/unix/process/process_fuchsia.rs index 5d34da04446..a7a67ed36e8 100644 --- a/src/libstd/sys/unix/process/process_fuchsia.rs +++ b/src/libstd/sys/unix/process/process_fuchsia.rs @@ -9,7 +9,7 @@ // except according to those terms. use io; -use libc; +use libc::{self, size_t}; use mem; use ptr; @@ -148,8 +148,8 @@ impl Process { use sys::process::zircon::*; let mut proc_info: zx_info_process_t = Default::default(); - let mut actual: zx_size_t = 0; - let mut avail: zx_size_t = 0; + let mut actual: size_t = 0; + let mut avail: size_t = 0; unsafe { zx_cvt(zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, @@ -171,8 +171,8 @@ impl Process { use sys::process::zircon::*; let mut proc_info: zx_info_process_t = Default::default(); - let mut actual: zx_size_t = 0; - let mut avail: zx_size_t = 0; + let mut actual: size_t = 0; + let mut avail: size_t = 0; unsafe { let status = zx_object_wait_one(self.handle.raw(), ZX_TASK_TERMINATED, diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index 870db820027..743c458d580 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -184,8 +184,8 @@ impl Command { *sys::os::environ() = envp.as_ptr(); } - // NaCl has no signal support. - #[cfg(not(any(target_os = "nacl", target_os = "emscripten")))] + // emscripten has no signal support. + #[cfg(not(any(target_os = "emscripten")))] { use mem; // Reset signal handling so the child process starts in a diff --git a/src/libstd/sys/unix/process/zircon.rs b/src/libstd/sys/unix/process/zircon.rs index b5ec11b40fd..90864e6ef3f 100644 --- a/src/libstd/sys/unix/process/zircon.rs +++ b/src/libstd/sys/unix/process/zircon.rs @@ -15,15 +15,13 @@ use io; use os::raw::c_char; use u64; -use libc::{c_int, c_void}; +use libc::{c_int, c_void, size_t}; -pub type zx_handle_t = i32; +pub type zx_handle_t = u32; pub type zx_vaddr_t = usize; pub type zx_rights_t = u32; pub type zx_status_t = i32; -pub type zx_size_t = usize; - pub const ZX_HANDLE_INVALID: zx_handle_t = 0; pub type zx_time_t = u64; @@ -115,36 +113,37 @@ extern { pending: *mut zx_signals_t) -> zx_status_t; pub fn zx_object_get_info(handle: zx_handle_t, topic: u32, buffer: *mut c_void, - buffer_size: zx_size_t, actual_size: *mut zx_size_t, - avail: *mut zx_size_t) -> zx_status_t; + buffer_size: size_t, actual_size: *mut size_t, + avail: *mut size_t) -> zx_status_t; } // From `enum special_handles` in system/ulib/launchpad/launchpad.c // HND_LOADER_SVC = 0 // HND_EXEC_VMO = 1 -pub const HND_SPECIAL_COUNT: usize = 2; +// HND_SEGMENTS_VMAR = 2 +const HND_SPECIAL_COUNT: c_int = 3; #[repr(C)] pub struct launchpad_t { argc: u32, envc: u32, args: *const c_char, - args_len: usize, + args_len: size_t, env: *const c_char, - env_len: usize, + env_len: size_t, handles: *mut zx_handle_t, handles_info: *mut u32, - handle_count: usize, - handle_alloc: usize, + handle_count: size_t, + handle_alloc: size_t, entry: zx_vaddr_t, base: zx_vaddr_t, vdso_base: zx_vaddr_t, - stack_size: usize, + stack_size: size_t, - special_handles: [zx_handle_t; HND_SPECIAL_COUNT], + special_handles: [zx_handle_t; HND_SPECIAL_COUNT as usize], loader_message: bool, } diff --git a/src/libstd/sys/unix/rand.rs b/src/libstd/sys/unix/rand.rs index fd066c9cdbe..caa18945765 100644 --- a/src/libstd/sys/unix/rand.rs +++ b/src/libstd/sys/unix/rand.rs @@ -8,20 +8,17 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -pub use self::imp::OsRng; - use mem; +use slice; -fn next_u32(fill_buf: &mut FnMut(&mut [u8])) -> u32 { - let mut buf: [u8; 4] = [0; 4]; - fill_buf(&mut buf); - unsafe { mem::transmute::<[u8; 4], u32>(buf) } -} - -fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 { - let mut buf: [u8; 8] = [0; 8]; - fill_buf(&mut buf); - unsafe { mem::transmute::<[u8; 8], u64>(buf) } +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(all(unix, @@ -30,56 +27,22 @@ fn next_u64(fill_buf: &mut FnMut(&mut [u8])) -> u64 { not(target_os = "freebsd"), not(target_os = "fuchsia")))] mod imp { - use self::OsRngInner::*; - use super::{next_u32, next_u64}; - use fs::File; - use io; + use io::Read; use libc; - use rand::Rng; - use rand::reader::ReaderRng; use sys::os::errno; - #[cfg(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x")))] + #[cfg(any(target_os = "linux", target_os = "android"))] fn getrandom(buf: &mut [u8]) -> libc::c_long { - #[cfg(target_arch = "x86_64")] - const NR_GETRANDOM: libc::c_long = 318; - #[cfg(target_arch = "x86")] - const NR_GETRANDOM: libc::c_long = 355; - #[cfg(target_arch = "arm")] - const NR_GETRANDOM: libc::c_long = 384; - #[cfg(target_arch = "s390x")] - const NR_GETRANDOM: libc::c_long = 349; - #[cfg(any(target_arch = "powerpc", target_arch = "powerpc64"))] - const NR_GETRANDOM: libc::c_long = 359; - #[cfg(target_arch = "aarch64")] - const NR_GETRANDOM: libc::c_long = 278; - - const GRND_NONBLOCK: libc::c_uint = 0x0001; - unsafe { - libc::syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), GRND_NONBLOCK) + libc::syscall(libc::SYS_getrandom, buf.as_mut_ptr(), buf.len(), libc::GRND_NONBLOCK) } } - #[cfg(not(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x"))))] + #[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]) { + fn getrandom_fill_bytes(v: &mut [u8]) -> bool { let mut read = 0; while read < v.len() { let result = getrandom(&mut v[read..]); @@ -88,18 +51,7 @@ mod imp { if err == libc::EINTR { continue; } else if err == libc::EAGAIN { - // if getrandom() returns EAGAIN 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 - let reader = File::open("/dev/urandom").expect("Unable to open /dev/urandom"); - let mut reader_rng = ReaderRng::new(reader); - reader_rng.fill_bytes(&mut v[read..]); - read += v.len(); + return false } else { panic!("unexpected getrandom error: {}", err); } @@ -107,17 +59,13 @@ mod imp { read += result as usize; } } + + return true } - #[cfg(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x")))] + #[cfg(any(target_os = "linux", target_os = "android"))] fn is_getrandom_available() -> bool { + use io; use sync::atomic::{AtomicBool, Ordering}; use sync::Once; @@ -139,99 +87,40 @@ mod imp { AVAILABLE.load(Ordering::Relaxed) } - #[cfg(not(all(target_os = "linux", - any(target_arch = "x86_64", - target_arch = "x86", - target_arch = "arm", - target_arch = "aarch64", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x"))))] + #[cfg(not(any(target_os = "linux", target_os = "android")))] fn is_getrandom_available() -> bool { false } - pub struct OsRng { - inner: OsRngInner, - } - - enum OsRngInner { - OsGetrandomRng, - OsReaderRng(ReaderRng<File>), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - if is_getrandom_available() { - return Ok(OsRng { inner: OsGetrandomRng }); - } - - let reader = File::open("/dev/urandom")?; - let reader_rng = ReaderRng::new(reader); - - Ok(OsRng { inner: OsReaderRng(reader_rng) }) + 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 } - } - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - match self.inner { - OsGetrandomRng => next_u32(&mut getrandom_fill_bytes), - OsReaderRng(ref mut rng) => rng.next_u32(), - } - } - fn next_u64(&mut self) -> u64 { - match self.inner { - OsGetrandomRng => next_u64(&mut getrandom_fill_bytes), - OsReaderRng(ref mut rng) => rng.next_u64(), - } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - match self.inner { - OsGetrandomRng => getrandom_fill_bytes(v), - OsReaderRng(ref mut rng) => rng.fill_bytes(v) - } - } + 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 super::{next_u32, next_u64}; - - use io; use libc; use sys::os::errno; - use rand::Rng; - - pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside - // of this module - _dummy: (), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { _dummy: () }) - } - } - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - next_u32(&mut |v| self.fill_bytes(v)) - } - fn next_u64(&mut self) -> u64 { - next_u64(&mut |v| self.fill_bytes(v)) - } - fn fill_bytes(&mut self, 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()); - } + 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()); } } } @@ -239,18 +128,9 @@ mod imp { #[cfg(target_os = "ios")] mod imp { - use super::{next_u32, next_u64}; - use io; - use ptr; - use rand::Rng; use libc::{c_int, size_t}; - - pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside - // of this module - _dummy: (), - } + use ptr; enum SecRandom {} @@ -259,79 +139,41 @@ mod imp { extern { fn SecRandomCopyBytes(rnd: *const SecRandom, - count: size_t, bytes: *mut u8) -> c_int; + count: size_t, + bytes: *mut u8) -> c_int; } - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { _dummy: () }) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - next_u32(&mut |v| self.fill_bytes(v)) - } - fn next_u64(&mut self) -> u64 { - next_u64(&mut |v| self.fill_bytes(v)) - } - fn fill_bytes(&mut self, 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()); - } + 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 super::{next_u32, next_u64}; - - use io; use libc; - use rand::Rng; use ptr; - pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside - // of this module - _dummy: (), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { _dummy: () }) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - next_u32(&mut |v| self.fill_bytes(v)) - } - fn next_u64(&mut self) -> u64 { - next_u64(&mut |v| self.fill_bytes(v)) - } - fn fill_bytes(&mut self, 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); - } + 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); } } } @@ -339,11 +181,6 @@ mod imp { #[cfg(target_os = "fuchsia")] mod imp { - use super::{next_u32, next_u64}; - - use io; - use rand::Rng; - #[link(name = "zircon")] extern { fn zx_cprng_draw(buffer: *mut u8, len: usize, actual: *mut usize) -> i32; @@ -361,39 +198,18 @@ mod imp { } } - pub struct OsRng { - // dummy field to ensure that this struct cannot be constructed outside - // of this module - _dummy: (), - } - - impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - Ok(OsRng { _dummy: () }) - } - } - - impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - next_u32(&mut |v| self.fill_bytes(v)) - } - fn next_u64(&mut self) -> u64 { - next_u64(&mut |v| self.fill_bytes(v)) - } - fn fill_bytes(&mut self, 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)..]; - } + 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)..]; } } } diff --git a/src/libstd/sys/unix/stdio.rs b/src/libstd/sys/unix/stdio.rs index 7a8fe25d98e..e9b3d4affc7 100644 --- a/src/libstd/sys/unix/stdio.rs +++ b/src/libstd/sys/unix/stdio.rs @@ -70,5 +70,8 @@ impl io::Write for Stderr { } } -pub const EBADF_ERR: i32 = ::libc::EBADF as i32; +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(libc::EBADF as i32) +} + pub const STDIN_BUF_SIZE: usize = ::sys_common::io::DEFAULT_BUF_SIZE; diff --git a/src/libstd/sys/unix/thread.rs b/src/libstd/sys/unix/thread.rs index 6c4a3324296..9da33f5adac 100644 --- a/src/libstd/sys/unix/thread.rs +++ b/src/libstd/sys/unix/thread.rs @@ -87,7 +87,7 @@ impl Thread { }; extern fn thread_start(main: *mut libc::c_void) -> *mut libc::c_void { - unsafe { start_thread(main); } + unsafe { start_thread(main as *mut u8); } ptr::null_mut() } } @@ -149,7 +149,7 @@ impl Thread { pub fn sleep(dur: Duration) { let mut secs = dur.as_secs(); - let mut nsecs = dur.subsec_nanos() as libc::c_long; + let mut nsecs = dur.subsec_nanos() as _; // If we're awoken with a signal then the return value will be -1 and // nanosleep will fill in `ts` with the remaining time. diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index c1bea95ce91..837cd7292e2 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -60,7 +60,7 @@ impl Timespec { Timespec { t: libc::timespec { tv_sec: secs, - tv_nsec: nsec as libc::c_long, + tv_nsec: nsec as _, }, } } @@ -83,7 +83,7 @@ impl Timespec { Timespec { t: libc::timespec { tv_sec: secs, - tv_nsec: nsec as libc::c_long, + tv_nsec: nsec as _, }, } } diff --git a/src/libstd/sys/wasm/args.rs b/src/libstd/sys/wasm/args.rs new file mode 100644 index 00000000000..d2a4a7b19d5 --- /dev/null +++ b/src/libstd/sys/wasm/args.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 ffi::OsString; +use marker::PhantomData; +use mem; +use vec; + +pub unsafe fn init(_argc: isize, _argv: *const *const u8) { + // On wasm these should always be null, so there's nothing for us to do here +} + +pub unsafe fn cleanup() { +} + +pub fn args() -> Args { + // When the runtime debugging is enabled we'll link to some extra runtime + // functions to actually implement this. These are for now just implemented + // in a node.js script but they're off by default as they're sort of weird + // in a web-wasm world. + if !super::DEBUG { + return Args { + iter: Vec::new().into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } + + // You'll find the definitions of these in `src/etc/wasm32-shim.js`. These + // are just meant for debugging and should not be relied on. + extern { + fn rust_wasm_args_count() -> usize; + fn rust_wasm_args_arg_size(a: usize) -> usize; + fn rust_wasm_args_arg_fill(a: usize, ptr: *mut u8); + } + + unsafe { + let cnt = rust_wasm_args_count(); + let mut v = Vec::with_capacity(cnt); + for i in 0..cnt { + let n = rust_wasm_args_arg_size(i); + let mut data = vec![0; n]; + rust_wasm_args_arg_fill(i, data.as_mut_ptr()); + v.push(mem::transmute::<Vec<u8>, OsString>(data)); + } + Args { + iter: v.into_iter(), + _dont_send_or_sync_me: PhantomData, + } + } +} + +pub struct Args { + iter: vec::IntoIter<OsString>, + _dont_send_or_sync_me: PhantomData<*mut ()>, +} + +impl Args { + pub fn inner_debug(&self) -> &[OsString] { + self.iter.as_slice() + } +} + +impl Iterator for Args { + type Item = OsString; + fn next(&mut self) -> Option<OsString> { + self.iter.next() + } + fn size_hint(&self) -> (usize, Option<usize>) { + self.iter.size_hint() + } +} + +impl ExactSizeIterator for Args { + fn len(&self) -> usize { + self.iter.len() + } +} + +impl DoubleEndedIterator for Args { + fn next_back(&mut self) -> Option<OsString> { + self.iter.next_back() + } +} diff --git a/src/libstd/sys/wasm/backtrace.rs b/src/libstd/sys/wasm/backtrace.rs new file mode 100644 index 00000000000..9a8c48ff29f --- /dev/null +++ b/src/libstd/sys/wasm/backtrace.rs @@ -0,0 +1,37 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use sys::unsupported; +use sys_common::backtrace::Frame; + +pub struct BacktraceContext; + +pub fn unwind_backtrace(_frames: &mut [Frame]) + -> io::Result<(usize, BacktraceContext)> +{ + unsupported() +} + +pub fn resolve_symname<F>(_frame: Frame, + _callback: F, + _: &BacktraceContext) -> io::Result<()> + where F: FnOnce(Option<&str>) -> io::Result<()> +{ + unsupported() +} + +pub fn foreach_symbol_fileline<F>(_: Frame, + _: F, + _: &BacktraceContext) -> io::Result<bool> + where F: FnMut(&[u8], u32) -> io::Result<()> +{ + unsupported() +} diff --git a/src/libstd/sys/wasm/cmath.rs b/src/libstd/sys/wasm/cmath.rs new file mode 100644 index 00000000000..87ac2091cad --- /dev/null +++ b/src/libstd/sys/wasm/cmath.rs @@ -0,0 +1,119 @@ +// 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. + +#[inline] +pub unsafe fn cbrtf(n: f32) -> f32 { + f64::cbrt(n as f64) as f32 +} + +#[inline] +pub unsafe fn expm1f(n: f32) -> f32 { + f64::exp_m1(n as f64) as f32 +} + +#[inline] +#[allow(deprecated)] +pub unsafe fn fdimf(a: f32, b: f32) -> f32 { + f64::abs_sub(a as f64, b as f64) as f32 +} + +#[inline] +pub unsafe fn log1pf(n: f32) -> f32 { + f64::ln_1p(n as f64) as f32 +} + +#[inline] +pub unsafe fn hypotf(x: f32, y: f32) -> f32 { + f64::hypot(x as f64, y as f64) as f32 +} + +#[inline] +pub unsafe fn acosf(n: f32) -> f32 { + f64::acos(n as f64) as f32 +} + +#[inline] +pub unsafe fn asinf(n: f32) -> f32 { + f64::asin(n as f64) as f32 +} + +#[inline] +pub unsafe fn atan2f(n: f32, b: f32) -> f32 { + f64::atan2(n as f64, b as f64) as f32 +} + +#[inline] +pub unsafe fn atanf(n: f32) -> f32 { + f64::atan(n as f64) as f32 +} + +#[inline] +pub unsafe fn coshf(n: f32) -> f32 { + f64::cosh(n as f64) as f32 +} + +#[inline] +pub unsafe fn sinhf(n: f32) -> f32 { + f64::sinh(n as f64) as f32 +} + +#[inline] +pub unsafe fn tanf(n: f32) -> f32 { + f64::tan(n as f64) as f32 +} + +#[inline] +pub unsafe fn tanhf(n: f32) -> f32 { + f64::tanh(n as f64) as f32 +} + +// Right now all these functions, the f64 version of the functions above, all +// shell out to random names. These names aren't actually defined anywhere, per +// se, but we need this to compile somehow. +// +// The idea with this is that when you're using wasm then, for now, we have no +// way of providing an implementation of these which delegates to a "correct" +// implementation. For example most wasm applications probably just want to +// delegate to the javascript `Math` object and its related functions, but wasm +// doesn't currently have the ability to seamlessly do that (when you +// instantiate a module you have to set that up). +// +// As a result these are just defined here with "hopefully helpful" names. The +// symbols won't ever be needed or show up unless these functions are called, +// and hopefully when they're called the errors are self-explanatory enough to +// figure out what's going on. + +extern { + #[link_name = "Math_acos"] + pub fn acos(n: f64) -> f64; + #[link_name = "Math_asin"] + pub fn asin(n: f64) -> f64; + #[link_name = "Math_atan"] + pub fn atan(n: f64) -> f64; + #[link_name = "Math_atan2"] + pub fn atan2(a: f64, b: f64) -> f64; + #[link_name = "Math_cbrt"] + pub fn cbrt(n: f64) -> f64; + #[link_name = "Math_cosh"] + pub fn cosh(n: f64) -> f64; + #[link_name = "Math_expm1"] + pub fn expm1(n: f64) -> f64; + pub fn fdim(a: f64, b: f64) -> f64; + #[link_name = "Math_log1p"] + pub fn log1p(n: f64) -> f64; + #[link_name = "Math_sinh"] + pub fn sinh(n: f64) -> f64; + #[link_name = "Math_tan"] + pub fn tan(n: f64) -> f64; + #[link_name = "Math_tanh"] + pub fn tanh(n: f64) -> f64; + #[link_name = "Math_hypot"] + pub fn hypot(x: f64, y: f64) -> f64; +} diff --git a/src/libstd/sys/wasm/condvar.rs b/src/libstd/sys/wasm/condvar.rs new file mode 100644 index 00000000000..afa7afeef59 --- /dev/null +++ b/src/libstd/sys/wasm/condvar.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. + +use sys::mutex::Mutex; +use time::Duration; + +pub struct Condvar { } + +impl Condvar { + pub const fn new() -> Condvar { + Condvar { } + } + + #[inline] + pub unsafe fn init(&mut self) {} + + #[inline] + pub unsafe fn notify_one(&self) { + } + + #[inline] + pub unsafe fn notify_all(&self) { + } + + pub unsafe fn wait(&self, _mutex: &Mutex) { + panic!("can't block with web assembly") + } + + pub unsafe fn wait_timeout(&self, _mutex: &Mutex, _dur: Duration) -> bool { + panic!("can't block with web assembly"); + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} diff --git a/src/libstd/sys/wasm/env.rs b/src/libstd/sys/wasm/env.rs new file mode 100644 index 00000000000..1422042bd02 --- /dev/null +++ b/src/libstd/sys/wasm/env.rs @@ -0,0 +1,19 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub mod os { + pub const FAMILY: &'static str = ""; + pub const OS: &'static str = ""; + pub const DLL_PREFIX: &'static str = ""; + pub const DLL_SUFFIX: &'static str = ".wasm"; + pub const DLL_EXTENSION: &'static str = "wasm"; + pub const EXE_SUFFIX: &'static str = ".wasm"; + pub const EXE_EXTENSION: &'static str = "wasm"; +} diff --git a/src/libstd/sys/wasm/fs.rs b/src/libstd/sys/wasm/fs.rs new file mode 100644 index 00000000000..b3c70a6685a --- /dev/null +++ b/src/libstd/sys/wasm/fs.rs @@ -0,0 +1,304 @@ +// 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() +} diff --git a/src/libstd/sys/wasm/memchr.rs b/src/libstd/sys/wasm/memchr.rs new file mode 100644 index 00000000000..e611d94af30 --- /dev/null +++ b/src/libstd/sys/wasm/memchr.rs @@ -0,0 +1,11 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub use sys_common::memchr::fallback::{memchr, memrchr}; diff --git a/src/libstd/sys/wasm/mod.rs b/src/libstd/sys/wasm/mod.rs new file mode 100644 index 00000000000..b838dbafd6f --- /dev/null +++ b/src/libstd/sys/wasm/mod.rs @@ -0,0 +1,104 @@ +// 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. + +//! System bindings for the wasm/web platform +//! +//! This module contains the facade (aka platform-specific) implementations of +//! OS level functionality for wasm. Note that this wasm is *not* the emscripten +//! wasm, so we have no runtime here. +//! +//! This is all super highly experimental and not actually intended for +//! wide/production use yet, it's still all in the experimental category. This +//! will likely change over time. +//! +//! Currently all functions here are basically stubs that immediately return +//! errors. The hope is that with a portability lint we can turn actually just +//! remove all this and just omit parts of the standard library if we're +//! compiling for wasm. That way it's a compile time error for something that's +//! guaranteed to be a runtime error! + +use io; +use os::raw::c_char; + +// Right now the wasm backend doesn't even have the ability to print to the +// console by default. Wasm can't import anything from JS! (you have to +// explicitly provide it). +// +// Sometimes that's a real bummer, though, so this flag can be set to `true` to +// enable calling various shims defined in `src/etc/wasm32-shim.js` which should +// help receive debug output and see what's going on. In general this flag +// currently controls "will we call out to our own defined shims in node.js", +// and this flag should always be `false` for release builds. +const DEBUG: bool = false; + +pub mod args; +pub mod backtrace; +pub mod cmath; +pub mod condvar; +pub mod env; +pub mod fs; +pub mod memchr; +pub mod mutex; +pub mod net; +pub mod os; +pub mod os_str; +pub mod path; +pub mod pipe; +pub mod process; +pub mod rwlock; +pub mod stack_overflow; +pub mod thread; +pub mod thread_local; +pub mod time; +pub mod stdio; + +#[cfg(not(test))] +pub fn init() { +} + +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 wasm yet") +} + +pub fn decode_error_kind(_code: i32) -> io::ErrorKind { + io::ErrorKind::Other +} + +// 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 unsafe fn strlen(mut s: *const c_char) -> usize { + let mut n = 0; + while *s != 0 { + n += 1; + s = s.offset(1); + } + return n +} + +pub unsafe fn abort_internal() -> ! { + ::intrinsics::abort(); +} + +// We don't have randomness yet, but I totally used a random number generator to +// generate these numbers. +// +// More seriously though this is just for DOS protection in hash maps. It's ok +// if we don't do that on wasm just yet. +pub fn hashmap_random_keys() -> (u64, u64) { + (1, 2) +} diff --git a/src/libstd/sys/wasm/mutex.rs b/src/libstd/sys/wasm/mutex.rs new file mode 100644 index 00000000000..4197bdcc808 --- /dev/null +++ b/src/libstd/sys/wasm/mutex.rs @@ -0,0 +1,79 @@ +// 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; + +pub struct Mutex { + locked: UnsafeCell<bool>, +} + +unsafe impl Send for Mutex {} +unsafe impl Sync for Mutex {} // no threads on wasm + +impl Mutex { + pub const fn new() -> Mutex { + Mutex { locked: UnsafeCell::new(false) } + } + + #[inline] + pub unsafe fn init(&mut self) { + } + + #[inline] + pub unsafe fn lock(&self) { + let locked = self.locked.get(); + assert!(!*locked, "cannot recursively acquire mutex"); + *locked = true; + } + + #[inline] + pub unsafe fn unlock(&self) { + *self.locked.get() = false; + } + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + let locked = self.locked.get(); + if *locked { + false + } else { + *locked = true; + true + } + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} + +// All empty stubs because wasm has no threads yet, so lock acquisition always +// succeeds. +pub struct ReentrantMutex { +} + +impl ReentrantMutex { + pub unsafe fn uninitialized() -> ReentrantMutex { + ReentrantMutex { } + } + + pub unsafe fn init(&mut self) {} + + pub unsafe fn lock(&self) {} + + #[inline] + pub unsafe fn try_lock(&self) -> bool { + true + } + + pub unsafe fn unlock(&self) {} + + pub unsafe fn destroy(&self) {} +} diff --git a/src/libstd/sys/wasm/net.rs b/src/libstd/sys/wasm/net.rs new file mode 100644 index 00000000000..e7476ab37f7 --- /dev/null +++ b/src/libstd/sys/wasm/net.rs @@ -0,0 +1,337 @@ +// 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::{SocketAddr, Shutdown, Ipv4Addr, Ipv6Addr}; +use time::Duration; +use sys::{unsupported, Void}; + +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() +} + +#[allow(bad_style)] +pub mod netc { + pub const AF_INET: u8 = 0; + pub const AF_INET6: u8 = 1; + pub type sa_family_t = u8; + + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: u16, + pub sin_addr: in_addr, + } + + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct sockaddr_in6 { + pub sin6_family: sa_family_t, + pub sin6_port: u16, + pub sin6_addr: in6_addr, + pub sin6_flowinfo: u32, + pub sin6_scope_id: u32, + } + + #[derive(Copy, Clone)] + pub struct sockaddr { + } + + pub type socklen_t = usize; +} diff --git a/src/libstd/sys/wasm/os.rs b/src/libstd/sys/wasm/os.rs new file mode 100644 index 00000000000..c98030f7ebf --- /dev/null +++ b/src/libstd/sys/wasm/os.rs @@ -0,0 +1,136 @@ +// 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 core::intrinsics; + +use error::Error as StdError; +use ffi::{OsString, OsStr}; +use fmt; +use io; +use mem; +use path::{self, PathBuf}; +use str; +use sys::{unsupported, Void}; + +pub fn errno() -> i32 { + 0 +} + +pub fn error_string(_errno: i32) -> String { + format!("operation successful") +} + +pub fn getcwd() -> io::Result<PathBuf> { + unsupported() +} + +pub fn chdir(_: &path::Path) -> 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 wasm yet".fmt(f) + } +} + +impl StdError for JoinPathsError { + fn description(&self) -> &str { + "not supported on wasm yet" + } +} + +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 web assembly") +} + +pub fn getenv(k: &OsStr) -> io::Result<Option<OsString>> { + // If we're debugging the runtime then we actually probe node.js to ask for + // the value of environment variables to help provide inputs to programs. + // The `extern` shims here are defined in `src/etc/wasm32-shim.js` and are + // intended for debugging only, you should not rely on them. + if !super::DEBUG { + return Ok(None) + } + + extern { + fn rust_wasm_getenv_len(k: *const u8, kl: usize) -> isize; + fn rust_wasm_getenv_data(k: *const u8, kl: usize, v: *mut u8); + } + unsafe { + let k: &[u8] = mem::transmute(k); + let n = rust_wasm_getenv_len(k.as_ptr(), k.len()); + if n == -1 { + return Ok(None) + } + let mut data = vec![0; n as usize]; + rust_wasm_getenv_data(k.as_ptr(), k.len(), data.as_mut_ptr()); + Ok(Some(mem::transmute(data))) + } +} + +pub fn setenv(_k: &OsStr, _v: &OsStr) -> io::Result<()> { + unsupported() +} + +pub fn unsetenv(_n: &OsStr) -> io::Result<()> { + unsupported() +} + +pub fn temp_dir() -> PathBuf { + panic!("no filesystem on wasm") +} + +pub fn home_dir() -> Option<PathBuf> { + None +} + +pub fn exit(_code: i32) -> ! { + unsafe { intrinsics::abort() } +} + +pub fn getpid() -> u32 { + panic!("no pids on wasm") +} diff --git a/src/libstd/sys/wasm/os_str.rs b/src/libstd/sys/wasm/os_str.rs new file mode 100644 index 00000000000..0e64b5bc6b8 --- /dev/null +++ b/src/libstd/sys/wasm/os_str.rs @@ -0,0 +1,183 @@ +// 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. + +/// 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 std_unicode::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 { + fmt::Debug::fmt(&Utf8Lossy::from_bytes(&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() + } + + 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) } + } +} diff --git a/src/libstd/sys/wasm/path.rs b/src/libstd/sys/wasm/path.rs new file mode 100644 index 00000000000..395b8c1e40e --- /dev/null +++ b/src/libstd/sys/wasm/path.rs @@ -0,0 +1,29 @@ +// 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 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 = '/'; diff --git a/src/libstd/sys/wasm/pipe.rs b/src/libstd/sys/wasm/pipe.rs new file mode 100644 index 00000000000..992e1ac409c --- /dev/null +++ b/src/libstd/sys/wasm/pipe.rs @@ -0,0 +1,35 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use io; +use sys::Void; + +pub struct AnonPipe(Void); + +impl AnonPipe { + pub fn read(&self, _buf: &mut [u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn write(&self, _buf: &[u8]) -> io::Result<usize> { + match self.0 {} + } + + pub fn diverge(&self) -> ! { + match self.0 {} + } +} + +pub fn read2(p1: AnonPipe, + _v1: &mut Vec<u8>, + _p2: AnonPipe, + _v2: &mut Vec<u8>) -> io::Result<()> { + match p1.0 {} +} diff --git a/src/libstd/sys/wasm/process.rs b/src/libstd/sys/wasm/process.rs new file mode 100644 index 00000000000..4febe8a1463 --- /dev/null +++ b/src/libstd/sys/wasm/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}; + +//////////////////////////////////////////////////////////////////////////////// +// Command +//////////////////////////////////////////////////////////////////////////////// + +pub struct Command { +} + +// 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 {} + } + + pub fn arg(&mut self, _arg: &OsStr) { + } + + pub fn env(&mut self, _key: &OsStr, _val: &OsStr) { + } + + pub fn env_remove(&mut self, _key: &OsStr) { + } + + pub fn env_clear(&mut self) { + } + + 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 {} + } +} + +pub struct Process(Void); + +impl Process { + pub fn id(&self) -> u32 { + match self.0 {} + } + + pub fn kill(&mut self) -> io::Result<()> { + match self.0 {} + } + + pub fn wait(&mut self) -> io::Result<ExitStatus> { + match self.0 {} + } + + pub fn try_wait(&mut self) -> io::Result<Option<ExitStatus>> { + match self.0 {} + } +} diff --git a/src/libstd/sys/wasm/rwlock.rs b/src/libstd/sys/wasm/rwlock.rs new file mode 100644 index 00000000000..8b06f541674 --- /dev/null +++ b/src/libstd/sys/wasm/rwlock.rs @@ -0,0 +1,82 @@ +// 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; + +pub struct RWLock { + mode: UnsafeCell<isize>, +} + +unsafe impl Send for RWLock {} +unsafe impl Sync for RWLock {} // no threads on wasm + +impl RWLock { + pub const fn new() -> RWLock { + RWLock { + mode: UnsafeCell::new(0), + } + } + + #[inline] + pub unsafe fn read(&self) { + let mode = self.mode.get(); + if *mode >= 0 { + *mode += 1; + } else { + panic!("rwlock locked for writing"); + } + } + + #[inline] + pub unsafe fn try_read(&self) -> bool { + let mode = self.mode.get(); + if *mode >= 0 { + *mode += 1; + true + } else { + false + } + } + + #[inline] + pub unsafe fn write(&self) { + let mode = self.mode.get(); + if *mode == 0 { + *mode = -1; + } else { + panic!("rwlock locked for reading") + } + } + + #[inline] + pub unsafe fn try_write(&self) -> bool { + let mode = self.mode.get(); + if *mode == 0 { + *mode = -1; + true + } else { + false + } + } + + #[inline] + pub unsafe fn read_unlock(&self) { + *self.mode.get() -= 1; + } + + #[inline] + pub unsafe fn write_unlock(&self) { + *self.mode.get() += 1; + } + + #[inline] + pub unsafe fn destroy(&self) { + } +} diff --git a/src/libstd/sys/wasm/stack_overflow.rs b/src/libstd/sys/wasm/stack_overflow.rs new file mode 100644 index 00000000000..bed274142f1 --- /dev/null +++ b/src/libstd/sys/wasm/stack_overflow.rs @@ -0,0 +1,23 @@ +// Copyright 2017 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or +// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license +// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +pub struct Handler; + +impl Handler { + pub unsafe fn new() -> Handler { + Handler + } +} + +pub unsafe fn init() { +} + +pub unsafe fn cleanup() { +} diff --git a/src/libstd/sys/wasm/stdio.rs b/src/libstd/sys/wasm/stdio.rs new file mode 100644 index 00000000000..0f75f240251 --- /dev/null +++ b/src/libstd/sys/wasm/stdio.rs @@ -0,0 +1,92 @@ +// 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, unsupported}; + +pub struct Stdin(Void); +pub struct Stdout; +pub struct Stderr; + +impl Stdin { + pub fn new() -> io::Result<Stdin> { + unsupported() + } + + pub fn read(&self, _data: &mut [u8]) -> io::Result<usize> { + match self.0 {} + } +} + +impl Stdout { + pub fn new() -> io::Result<Stdout> { + Ok(Stdout) + } + + pub fn write(&self, data: &[u8]) -> io::Result<usize> { + // If runtime debugging is enabled at compile time we'll invoke some + // runtime functions that are defined in our src/etc/wasm32-shim.js + // debugging script. Note that this ffi function call is intended + // *purely* for debugging only and should not be relied upon. + if !super::DEBUG { + return unsupported() + } + extern { + fn rust_wasm_write_stdout(data: *const u8, len: usize); + } + unsafe { + rust_wasm_write_stdout(data.as_ptr(), data.len()) + } + Ok(data.len()) + } + + 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> { + // See comments in stdout for what's going on here. + if !super::DEBUG { + return unsupported() + } + extern { + fn rust_wasm_write_stderr(data: *const u8, len: usize); + } + unsafe { + rust_wasm_write_stderr(data.as_ptr(), data.len()) + } + Ok(data.len()) + } + + pub fn flush(&self) -> io::Result<()> { + Ok(()) + } +} + +impl io::Write for Stderr { + fn write(&mut self, data: &[u8]) -> io::Result<usize> { + (&*self).write(data) + } + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } +} + +pub const STDIN_BUF_SIZE: usize = 0; + +pub fn is_ebadf(_err: &io::Error) -> bool { + true +} diff --git a/src/libstd/sys/wasm/thread.rs b/src/libstd/sys/wasm/thread.rs new file mode 100644 index 00000000000..13980e0cc19 --- /dev/null +++ b/src/libstd/sys/wasm/thread.rs @@ -0,0 +1,48 @@ +// 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::boxed::FnBox; +use ffi::CStr; +use io; +use sys::{unsupported, Void}; +use time::Duration; + +pub struct Thread(Void); + +pub const DEFAULT_MIN_STACK_SIZE: usize = 4096; + +impl Thread { + pub unsafe fn new<'a>(_stack: usize, _p: Box<FnBox() + 'a>) + -> io::Result<Thread> + { + unsupported() + } + + pub fn yield_now() { + // do nothing + } + + pub fn set_name(_name: &CStr) { + // nope + } + + pub fn sleep(_dur: Duration) { + panic!("can't sleep"); + } + + pub fn join(self) { + match self.0 {} + } +} + +pub mod guard { + pub unsafe fn current() -> Option<usize> { None } + pub unsafe fn init() -> Option<usize> { None } +} diff --git a/src/libstd/sys/wasm/thread_local.rs b/src/libstd/sys/wasm/thread_local.rs new file mode 100644 index 00000000000..442dd3302a0 --- /dev/null +++ b/src/libstd/sys/wasm/thread_local.rs @@ -0,0 +1,50 @@ +// 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 boxed::Box; +use ptr; + +pub type Key = usize; + +struct Allocated { + value: *mut u8, + dtor: Option<unsafe extern fn(*mut u8)>, +} + +#[inline] +pub unsafe fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key { + Box::into_raw(Box::new(Allocated { + value: ptr::null_mut(), + dtor, + })) as usize +} + +#[inline] +pub unsafe fn set(key: Key, value: *mut u8) { + (*(key as *mut Allocated)).value = value; +} + +#[inline] +pub unsafe fn get(key: Key) -> *mut u8 { + (*(key as *mut Allocated)).value +} + +#[inline] +pub unsafe fn destroy(key: Key) { + let key = Box::from_raw(key as *mut Allocated); + if let Some(f) = key.dtor { + f(key.value); + } +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + false +} diff --git a/src/libstd/sys/wasm/time.rs b/src/libstd/sys/wasm/time.rs new file mode 100644 index 00000000000..7907720e4da --- /dev/null +++ b/src/libstd/sys/wasm/time.rs @@ -0,0 +1,63 @@ +// 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 time::Duration; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] +pub struct Instant; + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct SystemTime; + +pub const UNIX_EPOCH: SystemTime = SystemTime; + +impl Instant { + pub fn now() -> Instant { + panic!("not supported on web assembly"); + } + + pub fn sub_instant(&self, _other: &Instant) -> Duration { + panic!("can't sub yet"); + } + + pub fn add_duration(&self, _other: &Duration) -> Instant { + panic!("can't add yet"); + } + + pub fn sub_duration(&self, _other: &Duration) -> Instant { + panic!("can't sub yet"); + } +} + +impl SystemTime { + pub fn now() -> SystemTime { + panic!("not supported on web assembly"); + } + + pub fn sub_time(&self, _other: &SystemTime) + -> Result<Duration, Duration> { + panic!() + } + + pub fn add_duration(&self, _other: &Duration) -> SystemTime { + panic!() + } + + pub fn sub_duration(&self, _other: &Duration) -> SystemTime { + panic!() + } +} + +impl fmt::Debug for SystemTime { + fn fmt(&self, _f: &mut fmt::Formatter) -> fmt::Result { + panic!() + } +} diff --git a/src/libstd/sys/windows/backtrace/mod.rs b/src/libstd/sys/windows/backtrace/mod.rs index 26b4cb90e0a..176891fff23 100644 --- a/src/libstd/sys/windows/backtrace/mod.rs +++ b/src/libstd/sys/windows/backtrace/mod.rs @@ -95,8 +95,8 @@ pub fn unwind_backtrace(frames: &mut [Frame]) frame.AddrReturn.Offset == 0 { break } frames[i] = Frame { - symbol_addr: (addr - 1) as *const c_void, - exact_position: (addr - 1) as *const c_void, + symbol_addr: (addr - 1) as *const u8, + exact_position: (addr - 1) as *const u8, }; i += 1; } diff --git a/src/libstd/sys/windows/backtrace/printing/msvc.rs b/src/libstd/sys/windows/backtrace/printing/msvc.rs index 3107d784324..5a49b77af8e 100644 --- a/src/libstd/sys/windows/backtrace/printing/msvc.rs +++ b/src/libstd/sys/windows/backtrace/printing/msvc.rs @@ -10,7 +10,7 @@ use ffi::CStr; use io; -use libc::{c_ulong, c_int, c_char}; +use libc::{c_ulong, c_char}; use mem; use sys::c; use sys::backtrace::BacktraceContext; @@ -59,7 +59,7 @@ pub fn foreach_symbol_fileline<F>(frame: Frame, mut f: F, context: &BacktraceContext) -> io::Result<bool> - where F: FnMut(&[u8], c_int) -> io::Result<()> + where F: FnMut(&[u8], u32) -> io::Result<()> { let SymGetLineFromAddr64 = sym!(&context.dbghelp, "SymGetLineFromAddr64", @@ -76,7 +76,7 @@ pub fn foreach_symbol_fileline<F>(frame: Frame, &mut line); if ret == c::TRUE { let name = CStr::from_ptr(line.Filename).to_bytes(); - f(name, line.LineNumber as c_int)?; + f(name, line.LineNumber as u32)?; } Ok(false) } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 9535ddfe5ca..6e0cccff001 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -37,7 +37,6 @@ pub type BOOL = c_int; pub type BYTE = u8; pub type BOOLEAN = BYTE; pub type GROUP = c_uint; -pub type LONG_PTR = isize; pub type LARGE_INTEGER = c_longlong; pub type LONG = c_long; pub type UINT = c_uint; @@ -46,7 +45,6 @@ pub type USHORT = c_ushort; pub type SIZE_T = usize; pub type WORD = u16; pub type CHAR = c_char; -pub type HCRYPTPROV = LONG_PTR; pub type ULONG_PTR = usize; pub type ULONG = c_ulong; #[cfg(target_arch = "x86_64")] @@ -279,16 +277,15 @@ pub const WAIT_TIMEOUT: DWORD = 258; pub const WAIT_FAILED: DWORD = 0xFFFFFFFF; #[cfg(target_env = "msvc")] +#[cfg(feature = "backtrace")] pub const MAX_SYM_NAME: usize = 2000; #[cfg(target_arch = "x86")] +#[cfg(feature = "backtrace")] pub const IMAGE_FILE_MACHINE_I386: DWORD = 0x014c; #[cfg(target_arch = "x86_64")] +#[cfg(feature = "backtrace")] pub const IMAGE_FILE_MACHINE_AMD64: DWORD = 0x8664; -pub const PROV_RSA_FULL: DWORD = 1; -pub const CRYPT_SILENT: DWORD = 64; -pub const CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000; - pub const EXCEPTION_CONTINUE_SEARCH: LONG = 0; pub const EXCEPTION_STACK_OVERFLOW: DWORD = 0xc00000fd; pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; @@ -575,6 +572,7 @@ pub struct OVERLAPPED { #[repr(C)] #[cfg(target_env = "msvc")] +#[cfg(feature = "backtrace")] pub struct SYMBOL_INFO { pub SizeOfStruct: c_ulong, pub TypeIndex: c_ulong, @@ -598,6 +596,7 @@ pub struct SYMBOL_INFO { #[repr(C)] #[cfg(target_env = "msvc")] +#[cfg(feature = "backtrace")] pub struct IMAGEHLP_LINE64 { pub SizeOfStruct: u32, pub Key: *const c_void, @@ -616,6 +615,7 @@ pub enum ADDRESS_MODE { } #[repr(C)] +#[cfg(feature = "backtrace")] pub struct ADDRESS64 { pub Offset: u64, pub Segment: u16, @@ -623,6 +623,7 @@ pub struct ADDRESS64 { } #[repr(C)] +#[cfg(feature = "backtrace")] pub struct STACKFRAME64 { pub AddrPC: ADDRESS64, pub AddrReturn: ADDRESS64, @@ -638,6 +639,7 @@ pub struct STACKFRAME64 { } #[repr(C)] +#[cfg(feature = "backtrace")] pub struct KDHELP64 { pub Thread: u64, pub ThCallbackStack: DWORD, @@ -1089,6 +1091,7 @@ extern "system" { pub fn FindNextFileW(findFile: HANDLE, findFileData: LPWIN32_FIND_DATAW) -> BOOL; pub fn FindClose(findFile: HANDLE) -> BOOL; + #[cfg(feature = "backtrace")] pub fn RtlCaptureContext(ctx: *mut CONTEXT); pub fn getsockopt(s: SOCKET, level: c_int, @@ -1120,20 +1123,13 @@ extern "system" { res: *mut *mut ADDRINFOA) -> c_int; pub fn freeaddrinfo(res: *mut ADDRINFOA); + #[cfg(feature = "backtrace")] pub fn LoadLibraryW(name: LPCWSTR) -> HMODULE; + #[cfg(feature = "backtrace")] pub fn FreeLibrary(handle: HMODULE) -> BOOL; pub fn GetProcAddress(handle: HMODULE, name: LPCSTR) -> *mut c_void; pub fn GetModuleHandleW(lpModuleName: LPCWSTR) -> HMODULE; - pub fn CryptAcquireContextA(phProv: *mut HCRYPTPROV, - pszContainer: LPCSTR, - pszProvider: LPCSTR, - dwProvType: DWORD, - dwFlags: DWORD) -> BOOL; - pub fn CryptGenRandom(hProv: HCRYPTPROV, - dwLen: DWORD, - pbBuffer: *mut BYTE) -> BOOL; - pub fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL; pub fn GetSystemTimeAsFileTime(lpSystemTimeAsFileTime: LPFILETIME); @@ -1164,6 +1160,9 @@ extern "system" { writefds: *mut fd_set, exceptfds: *mut fd_set, timeout: *const timeval) -> c_int; + + #[link_name = "SystemFunction036"] + pub fn RtlGenRandom(RandomBuffer: *mut u8, RandomBufferLength: ULONG) -> BOOLEAN; } // Functions that aren't available on every version of Windows that we support, @@ -1229,7 +1228,7 @@ compat_fn! { } } -#[cfg(target_env = "gnu")] +#[cfg(all(target_env = "gnu", feature = "backtrace"))] mod gnu { use super::*; @@ -1257,5 +1256,5 @@ mod gnu { } } -#[cfg(target_env = "gnu")] +#[cfg(all(target_env = "gnu", feature = "backtrace"))] pub use self::gnu::*; diff --git a/src/libstd/sys/windows/cmath.rs b/src/libstd/sys/windows/cmath.rs new file mode 100644 index 00000000000..b665a2c9ba4 --- /dev/null +++ b/src/libstd/sys/windows/cmath.rs @@ -0,0 +1,103 @@ +// 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 asin(n: c_double) -> c_double; + pub fn atan(n: c_double) -> c_double; + pub fn atan2(a: c_double, b: c_double) -> c_double; + 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 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; + #[cfg_attr(target_env = "msvc", link_name = "_hypot")] + pub fn hypot(x: c_double, y: c_double) -> c_double; + #[cfg_attr(target_env = "msvc", link_name = "_hypotf")] + 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 tan(n: c_double) -> c_double; + pub fn tanh(n: c_double) -> c_double; +} + +pub use self::shims::*; + +#[cfg(not(target_env = "msvc"))] +mod shims { + use libc::c_float; + + extern { + pub fn acosf(n: c_float) -> c_float; + pub fn asinf(n: c_float) -> c_float; + pub fn atan2f(a: c_float, b: c_float) -> c_float; + pub fn atanf(n: c_float) -> c_float; + pub fn coshf(n: c_float) -> c_float; + pub fn sinhf(n: c_float) -> c_float; + pub fn tanf(n: c_float) -> c_float; + pub fn tanhf(n: c_float) -> c_float; + } +} + +// On MSVC these functions aren't defined, so we just define shims which promote +// everything fo f64, perform the calculation, and then demote back to f32. +// While not precisely correct should be "correct enough" for now. +#[cfg(target_env = "msvc")] +mod shims { + use libc::c_float; + + #[inline] + pub unsafe fn acosf(n: c_float) -> c_float { + f64::acos(n as f64) as c_float + } + + #[inline] + pub unsafe fn asinf(n: c_float) -> c_float { + f64::asin(n as f64) as c_float + } + + #[inline] + pub unsafe fn atan2f(n: c_float, b: c_float) -> c_float { + f64::atan2(n as f64, b as f64) as c_float + } + + #[inline] + pub unsafe fn atanf(n: c_float) -> c_float { + f64::atan(n as f64) as c_float + } + + #[inline] + pub unsafe fn coshf(n: c_float) -> c_float { + f64::cosh(n as f64) as c_float + } + + #[inline] + pub unsafe fn sinhf(n: c_float) -> c_float { + f64::sinh(n as f64) as c_float + } + + #[inline] + pub unsafe fn tanf(n: c_float) -> c_float { + f64::tan(n as f64) as c_float + } + + #[inline] + pub unsafe fn tanhf(n: c_float) -> c_float { + f64::tanh(n as f64) as c_float + } +} diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index 3f6c2827a3f..d6b8896ac09 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -9,6 +9,62 @@ // except according to those terms. //! Windows-specific extensions to the primitives in the `std::ffi` module. +//! +//! # Overview +//! +//! For historical reasons, the Windows API uses a form of potentially +//! ill-formed UTF-16 encoding for strings. Specifically, the 16-bit +//! code units in Windows strings may contain [isolated surrogate code +//! points which are not paired together][ill-formed-utf-16]. The +//! Unicode standard requires that surrogate code points (those in the +//! range U+D800 to U+DFFF) always be *paired*, because in the UTF-16 +//! encoding a *surrogate code unit pair* is used to encode a single +//! character. For compatibility with code that does not enforce +//! these pairings, Windows does not enforce them, either. +//! +//! While it is not always possible to convert such a string losslessly into +//! a valid UTF-16 string (or even UTF-8), it is often desirable to be +//! able to round-trip such a string from and to Windows APIs +//! losslessly. For example, some Rust code may be "bridging" some +//! Windows APIs together, just passing `WCHAR` strings among those +//! APIs without ever really looking into the strings. +//! +//! If Rust code *does* need to look into those strings, it can +//! convert them to valid UTF-8, possibly lossily, by substituting +//! invalid sequences with U+FFFD REPLACEMENT CHARACTER, as is +//! conventionally done in other Rust APIs that deal with string +//! encodings. +//! +//! # `OsStringExt` and `OsStrExt` +//! +//! [`OsString`] is the Rust wrapper for owned strings in the +//! preferred representation of the operating system. On Windows, +//! this struct gets augmented with an implementation of the +//! [`OsStringExt`] trait, which has a [`from_wide`] method. This +//! lets you create an [`OsString`] from a `&[u16]` slice; presumably +//! you get such a slice out of a `WCHAR` Windows API. +//! +//! Similarly, [`OsStr`] is the Rust wrapper for borrowed strings from +//! preferred representation of the operating system. On Windows, the +//! [`OsStrExt`] trait provides the [`encode_wide`] method, which +//! outputs an [`EncodeWide`] iterator. You can [`collect`] this +//! iterator, for example, to obtain a `Vec<u16>`; you can later get a +//! pointer to this vector's contents and feed it to Windows APIs. +//! +//! These traits, along with [`OsString`] and [`OsStr`], work in +//! conjunction so that it is possible to **round-trip** strings from +//! Windows and back, with no loss of data, even if the strings are +//! ill-formed UTF-16. +//! +//! [ill-formed-utf-16]: https://simonsapin.github.io/wtf-8/#ill-formed-utf-16 +//! [`OsString`]: ../../../ffi/struct.OsString.html +//! [`OsStr`]: ../../../ffi/struct.OsStr.html +//! [`OsStringExt`]: trait.OsStringExt.html +//! [`OsStrExt`]: trait.OsStrExt.html +//! [`EncodeWide`]: struct.EncodeWide.html +//! [`from_wide`]: trait.OsStringExt.html#tymethod.from_wide +//! [`encode_wide`]: trait.OsStrExt.html#tymethod.encode_wide +//! [`collect`]: ../../../iter/trait.Iterator.html#method.collect #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index d58a3505154..24c41046f26 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -32,7 +32,7 @@ pub trait FileExt { /// function, it is set to the end of the read. /// /// Reading beyond the end of the file will always return with a length of - /// 0. + /// 0\. /// /// Note that similar to `File::read`, it is not an error to return with a /// short read. When returning from such a short read, the file pointer is @@ -393,8 +393,8 @@ pub trait MetadataExt { /// to. For a directory, the structure specifies when the directory was /// created. /// - /// If the underlying filesystem does not support the last write time - /// time, the returned value is 0. + /// If the underlying filesystem does not support the last write time, + /// the returned value is 0. /// /// # Examples /// diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index f2487c1b0bd..ae9535139d9 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -722,16 +722,16 @@ pub fn canonicalize(p: &Path) -> io::Result<PathBuf> { pub fn copy(from: &Path, to: &Path) -> io::Result<u64> { unsafe extern "system" fn callback( _TotalFileSize: c::LARGE_INTEGER, - TotalBytesTransferred: c::LARGE_INTEGER, + _TotalBytesTransferred: c::LARGE_INTEGER, _StreamSize: c::LARGE_INTEGER, - _StreamBytesTransferred: c::LARGE_INTEGER, - _dwStreamNumber: c::DWORD, + StreamBytesTransferred: c::LARGE_INTEGER, + dwStreamNumber: c::DWORD, _dwCallbackReason: c::DWORD, _hSourceFile: c::HANDLE, _hDestinationFile: c::HANDLE, lpData: c::LPVOID, ) -> c::DWORD { - *(lpData as *mut i64) = TotalBytesTransferred; + if dwStreamNumber == 1 {*(lpData as *mut i64) = StreamBytesTransferred;} c::PROGRESS_CONTINUE } let pfrom = to_u16s(from)?; diff --git a/src/libstd/sys/windows/mod.rs b/src/libstd/sys/windows/mod.rs index ee58efc5144..0d12ecf8fe3 100644 --- a/src/libstd/sys/windows/mod.rs +++ b/src/libstd/sys/windows/mod.rs @@ -17,12 +17,18 @@ use os::windows::ffi::{OsStrExt, OsStringExt}; use path::PathBuf; use time::Duration; +pub use libc::strlen; +pub use self::rand::hashmap_random_keys; + #[macro_use] pub mod compat; pub mod args; +#[cfg(feature = "backtrace")] pub mod backtrace; pub mod c; +pub mod cmath; pub mod condvar; +#[cfg(feature = "backtrace")] pub mod dynamic_lib; pub mod env; pub mod ext; diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index a51b458451e..b9448243559 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -318,6 +318,10 @@ pub fn exit(code: i32) -> ! { unsafe { c::ExitProcess(code as c::UINT) } } +pub fn getpid() -> u32 { + unsafe { c::GetCurrentProcessId() as u32 } +} + #[cfg(test)] mod tests { use io::Error; diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index 3eb4582718b..b8d2f7bc53c 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -15,6 +15,8 @@ use borrow::Cow; use fmt; use sys_common::wtf8::{Wtf8, Wtf8Buf}; use mem; +use rc::Rc; +use sync::Arc; use sys_common::{AsInner, IntoInner}; #[derive(Clone, Hash)] @@ -115,6 +117,16 @@ impl Buf { let inner: Box<Wtf8> = unsafe { mem::transmute(boxed) }; Buf { inner: Wtf8Buf::from_box(inner) } } + + #[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 { @@ -144,4 +156,16 @@ impl Slice { pub fn empty_box() -> Box<Slice> { unsafe { mem::transmute(Wtf8::empty_box()) } } + + #[inline] + pub fn into_arc(&self) -> Arc<Slice> { + let arc = self.inner.into_arc(); + unsafe { Arc::from_raw(Arc::into_raw(arc) as *const Slice) } + } + + #[inline] + pub fn into_rc(&self) -> Rc<Slice> { + let rc = self.inner.into_rc(); + unsafe { Rc::from_raw(Rc::into_raw(rc) as *const Slice) } + } } diff --git a/src/libstd/sys/windows/path.rs b/src/libstd/sys/windows/path.rs index 2b47808451b..98d62a0c953 100644 --- a/src/libstd/sys/windows/path.rs +++ b/src/libstd/sys/windows/path.rs @@ -8,8 +8,6 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ascii::*; - use path::Prefix; use ffi::OsStr; use mem; diff --git a/src/libstd/sys/windows/pipe.rs b/src/libstd/sys/windows/pipe.rs index 452d720ce59..f3b1185c6ea 100644 --- a/src/libstd/sys/windows/pipe.rs +++ b/src/libstd/sys/windows/pipe.rs @@ -15,11 +15,13 @@ use io; use mem; use path::Path; use ptr; -use rand::{self, Rng}; use slice; +use sync::atomic::Ordering::SeqCst; +use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT}; use sys::c; use sys::fs::{File, OpenOptions}; use sys::handle::Handle; +use sys::hashmap_random_keys; //////////////////////////////////////////////////////////////////////////////// // Anonymous pipes @@ -71,10 +73,9 @@ pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> { let mut reject_remote_clients_flag = c::PIPE_REJECT_REMOTE_CLIENTS; loop { tries += 1; - let key: u64 = rand::thread_rng().gen(); name = format!(r"\\.\pipe\__rust_anonymous_pipe1__.{}.{}", c::GetCurrentProcessId(), - key); + random_number()); let wide_name = OsStr::new(&name) .encode_wide() .chain(Some(0)) @@ -156,6 +157,17 @@ pub fn anon_pipe(ours_readable: bool) -> io::Result<Pipes> { } } +fn random_number() -> usize { + static N: AtomicUsize = ATOMIC_USIZE_INIT; + loop { + if N.load(SeqCst) != 0 { + return N.fetch_add(1, SeqCst) + } + + N.store(hashmap_random_keys().0 as usize, SeqCst); + } +} + impl AnonPipe { pub fn handle(&self) -> &Handle { &self.inner } pub fn into_handle(self) -> Handle { self.inner } diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 0d1766d5aec..631d69b05e1 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use ascii::*; +use ascii::AsciiExt; use collections::HashMap; use collections; use env::split_paths; diff --git a/src/libstd/sys/windows/rand.rs b/src/libstd/sys/windows/rand.rs index 10e3d45f9d5..262323656aa 100644 --- a/src/libstd/sys/windows/rand.rs +++ b/src/libstd/sys/windows/rand.rs @@ -8,69 +8,19 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. - use io; use mem; -use rand::Rng; use sys::c; -pub struct OsRng { - hcryptprov: c::HCRYPTPROV -} - -impl OsRng { - /// Create a new `OsRng`. - pub fn new() -> io::Result<OsRng> { - let mut hcp = 0; - let ret = unsafe { - c::CryptAcquireContextA(&mut hcp, 0 as c::LPCSTR, 0 as c::LPCSTR, - c::PROV_RSA_FULL, - c::CRYPT_VERIFYCONTEXT | c::CRYPT_SILENT) - }; - - if ret == 0 { - Err(io::Error::last_os_error()) - } else { - Ok(OsRng { hcryptprov: hcp }) - } - } -} - -impl Rng for OsRng { - fn next_u32(&mut self) -> u32 { - let mut v = [0; 4]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn next_u64(&mut self) -> u64 { - let mut v = [0; 8]; - self.fill_bytes(&mut v); - unsafe { mem::transmute(v) } - } - fn fill_bytes(&mut self, v: &mut [u8]) { - // CryptGenRandom takes a DWORD (u32) for the length so we need to - // split up the buffer. - for slice in v.chunks_mut(<c::DWORD>::max_value() as usize) { - let ret = unsafe { - c::CryptGenRandom(self.hcryptprov, slice.len() as c::DWORD, - slice.as_mut_ptr()) - }; - if ret == 0 { - panic!("couldn't generate random bytes: {}", - io::Error::last_os_error()); - } - } - } -} - -impl Drop for OsRng { - fn drop(&mut self) { - let ret = unsafe { - c::CryptReleaseContext(self.hcryptprov, 0) - }; - if ret == 0 { - panic!("couldn't release context: {}", - io::Error::last_os_error()); - } +pub fn hashmap_random_keys() -> (u64, u64) { + let mut v = (0, 0); + let ret = unsafe { + c::RtlGenRandom(&mut v as *mut _ as *mut u8, + mem::size_of_val(&v) as c::ULONG) + }; + if ret == 0 { + panic!("couldn't generate random bytes: {}", + io::Error::last_os_error()); } + return v } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b5e5b5760f2..b43df20bddd 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -218,7 +218,10 @@ fn readconsole_input_control(wakeup_mask: c::ULONG) -> c::CONSOLE_READCONSOLE_CO const CTRL_Z: u8 = 0x1A; const CTRL_Z_MASK: c::ULONG = 0x4000000; //1 << 0x1A -pub const EBADF_ERR: i32 = ::sys::c::ERROR_INVALID_HANDLE as i32; +pub fn is_ebadf(err: &io::Error) -> bool { + err.raw_os_error() == Some(c::ERROR_INVALID_HANDLE as i32) +} + // The default buffer capacity is 64k, but apparently windows // doesn't like 64k reads on stdin. See #13304 for details, but the // idea is that on windows we use a slightly smaller buffer that's diff --git a/src/libstd/sys/windows/thread.rs b/src/libstd/sys/windows/thread.rs index c47baaa2434..74786d09285 100644 --- a/src/libstd/sys/windows/thread.rs +++ b/src/libstd/sys/windows/thread.rs @@ -52,7 +52,7 @@ impl Thread { }; extern "system" fn thread_start(main: *mut c_void) -> c::DWORD { - unsafe { start_thread(main); } + unsafe { start_thread(main as *mut u8); } 0 } } diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 7ae9ed917bd..cdad320e122 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -200,8 +200,9 @@ unsafe fn register_dtor(key: Key, dtor: Dtor) { // the address of the symbol to ensure it sticks around. #[link_section = ".CRT$XLB"] -#[linkage = "external"] #[allow(dead_code, unused_variables)] +#[used] // we don't want LLVM eliminating this symbol for any reason, and + // when the symbol makes it to the linker the linker will take over pub static p_thread_callback: unsafe extern "system" fn(c::LPVOID, c::DWORD, c::LPVOID) = on_tls_callback; |
