about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/Cargo.toml2
-rw-r--r--src/libstd/collections/hash/set.rs6
-rw-r--r--src/libstd/f32.rs10
-rw-r--r--src/libstd/f64.rs10
-rw-r--r--src/libstd/ffi/os_str.rs1
-rw-r--r--src/libstd/sys/sgx/alloc.rs16
-rw-r--r--src/libstd/sys/sgx/mod.rs9
-rw-r--r--src/libstd/sys/sgx/rwlock.rs42
-rw-r--r--src/libstd/sys/sgx/stdio.rs18
-rw-r--r--src/libstd/sys/unix/time.rs27
-rw-r--r--src/libstd/sys/wasi/fs.rs173
-rw-r--r--src/libstd/sys/windows/time.rs24
-rw-r--r--src/libstd/sys_common/os_str_bytes.rs2
13 files changed, 187 insertions, 153 deletions
diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml
index 875483518e8..86ad334d886 100644
--- a/src/libstd/Cargo.toml
+++ b/src/libstd/Cargo.toml
@@ -19,7 +19,7 @@ panic_unwind = { path = "../libpanic_unwind", optional = true }
 panic_abort = { path = "../libpanic_abort" }
 core = { path = "../libcore" }
 libc = { version = "0.2.51", default-features = false, features = ['rustc-dep-of-std'] }
-compiler_builtins = { version = "0.1.8" }
+compiler_builtins = { version = "0.1.9" }
 profiler_builtins = { path = "../libprofiler_builtins", optional = true }
 unwind = { path = "../libunwind" }
 rustc-demangle = { version = "0.1.10", features = ['rustc-dep-of-std'] }
diff --git a/src/libstd/collections/hash/set.rs b/src/libstd/collections/hash/set.rs
index 89d5b2ff30f..b9fcc2365fa 100644
--- a/src/libstd/collections/hash/set.rs
+++ b/src/libstd/collections/hash/set.rs
@@ -627,7 +627,11 @@ impl<T, S> HashSet<T, S>
     /// ```
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn is_subset(&self, other: &HashSet<T, S>) -> bool {
-        self.iter().all(|v| other.contains(v))
+        if self.len() <= other.len() {
+            self.iter().all(|v| other.contains(v))
+        } else {
+            false
+        }
     }
 
     /// Returns `true` if the set is a superset of another,
diff --git a/src/libstd/f32.rs b/src/libstd/f32.rs
index 2952c6aea00..133540ed6b9 100644
--- a/src/libstd/f32.rs
+++ b/src/libstd/f32.rs
@@ -193,11 +193,11 @@ impl f32 {
     }
 
     /// Returns a number composed of the magnitude of `self` and the sign of
-    /// `y`.
+    /// `sign`.
     ///
-    /// Equal to `self` if the sign of `self` and `y` are the same, otherwise
+    /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
     /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
-    /// `y` is returned.
+    /// `sign` is returned.
     ///
     /// # Examples
     ///
@@ -216,8 +216,8 @@ impl f32 {
     #[inline]
     #[must_use]
     #[stable(feature = "copysign", since = "1.35.0")]
-    pub fn copysign(self, y: f32) -> f32 {
-        unsafe { intrinsics::copysignf32(self, y) }
+    pub fn copysign(self, sign: f32) -> f32 {
+        unsafe { intrinsics::copysignf32(self, sign) }
     }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
diff --git a/src/libstd/f64.rs b/src/libstd/f64.rs
index 3c3a35573ad..87467aeed8b 100644
--- a/src/libstd/f64.rs
+++ b/src/libstd/f64.rs
@@ -171,11 +171,11 @@ impl f64 {
     }
 
     /// Returns a number composed of the magnitude of `self` and the sign of
-    /// `y`.
+    /// `sign`.
     ///
-    /// Equal to `self` if the sign of `self` and `y` are the same, otherwise
+    /// Equal to `self` if the sign of `self` and `sign` are the same, otherwise
     /// equal to `-self`. If `self` is a `NAN`, then a `NAN` with the sign of
-    /// `y` is returned.
+    /// `sign` is returned.
     ///
     /// # Examples
     ///
@@ -194,8 +194,8 @@ impl f64 {
     #[inline]
     #[must_use]
     #[stable(feature = "copysign", since = "1.35.0")]
-    pub fn copysign(self, y: f64) -> f64 {
-        unsafe { intrinsics::copysignf64(self, y) }
+    pub fn copysign(self, sign: f64) -> f64 {
+        unsafe { intrinsics::copysignf64(self, sign) }
     }
 
     /// Fused multiply-add. Computes `(self * a) + b` with only one rounding
diff --git a/src/libstd/ffi/os_str.rs b/src/libstd/ffi/os_str.rs
index 01e7a57cd00..13aee783750 100644
--- a/src/libstd/ffi/os_str.rs
+++ b/src/libstd/ffi/os_str.rs
@@ -960,6 +960,7 @@ impl IntoInner<Buf> for OsString {
 }
 
 impl AsInner<Slice> for OsStr {
+    #[inline]
     fn as_inner(&self) -> &Slice {
         &self.inner
     }
diff --git a/src/libstd/sys/sgx/alloc.rs b/src/libstd/sys/sgx/alloc.rs
index 98eb8397436..b385d567dd8 100644
--- a/src/libstd/sys/sgx/alloc.rs
+++ b/src/libstd/sys/sgx/alloc.rs
@@ -1,4 +1,4 @@
-use crate::alloc::{GlobalAlloc, Layout, System};
+use crate::alloc::{self, GlobalAlloc, Layout, System};
 
 use super::waitqueue::SpinMutex;
 
@@ -30,3 +30,17 @@ unsafe impl GlobalAlloc for System {
         DLMALLOC.lock().realloc(ptr, layout.size(), layout.align(), new_size)
     }
 }
+
+// The following functions are needed by libunwind. These symbols are named
+// in pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
+    alloc::alloc(Layout::from_size_align_unchecked(size, align))
+}
+
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
+    alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
+}
diff --git a/src/libstd/sys/sgx/mod.rs b/src/libstd/sys/sgx/mod.rs
index b0679f65f0d..a99a534f41e 100644
--- a/src/libstd/sys/sgx/mod.rs
+++ b/src/libstd/sys/sgx/mod.rs
@@ -130,6 +130,15 @@ pub unsafe fn abort_internal() -> ! {
     abi::usercalls::exit(true)
 }
 
+// This function is needed by the panic runtime. The symbol is named in
+// pre-link args for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+// NB. used by both libunwind and libpanic_abort
+pub unsafe extern "C" fn __rust_abort() {
+    abort_internal();
+}
+
 pub fn hashmap_random_keys() -> (u64, u64) {
     fn rdrand64() -> u64 {
         unsafe {
diff --git a/src/libstd/sys/sgx/rwlock.rs b/src/libstd/sys/sgx/rwlock.rs
index 09b5ffb1996..30c47e44eef 100644
--- a/src/libstd/sys/sgx/rwlock.rs
+++ b/src/libstd/sys/sgx/rwlock.rs
@@ -1,10 +1,4 @@
-#[cfg(not(test))]
-use crate::alloc::{self, Layout};
 use crate::num::NonZeroUsize;
-#[cfg(not(test))]
-use crate::slice;
-#[cfg(not(test))]
-use crate::str;
 
 use super::waitqueue::{
     try_lock_or_false, NotifiedTcs, SpinMutex, SpinMutexGuard, WaitQueue, WaitVariable,
@@ -165,10 +159,11 @@ impl RWLock {
     pub unsafe fn destroy(&self) {}
 }
 
+// The following functions are needed by libunwind. These symbols are named
+// in pre-link args for the target specification, so keep that in sync.
 #[cfg(not(test))]
 const EINVAL: i32 = 22;
 
-// used by libunwind port
 #[cfg(not(test))]
 #[no_mangle]
 pub unsafe extern "C" fn __rust_rwlock_rdlock(p: *mut RWLock) -> i32 {
@@ -198,39 +193,6 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 {
     return 0;
 }
 
-// the following functions are also used by the libunwind port. They're
-// included here to make sure parallel codegen and LTO don't mess things up.
-#[cfg(not(test))]
-#[no_mangle]
-pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
-    if s < 0 {
-        return;
-    }
-    let buf = slice::from_raw_parts(m as *const u8, s as _);
-    if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
-        eprint!("{}", s);
-    }
-}
-
-#[cfg(not(test))]
-#[no_mangle]
-// NB. used by both libunwind and libpanic_abort
-pub unsafe extern "C" fn __rust_abort() {
-    crate::sys::abort_internal();
-}
-
-#[cfg(not(test))]
-#[no_mangle]
-pub unsafe extern "C" fn __rust_c_alloc(size: usize, align: usize) -> *mut u8 {
-    alloc::alloc(Layout::from_size_align_unchecked(size, align))
-}
-
-#[cfg(not(test))]
-#[no_mangle]
-pub unsafe extern "C" fn __rust_c_dealloc(ptr: *mut u8, size: usize, align: usize) {
-    alloc::dealloc(ptr, Layout::from_size_align_unchecked(size, align))
-}
-
 #[cfg(test)]
 mod tests {
     use super::*;
diff --git a/src/libstd/sys/sgx/stdio.rs b/src/libstd/sys/sgx/stdio.rs
index f2c6892bfb7..a575401f5f6 100644
--- a/src/libstd/sys/sgx/stdio.rs
+++ b/src/libstd/sys/sgx/stdio.rs
@@ -2,6 +2,10 @@ use fortanix_sgx_abi as abi;
 
 use crate::io;
 use crate::sys::fd::FileDesc;
+#[cfg(not(test))]
+use crate::slice;
+#[cfg(not(test))]
+use crate::str;
 
 pub struct Stdin(());
 pub struct Stdout(());
@@ -62,3 +66,17 @@ pub fn is_ebadf(err: &io::Error) -> bool {
 pub fn panic_output() -> Option<impl io::Write> {
     super::abi::panic::SgxPanicOutput::new()
 }
+
+// This function is needed by libunwind. The symbol is named in pre-link args
+// for the target specification, so keep that in sync.
+#[cfg(not(test))]
+#[no_mangle]
+pub unsafe extern "C" fn __rust_print_err(m: *mut u8, s: i32) {
+    if s < 0 {
+        return;
+    }
+    let buf = slice::from_raw_parts(m as *const u8, s as _);
+    if let Ok(s) = str::from_utf8(&buf[..buf.iter().position(|&b| b == 0).unwrap_or(buf.len())]) {
+        eprint!("{}", s);
+    }
+}
diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs
index 127ae6aa104..e21c32cd91b 100644
--- a/src/libstd/sys/unix/time.rs
+++ b/src/libstd/sys/unix/time.rs
@@ -114,7 +114,8 @@ impl Hash for Timespec {
 #[cfg(any(target_os = "macos", target_os = "ios"))]
 mod inner {
     use crate::fmt;
-    use crate::sync::Once;
+    use crate::mem;
+    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
     use crate::sys::cvt;
     use crate::sys_common::mul_div_u64;
     use crate::time::Duration;
@@ -229,18 +230,30 @@ mod inner {
         Some(mul_div_u64(nanos, info.denom as u64, info.numer as u64))
     }
 
-    fn info() -> &'static libc::mach_timebase_info {
+    fn info() -> libc::mach_timebase_info {
         static mut INFO: libc::mach_timebase_info = libc::mach_timebase_info {
             numer: 0,
             denom: 0,
         };
-        static ONCE: Once = Once::new();
+        static STATE: AtomicUsize = AtomicUsize::new(0);
 
         unsafe {
-            ONCE.call_once(|| {
-                libc::mach_timebase_info(&mut INFO);
-            });
-            &INFO
+            // If a previous thread has filled in this global state, use that.
+            if STATE.load(SeqCst) == 2 {
+                return INFO;
+            }
+
+            // ... otherwise learn for ourselves ...
+            let mut info = mem::zeroed();
+            libc::mach_timebase_info(&mut info);
+
+            // ... and attempt to be the one thread that stores it globally for
+            // all other threads
+            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
+                INFO = info;
+                STATE.store(2, SeqCst);
+            }
+            return info;
         }
     }
 }
diff --git a/src/libstd/sys/wasi/fs.rs b/src/libstd/sys/wasi/fs.rs
index 7b1c2bd79cc..589593299d6 100644
--- a/src/libstd/sys/wasi/fs.rs
+++ b/src/libstd/sys/wasi/fs.rs
@@ -1,5 +1,4 @@
-use crate::collections::HashMap;
-use crate::ffi::{OsStr, OsString};
+use crate::ffi::{CStr, CString, OsStr, OsString};
 use crate::fmt;
 use crate::io::{self, IoVec, IoVecMut, SeekFrom};
 use crate::iter;
@@ -7,11 +6,10 @@ use crate::mem::{self, ManuallyDrop};
 use crate::os::wasi::ffi::{OsStrExt, OsStringExt};
 use crate::path::{Path, PathBuf};
 use crate::ptr;
-use crate::sync::atomic::{AtomicPtr, Ordering::SeqCst};
 use crate::sync::Arc;
 use crate::sys::fd::{DirCookie, WasiFd};
 use crate::sys::time::SystemTime;
-use crate::sys::{cvt_wasi, unsupported};
+use crate::sys::unsupported;
 use crate::sys_common::FromInner;
 
 pub use crate::sys_common::fs::copy;
@@ -230,7 +228,11 @@ impl DirEntry {
     }
 
     pub fn metadata(&self) -> io::Result<FileAttr> {
-        metadata_at(&self.inner.dir.fd, 0, OsStr::from_bytes(&self.name).as_ref())
+        metadata_at(
+            &self.inner.dir.fd,
+            0,
+            OsStr::from_bytes(&self.name).as_ref(),
+        )
     }
 
     pub fn file_type(&self) -> io::Result<FileType> {
@@ -377,8 +379,8 @@ impl OpenOptions {
 
 impl File {
     pub fn open(path: &Path, opts: &OpenOptions) -> io::Result<File> {
-        let (dir, file) = open_parent(path)?;
-        open_at(&dir, file, opts)
+        let (dir, file) = open_parent(path, libc::__WASI_RIGHT_PATH_OPEN)?;
+        open_at(&dir, &file, opts)
     }
 
     pub fn open_at(&self, path: &Path, opts: &OpenOptions) -> io::Result<File> {
@@ -475,7 +477,7 @@ impl DirBuilder {
     }
 
     pub fn mkdir(&self, p: &Path) -> io::Result<()> {
-        let (dir, file) = open_parent(p)?;
+        let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_CREATE_DIRECTORY)?;
         dir.create_directory(file.as_os_str().as_bytes())
     }
 }
@@ -506,13 +508,13 @@ pub fn readdir(p: &Path) -> io::Result<ReadDir> {
 }
 
 pub fn unlink(p: &Path) -> io::Result<()> {
-    let (dir, file) = open_parent(p)?;
+    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_UNLINK_FILE)?;
     dir.unlink_file(file.as_os_str().as_bytes())
 }
 
 pub fn rename(old: &Path, new: &Path) -> io::Result<()> {
-    let (old, old_file) = open_parent(old)?;
-    let (new, new_file) = open_parent(new)?;
+    let (old, old_file) = open_parent(old, libc::__WASI_RIGHT_PATH_RENAME_SOURCE)?;
+    let (new, new_file) = open_parent(new, libc::__WASI_RIGHT_PATH_RENAME_TARGET)?;
     old.rename(
         old_file.as_os_str().as_bytes(),
         &new,
@@ -527,13 +529,13 @@ pub fn set_perm(_p: &Path, _perm: FilePermissions) -> io::Result<()> {
 }
 
 pub fn rmdir(p: &Path) -> io::Result<()> {
-    let (dir, file) = open_parent(p)?;
+    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_REMOVE_DIRECTORY)?;
     dir.remove_directory(file.as_os_str().as_bytes())
 }
 
 pub fn readlink(p: &Path) -> io::Result<PathBuf> {
-    let (dir, file) = open_parent(p)?;
-    read_link(&dir, file)
+    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_READLINK)?;
+    read_link(&dir, &file)
 }
 
 fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
@@ -568,13 +570,13 @@ fn read_link(fd: &WasiFd, file: &Path) -> io::Result<PathBuf> {
 }
 
 pub fn symlink(src: &Path, dst: &Path) -> io::Result<()> {
-    let (dst, dst_file) = open_parent(dst)?;
+    let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_SYMLINK)?;
     dst.symlink(src.as_os_str().as_bytes(), dst_file.as_os_str().as_bytes())
 }
 
 pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
-    let (src, src_file) = open_parent(src)?;
-    let (dst, dst_file) = open_parent(dst)?;
+    let (src, src_file) = open_parent(src, libc::__WASI_RIGHT_PATH_LINK_SOURCE)?;
+    let (dst, dst_file) = open_parent(dst, libc::__WASI_RIGHT_PATH_LINK_TARGET)?;
     src.link(
         libc::__WASI_LOOKUP_SYMLINK_FOLLOW,
         src_file.as_os_str().as_bytes(),
@@ -584,13 +586,13 @@ pub fn link(src: &Path, dst: &Path) -> io::Result<()> {
 }
 
 pub fn stat(p: &Path) -> io::Result<FileAttr> {
-    let (dir, file) = open_parent(p)?;
-    metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, file)
+    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?;
+    metadata_at(&dir, libc::__WASI_LOOKUP_SYMLINK_FOLLOW, &file)
 }
 
 pub fn lstat(p: &Path) -> io::Result<FileAttr> {
-    let (dir, file) = open_parent(p)?;
-    metadata_at(&dir, 0, file)
+    let (dir, file) = open_parent(p, libc::__WASI_RIGHT_PATH_FILESTAT_GET)?;
+    metadata_at(&dir, 0, &file)
 }
 
 fn metadata_at(
@@ -621,72 +623,69 @@ fn open_at(fd: &WasiFd, path: &Path, opts: &OpenOptions) -> io::Result<File> {
     Ok(File { fd })
 }
 
-// FIXME: we shouldn't implement this. It'd be much better to share this between
-// libc (the wasi-sysroot) and Rust as the logic here is likely far more tricky
-// than what we're executing below. For now this is a stopgap to enable this
-// module, but we should add an official API in upstream wasi-libc which looks
-// like this.
-//
-// In the meantime this is highly unlikely to be correct. It allows some basic
-// testing but is not at all robust.
-fn open_parent(p: &Path) -> io::Result<(&'static WasiFd, &Path)> {
-    let map = preopened_map();
-    for ancestor in p.ancestors() {
-        if let Some(fd) = map.get(ancestor) {
-            let tail = p.strip_prefix(ancestor).unwrap();
-            let tail = if tail == Path::new("") {
-                ".".as_ref()
-            } else {
-                tail
-            };
-            return Ok((fd, tail))
-        }
-    }
-    let msg = format!("failed to find a preopened file descriptor to open {:?}", p);
-    return Err(io::Error::new(io::ErrorKind::Other, msg));
-
-    type Preopened = HashMap<PathBuf, ManuallyDrop<WasiFd>>;
-    fn preopened_map() -> &'static Preopened {
-        static PTR: AtomicPtr<Preopened> = AtomicPtr::new(ptr::null_mut());
-        unsafe {
-            let ptr = PTR.load(SeqCst);
-            if !ptr.is_null() {
-                return &*ptr;
-            }
-
-            let mut map = Box::new(HashMap::new());
-            for fd in 3.. {
-                let mut buf = mem::zeroed();
-                if cvt_wasi(libc::__wasi_fd_prestat_get(fd, &mut buf)).is_err() {
-                    break;
-                }
-                if buf.pr_type != libc::__WASI_PREOPENTYPE_DIR {
-                    continue;
-                }
-                let len = buf.u.dir.pr_name_len;
-                let mut v = vec![0u8; len];
-                let res = cvt_wasi(libc::__wasi_fd_prestat_dir_name(
-                    fd,
-                    v.as_mut_ptr() as *mut i8,
-                    v.len(),
-                ));
-                if res.is_err() {
-                    continue;
-                }
-                let path = PathBuf::from(OsString::from_vec(v));
-                map.insert(path, ManuallyDrop::new(WasiFd::from_raw(fd)));
-            }
-            let ptr = Box::into_raw(map);
-            match PTR.compare_exchange(ptr::null_mut(), ptr, SeqCst, SeqCst) {
-                Ok(_) => &*ptr,
-
-                // If we lost the race for initialization clean up the map we
-                // made and just use the one that's already there
-                Err(other) => {
-                    drop(Box::from_raw(ptr));
-                    &*other
-                }
-            }
+/// Attempts to open a bare path `p`.
+///
+/// WASI has no fundamental capability to do this. All syscalls and operations
+/// are relative to already-open file descriptors. The C library, however,
+/// manages a map of preopened file descriptors to their path, and then the C
+/// library provides an API to look at this. In other words, when you want to
+/// open a path `p`, you have to find a previously opened file descriptor in a
+/// global table and then see if `p` is relative to that file descriptor.
+///
+/// This function, if successful, will return two items:
+///
+/// * The first is a `ManuallyDrop<WasiFd>`. This represents a preopened file
+///   descriptor which we don't have ownership of, but we can use. You shouldn't
+///   actually drop the `fd`.
+///
+/// * The second is a path that should be a part of `p` and represents a
+///   relative traversal from the file descriptor specified to the desired
+///   location `p`.
+///
+/// If successful you can use the returned file descriptor to perform
+/// file-descriptor-relative operations on the path returned as well. The
+/// `rights` argument indicates what operations are desired on the returned file
+/// descriptor, and if successful the returned file descriptor should have the
+/// appropriate rights for performing `rights` actions.
+///
+/// Note that this can fail if `p` doesn't look like it can be opened relative
+/// to any preopened file descriptor.
+fn open_parent(
+    p: &Path,
+    rights: libc::__wasi_rights_t,
+) -> io::Result<(ManuallyDrop<WasiFd>, PathBuf)> {
+    let p = CString::new(p.as_os_str().as_bytes())?;
+    unsafe {
+        let mut ret = ptr::null();
+        let fd = __wasilibc_find_relpath(p.as_ptr(), rights, 0, &mut ret);
+        if fd == -1 {
+            let msg = format!(
+                "failed to find a preopened file descriptor \
+                 through which {:?} could be opened",
+                p
+            );
+            return Err(io::Error::new(io::ErrorKind::Other, msg));
         }
+        let path = Path::new(OsStr::from_bytes(CStr::from_ptr(ret).to_bytes()));
+
+        // FIXME: right now `path` is a pointer into `p`, the `CString` above.
+        // When we return `p` is deallocated and we can't use it, so we need to
+        // currently separately allocate `path`. If this becomes an issue though
+        // we should probably turn this into a closure-taking interface or take
+        // `&CString` and then pass off `&Path` tied to the same lifetime.
+        let path = path.to_path_buf();
+
+        return Ok((ManuallyDrop::new(WasiFd::from_raw(fd as u32)), path));
+    }
+
+    // FIXME(rust-lang/libc#1314) use the `libc` crate for this when the API
+    // there is published
+    extern "C" {
+        pub fn __wasilibc_find_relpath(
+            path: *const libc::c_char,
+            rights_base: libc::__wasi_rights_t,
+            rights_inheriting: libc::__wasi_rights_t,
+            relative_path: *mut *const libc::c_char,
+        ) -> libc::c_int;
     }
 }
diff --git a/src/libstd/sys/windows/time.rs b/src/libstd/sys/windows/time.rs
index 4c9d2aee157..e0f0e3a1a45 100644
--- a/src/libstd/sys/windows/time.rs
+++ b/src/libstd/sys/windows/time.rs
@@ -173,7 +173,7 @@ fn intervals2dur(intervals: u64) -> Duration {
 
 mod perf_counter {
     use super::{NANOS_PER_SEC};
-    use crate::sync::Once;
+    use crate::sync::atomic::{AtomicUsize, Ordering::SeqCst};
     use crate::sys_common::mul_div_u64;
     use crate::sys::c;
     use crate::sys::cvt;
@@ -210,13 +210,25 @@ mod perf_counter {
 
     fn frequency() -> c::LARGE_INTEGER {
         static mut FREQUENCY: c::LARGE_INTEGER = 0;
-        static ONCE: Once = Once::new();
+        static STATE: AtomicUsize = AtomicUsize::new(0);
 
         unsafe {
-            ONCE.call_once(|| {
-                cvt(c::QueryPerformanceFrequency(&mut FREQUENCY)).unwrap();
-            });
-            FREQUENCY
+            // If a previous thread has filled in this global state, use that.
+            if STATE.load(SeqCst) == 2 {
+                return FREQUENCY;
+            }
+
+            // ... otherwise learn for ourselves ...
+            let mut frequency = 0;
+            cvt(c::QueryPerformanceFrequency(&mut frequency)).unwrap();
+
+            // ... and attempt to be the one thread that stores it globally for
+            // all other threads
+            if STATE.compare_exchange(0, 1, SeqCst, SeqCst).is_ok() {
+                FREQUENCY = frequency;
+                STATE.store(2, SeqCst);
+            }
+            return frequency;
         }
     }
 
diff --git a/src/libstd/sys_common/os_str_bytes.rs b/src/libstd/sys_common/os_str_bytes.rs
index 7cc93477a73..a4961974d89 100644
--- a/src/libstd/sys_common/os_str_bytes.rs
+++ b/src/libstd/sys_common/os_str_bytes.rs
@@ -236,9 +236,11 @@ pub trait OsStrExt {
 
 #[stable(feature = "rust1", since = "1.0.0")]
 impl OsStrExt for OsStr {
+    #[inline]
     fn from_bytes(slice: &[u8]) -> &OsStr {
         unsafe { mem::transmute(slice) }
     }
+    #[inline]
     fn as_bytes(&self) -> &[u8] {
         &self.as_inner().inner
     }