diff options
| author | Djzin <djzin@users.noreply.github.com> | 2017-05-27 14:31:47 +0100 |
|---|---|---|
| committer | Djzin <djzin@users.noreply.github.com> | 2017-05-27 14:31:47 +0100 |
| commit | 74751358e625878306aa193fed788e79aa53d4fa (patch) | |
| tree | 1ba9b336d1ddb45d9f688d69f5bd4ede028db622 /src/libstd/sys | |
| parent | c6307a2fa55c3d62c06b85b349257a8194093442 (diff) | |
| parent | 3e7908f616745573a11ad7dfad245f12be0069da (diff) | |
| download | rust-74751358e625878306aa193fed788e79aa53d4fa.tar.gz rust-74751358e625878306aa193fed788e79aa53d4fa.zip | |
Merge remote-tracking branch 'upstream/master' into fast-swap
Diffstat (limited to 'src/libstd/sys')
31 files changed, 619 insertions, 325 deletions
diff --git a/src/libstd/sys/redox/fast_thread_local.rs b/src/libstd/sys/redox/fast_thread_local.rs index 6eeae2d90ea..7dc61ce6654 100644 --- a/src/libstd/sys/redox/fast_thread_local.rs +++ b/src/libstd/sys/redox/fast_thread_local.rs @@ -12,9 +12,10 @@ #![unstable(feature = "thread_local_internals", issue = "0")] use cell::{Cell, UnsafeCell}; -use intrinsics; +use mem; use ptr; + pub struct Key<T> { inner: UnsafeCell<Option<T>>, @@ -37,7 +38,7 @@ impl<T> Key<T> { pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { unsafe { - if intrinsics::needs_drop::<T>() && self.dtor_running.get() { + if mem::needs_drop::<T>() && self.dtor_running.get() { return None } self.register_dtor(); @@ -46,7 +47,7 @@ impl<T> Key<T> { } unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() { + if !mem::needs_drop::<T>() || self.dtor_registered.get() { return } @@ -96,17 +97,17 @@ pub unsafe extern fn destroy_value<T>(ptr: *mut u8) { // `None`. (*ptr).dtor_running.set(true); - // The OSX implementation of TLS apparently had an odd aspect to it + // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor // is running. Specifically if a TLS destructor re-accesses TLS it may // trigger a re-initialization of all TLS variables, paving over at // least some destroyed ones with initial values. // - // This means that if we drop a TLS value in place on OSX that we could + // This means that if we drop a TLS value in place on macOS that we could // revert the value to its original state halfway through the // destructor, which would be bad! // - // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // Hence, we use `ptr::read` on macOS (to move to a "safe" location) // instead of drop_in_place. if cfg!(target_os = "macos") { ptr::read((*ptr).inner.get()); diff --git a/src/libstd/sys/redox/os_str.rs b/src/libstd/sys/redox/os_str.rs index 474d59eed83..c2bba07f68c 100644 --- a/src/libstd/sys/redox/os_str.rs +++ b/src/libstd/sys/redox/os_str.rs @@ -104,6 +104,12 @@ impl Buf { 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() } + } } impl Slice { diff --git a/src/libstd/sys/redox/process.rs b/src/libstd/sys/redox/process.rs index 60dc03fcf47..95e9438cd71 100644 --- a/src/libstd/sys/redox/process.rs +++ b/src/libstd/sys/redox/process.rs @@ -249,7 +249,7 @@ impl Command { // mutex, and then after the fork they unlock it. // // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but // all collected backtraces point at malloc/free traffic in the // child spawned process. // @@ -270,19 +270,22 @@ impl Command { } if let Some(fd) = stdio.stderr.fd() { - let _ = syscall::close(2); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 2, &[]))); + let mut flags = t!(cvt(syscall::fcntl(2, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(2, syscall::F_SETFL, flags))); } if let Some(fd) = stdio.stdout.fd() { - let _ = syscall::close(1); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 1, &[]))); + let mut flags = t!(cvt(syscall::fcntl(1, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(1, syscall::F_SETFL, flags))); } if let Some(fd) = stdio.stdin.fd() { - let _ = syscall::close(0); - t!(cvt(syscall::dup(fd, &[]))); - let _ = syscall::close(fd); + t!(cvt(syscall::dup2(fd, 0, &[]))); + let mut flags = t!(cvt(syscall::fcntl(0, syscall::F_GETFL, 0))); + flags &= ! syscall::O_CLOEXEC; + t!(cvt(syscall::fcntl(0, syscall::F_SETFL, flags))); } if let Some(g) = self.gid { diff --git a/src/libstd/sys/redox/syscall/call.rs b/src/libstd/sys/redox/syscall/call.rs index f58c240f31e..fadf7325d75 100644 --- a/src/libstd/sys/redox/syscall/call.rs +++ b/src/libstd/sys/redox/syscall/call.rs @@ -71,6 +71,11 @@ pub fn dup(fd: usize, buf: &[u8]) -> Result<usize> { unsafe { syscall3(SYS_DUP, fd, buf.as_ptr() as usize, buf.len()) } } +/// Copy and transform a file descriptor +pub fn dup2(fd: usize, newfd: usize, buf: &[u8]) -> Result<usize> { + unsafe { syscall4(SYS_DUP2, fd, newfd, buf.as_ptr() as usize, buf.len()) } +} + /// Replace the current process with a new executable pub fn execve(path: &str, args: &[[usize; 2]]) -> Result<usize> { unsafe { syscall4(SYS_EXECVE, path.as_ptr() as usize, path.len(), diff --git a/src/libstd/sys/redox/syscall/number.rs b/src/libstd/sys/redox/syscall/number.rs index 358746cd20a..98f8b73e4e1 100644 --- a/src/libstd/sys/redox/syscall/number.rs +++ b/src/libstd/sys/redox/syscall/number.rs @@ -28,6 +28,7 @@ pub const SYS_UNLINK: usize = SYS_CLASS_PATH | 10; pub const SYS_CLOSE: usize = SYS_CLASS_FILE | 6; pub const SYS_DUP: usize = SYS_CLASS_FILE | SYS_RET_FILE | 41; +pub const SYS_DUP2: usize = SYS_CLASS_FILE | SYS_RET_FILE | 63; pub const SYS_READ: usize = SYS_CLASS_FILE | SYS_ARG_MSLICE | 3; pub const SYS_WRITE: usize = SYS_CLASS_FILE | SYS_ARG_SLICE | 4; pub const SYS_LSEEK: usize = SYS_CLASS_FILE | 19; diff --git a/src/libstd/sys/redox/thread_local.rs b/src/libstd/sys/redox/thread_local.rs index abdd9ace795..cacd84e2102 100644 --- a/src/libstd/sys/redox/thread_local.rs +++ b/src/libstd/sys/redox/thread_local.rs @@ -64,3 +64,8 @@ pub unsafe fn set(key: Key, value: *mut u8) { pub unsafe fn destroy(key: Key) { keys().remove(&key); } + +#[inline] +pub fn requires_synchronized_create() -> bool { + false +} diff --git a/src/libstd/sys/unix/backtrace/mod.rs b/src/libstd/sys/unix/backtrace/mod.rs index 29d4012dcdf..bf52da2ed4a 100644 --- a/src/libstd/sys/unix/backtrace/mod.rs +++ b/src/libstd/sys/unix/backtrace/mod.rs @@ -13,7 +13,7 @@ /// Some methods of getting a backtrace: /// /// * The backtrace() functions on unix. It turns out this doesn't work very -/// well for green threads on OSX, and the address to symbol portion of it +/// well for green threads on macOS, and the address to symbol portion of it /// suffers problems that are described below. /// /// * Using libunwind. This is more difficult than it sounds because libunwind @@ -51,9 +51,9 @@ /// /// * Use dladdr(). The original backtrace()-based idea actually uses dladdr() /// behind the scenes to translate, and this is why backtrace() was not used. -/// Conveniently, this method works fantastically on OSX. It appears dladdr() +/// Conveniently, this method works fantastically on macOS. It appears dladdr() /// uses magic to consult the local symbol table, or we're putting everything -/// in the dynamic symbol table anyway. Regardless, for OSX, this is the +/// in the dynamic symbol table anyway. Regardless, for macOS, this is the /// method used for translation. It's provided by the system and easy to do.o /// /// Sadly, all other systems have a dladdr() implementation that does not @@ -75,7 +75,7 @@ /// * Use `libbacktrace`. It turns out that this is a small library bundled in /// the gcc repository which provides backtrace and symbol translation /// functionality. All we really need from it is the backtrace functionality, -/// and we only really need this on everything that's not OSX, so this is the +/// and we only really need this on everything that's not macOS, so this is the /// chosen route for now. /// /// In summary, the current situation uses libgcc_s to get a trace of stack diff --git a/src/libstd/sys/unix/ext/net.rs b/src/libstd/sys/unix/ext/net.rs index 1ba4a104e51..d688f2fa504 100644 --- a/src/libstd/sys/unix/ext/net.rs +++ b/src/libstd/sys/unix/ext/net.rs @@ -204,7 +204,7 @@ impl SocketAddr { let len = self.len as usize - sun_path_offset(); let path = unsafe { mem::transmute::<&[libc::c_char], &[u8]>(&self.addr.sun_path) }; - // OSX seems to return a len of 16 and a zeroed sun_path for unnamed addresses + // macOS seems to return a len of 16 and a zeroed sun_path for unnamed addresses if len == 0 || (cfg!(not(target_os = "linux")) && self.addr.sun_path[0] == 0) { AddressKind::Unnamed } else if self.addr.sun_path[0] == 0 { @@ -375,12 +375,12 @@ impl UnixStream { /// Sets the read timeout for the socket. /// - /// If the provided value is [`None`], then [`read()`] calls will block + /// If the provided value is [`None`], then [`read`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../../../std/io/trait.Read.html#tymethod.read + /// [`read`]: ../../../../std/io/trait.Read.html#tymethod.read /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -399,12 +399,12 @@ impl UnixStream { /// Sets the write timeout for the socket. /// - /// If the provided value is [`None`], then [`write()`] calls will block + /// If the provided value is [`None`], then [`write`] calls will block /// indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`read()`]: ../../../../std/io/trait.Write.html#tymethod.write + /// [`read`]: ../../../../std/io/trait.Write.html#tymethod.write /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -641,7 +641,7 @@ impl UnixListener { let inner = Socket::new_raw(libc::AF_UNIX, libc::SOCK_STREAM)?; let (addr, len) = sockaddr_un(path)?; - cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::bind(*inner.as_inner(), &addr as *const _ as *const _, len as _))?; cvt(libc::listen(*inner.as_inner(), 128))?; Ok(UnixListener(inner)) @@ -920,7 +920,7 @@ impl UnixDatagram { let socket = UnixDatagram::unbound()?; let (addr, len) = sockaddr_un(path)?; - cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len))?; + cvt(libc::bind(*socket.0.as_inner(), &addr as *const _ as *const _, len as _))?; Ok(socket) } @@ -974,12 +974,12 @@ impl UnixDatagram { /// Connects the socket to the specified address. /// - /// The [`send()`] method may be used to send data to the specified address. - /// [`recv()`] and [`recv_from()`] will only receive data from that address. + /// The [`send`] method may be used to send data to the specified address. + /// [`recv`] and [`recv_from`] will only receive data from that address. /// - /// [`send()`]: #method.send - /// [`recv()`]: #method.recv - /// [`recv_from()`]: #method.recv_from + /// [`send`]: #method.send + /// [`recv`]: #method.recv + /// [`recv_from`]: #method.recv_from /// /// # Examples /// @@ -1047,9 +1047,9 @@ impl UnixDatagram { /// Returns the address of this socket's peer. /// - /// The [`connect()`] method will connect the socket to a peer. + /// The [`connect`] method will connect the socket to a peer. /// - /// [`connect()`]: #method.connect + /// [`connect`]: #method.connect /// /// # Examples /// @@ -1178,13 +1178,13 @@ impl UnixDatagram { /// Sets the read timeout for the socket. /// - /// If the provided value is [`None`], then [`recv()`] and [`recv_from()`] calls will + /// If the provided value is [`None`], then [`recv`] and [`recv_from`] calls will /// block indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`recv()`]: #method.recv - /// [`recv_from()`]: #method.recv_from + /// [`recv`]: #method.recv + /// [`recv_from`]: #method.recv_from /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples @@ -1203,13 +1203,13 @@ impl UnixDatagram { /// Sets the write timeout for the socket. /// - /// If the provided value is [`None`], then [`send()`] and [`send_to()`] calls will + /// If the provided value is [`None`], then [`send`] and [`send_to`] calls will /// block indefinitely. It is an error to pass the zero [`Duration`] to this /// method. /// /// [`None`]: ../../../../std/option/enum.Option.html#variant.None - /// [`send()`]: #method.send - /// [`send_to()`]: #method.send_to + /// [`send`]: #method.send + /// [`send_to`]: #method.send_to /// [`Duration`]: ../../../../std/time/struct.Duration.html /// /// # Examples diff --git a/src/libstd/sys/unix/fast_thread_local.rs b/src/libstd/sys/unix/fast_thread_local.rs index f4f73646e1b..6b3973de84c 100644 --- a/src/libstd/sys/unix/fast_thread_local.rs +++ b/src/libstd/sys/unix/fast_thread_local.rs @@ -13,7 +13,7 @@ use cell::{Cell, UnsafeCell}; use fmt; -use intrinsics; +use mem; use ptr; pub struct Key<T> { @@ -44,7 +44,7 @@ impl<T> Key<T> { pub fn get(&'static self) -> Option<&'static UnsafeCell<Option<T>>> { unsafe { - if intrinsics::needs_drop::<T>() && self.dtor_running.get() { + if mem::needs_drop::<T>() && self.dtor_running.get() { return None } self.register_dtor(); @@ -53,7 +53,7 @@ impl<T> Key<T> { } unsafe fn register_dtor(&self) { - if !intrinsics::needs_drop::<T>() || self.dtor_registered.get() { + if !mem::needs_drop::<T>() || self.dtor_registered.get() { return } @@ -128,7 +128,7 @@ unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) { register_dtor_fallback(t, dtor); } -// OSX's analog of the above linux function is this _tlv_atexit function. +// macOS's analog of the above linux function is this _tlv_atexit function. // The disassembly of thread_local globals in C++ (at least produced by // clang) will have this show up in the output. #[cfg(target_os = "macos")] @@ -154,17 +154,17 @@ pub unsafe extern fn destroy_value<T>(ptr: *mut u8) { // `None`. (*ptr).dtor_running.set(true); - // The OSX implementation of TLS apparently had an odd aspect to it + // The macOS implementation of TLS apparently had an odd aspect to it // where the pointer we have may be overwritten while this destructor // is running. Specifically if a TLS destructor re-accesses TLS it may // trigger a re-initialization of all TLS variables, paving over at // least some destroyed ones with initial values. // - // This means that if we drop a TLS value in place on OSX that we could + // This means that if we drop a TLS value in place on macOS that we could // revert the value to its original state halfway through the // destructor, which would be bad! // - // Hence, we use `ptr::read` on OSX (to move to a "safe" location) + // Hence, we use `ptr::read` on macOS (to move to a "safe" location) // instead of drop_in_place. if cfg!(target_os = "macos") { ptr::read((*ptr).inner.get()); diff --git a/src/libstd/sys/unix/fd.rs b/src/libstd/sys/unix/fd.rs index c690fd467ee..405fac2b9d7 100644 --- a/src/libstd/sys/unix/fd.rs +++ b/src/libstd/sys/unix/fd.rs @@ -29,7 +29,7 @@ fn max_len() -> usize { // with the man page quoting that if the count of bytes to read is // greater than `SSIZE_MAX` the result is "unspecified". // - // On OSX, however, apparently the 64-bit libc is either buggy or + // On macOS, however, apparently the 64-bit libc is either buggy or // intentionally showing odd behavior by rejecting any read with a size // larger than or equal to INT_MAX. To handle both of these the read // size is capped on both platforms. diff --git a/src/libstd/sys/unix/fs.rs b/src/libstd/sys/unix/fs.rs index d0fb96b1ff1..e893a139094 100644 --- a/src/libstd/sys/unix/fs.rs +++ b/src/libstd/sys/unix/fs.rs @@ -439,7 +439,7 @@ impl File { // Linux kernel then the flag is just ignored by the OS, so we continue // to explicitly ask for a CLOEXEC fd here. // - // The CLOEXEC flag, however, is supported on versions of OSX/BSD/etc + // The CLOEXEC flag, however, is supported on versions of macOS/BSD/etc // that we support, so we only do this on Linux currently. if cfg!(target_os = "linux") { fd.set_cloexec()?; @@ -573,7 +573,7 @@ impl fmt::Debug for File { #[cfg(target_os = "macos")] fn get_path(fd: c_int) -> Option<PathBuf> { // FIXME: The use of PATH_MAX is generally not encouraged, but it - // is inevitable in this case because OS X defines `fcntl` with + // is inevitable in this case because macOS defines `fcntl` with // `F_GETPATH` in terms of `MAXPATHLEN`, and there are no // alternatives. If a better method is invented, it should be used // instead. diff --git a/src/libstd/sys/unix/mod.rs b/src/libstd/sys/unix/mod.rs index c57751a01d7..854d380d128 100644 --- a/src/libstd/sys/unix/mod.rs +++ b/src/libstd/sys/unix/mod.rs @@ -92,7 +92,7 @@ pub fn init() { #[cfg(not(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia")))] unsafe fn reset_sigpipe() { - assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != !0); + assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); } #[cfg(any(target_os = "nacl", target_os = "emscripten", target_os="fuchsia"))] unsafe fn reset_sigpipe() {} diff --git a/src/libstd/sys/unix/os.rs b/src/libstd/sys/unix/os.rs index 36928696c40..8e41fd009be 100644 --- a/src/libstd/sys/unix/os.rs +++ b/src/libstd/sys/unix/os.rs @@ -253,7 +253,12 @@ pub fn current_exe() -> io::Result<PathBuf> { #[cfg(any(target_os = "linux", target_os = "android", target_os = "emscripten"))] pub fn current_exe() -> io::Result<PathBuf> { - ::fs::read_link("/proc/self/exe") + let selfexe = PathBuf::from("/proc/self/exe"); + if selfexe.exists() { + ::fs::read_link(selfexe) + } else { + Err(io::Error::new(io::ErrorKind::Other, "no /proc/self/exe available. Is /proc mounted?")) + } } #[cfg(any(target_os = "macos", target_os = "ios"))] diff --git a/src/libstd/sys/unix/os_str.rs b/src/libstd/sys/unix/os_str.rs index c27599ec020..f5b942d3343 100644 --- a/src/libstd/sys/unix/os_str.rs +++ b/src/libstd/sys/unix/os_str.rs @@ -104,6 +104,12 @@ impl Buf { 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() } + } } impl Slice { diff --git a/src/libstd/sys/unix/pipe.rs b/src/libstd/sys/unix/pipe.rs index 51e00fc1ab9..706256ff10e 100644 --- a/src/libstd/sys/unix/pipe.rs +++ b/src/libstd/sys/unix/pipe.rs @@ -8,11 +8,9 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use cmp; use io; use libc::{self, c_int}; use mem; -use ptr; use sys::{cvt, cvt_r}; use sys::fd::FileDesc; @@ -80,16 +78,14 @@ pub fn read2(p1: AnonPipe, p1.set_nonblocking(true)?; p2.set_nonblocking(true)?; - let max = cmp::max(p1.raw(), p2.raw()); + let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() }; + fds[0].fd = p1.raw(); + fds[0].events = libc::POLLIN; + fds[1].fd = p2.raw(); + fds[1].events = libc::POLLIN; loop { - // wait for either pipe to become readable using `select` - cvt_r(|| unsafe { - let mut read: libc::fd_set = mem::zeroed(); - libc::FD_SET(p1.raw(), &mut read); - libc::FD_SET(p2.raw(), &mut read); - libc::select(max + 1, &mut read, ptr::null_mut(), ptr::null_mut(), - ptr::null_mut()) - })?; + // wait for either pipe to become readable using `poll` + cvt_r(|| unsafe { libc::poll(fds.as_mut_ptr(), 2, -1) })?; // Read as much as we can from each pipe, ignoring EWOULDBLOCK or // EAGAIN. If we hit EOF, then this will happen because the underlying @@ -109,11 +105,11 @@ pub fn read2(p1: AnonPipe, } } }; - if read(&p1, v1)? { + if fds[0].revents != 0 && read(&p1, v1)? { p2.set_nonblocking(false)?; return p2.read_to_end(v2).map(|_| ()); } - if read(&p2, v2)? { + if fds[1].revents != 0 && read(&p2, v2)? { p1.set_nonblocking(false)?; return p1.read_to_end(v1).map(|_| ()); } diff --git a/src/libstd/sys/unix/process/magenta.rs b/src/libstd/sys/unix/process/magenta.rs index 07f29784df6..5b5e29c0374 100644 --- a/src/libstd/sys/unix/process/magenta.rs +++ b/src/libstd/sys/unix/process/magenta.rs @@ -202,7 +202,7 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // ERR_NO_RESOURCES: The system was not able to allocate some resource // needed for the operation. -#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -5; +#[allow(unused)] pub const ERR_NO_RESOURCES: mx_status_t = -3; // ERR_NO_MEMORY: The system was not able to allocate memory needed // for the operation. @@ -210,30 +210,34 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // ERR_CALL_FAILED: The second phase of mx_channel_call(; did not complete // successfully. -#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -53; +#[allow(unused)] pub const ERR_CALL_FAILED: mx_status_t = -5; + +// ERR_INTERRUPTED_RETRY: The system call was interrupted, but should be +// retried. This should not be seen outside of the VDSO. +#[allow(unused)] pub const ERR_INTERRUPTED_RETRY: mx_status_t = -6; // ======= Parameter errors ======= // ERR_INVALID_ARGS: an argument is invalid, ex. null pointer #[allow(unused)] pub const ERR_INVALID_ARGS: mx_status_t = -10; +// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. +#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -11; + // ERR_WRONG_TYPE: The subject of the operation is the wrong type to // perform the operation. // Example: Attempting a message_read on a thread handle. -#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -54; +#[allow(unused)] pub const ERR_WRONG_TYPE: mx_status_t = -12; // ERR_BAD_SYSCALL: The specified syscall number is invalid. -#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -11; - -// ERR_BAD_HANDLE: A specified handle value does not refer to a handle. -#[allow(unused)] pub const ERR_BAD_HANDLE: mx_status_t = -12; +#[allow(unused)] pub const ERR_BAD_SYSCALL: mx_status_t = -13; // ERR_OUT_OF_RANGE: An argument is outside the valid range for this // operation. -#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -13; +#[allow(unused)] pub const ERR_OUT_OF_RANGE: mx_status_t = -14; // ERR_BUFFER_TOO_SMALL: A caller provided buffer is too small for // this operation. -#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -14; +#[allow(unused)] pub const ERR_BUFFER_TOO_SMALL: mx_status_t = -15; // ======= Precondition or state errors ======= // ERR_BAD_STATE: operation failed because the current state of the @@ -241,47 +245,48 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; // not satisfied #[allow(unused)] pub const ERR_BAD_STATE: mx_status_t = -20; +// ERR_TIMED_OUT: The time limit for the operation elapsed before +// the operation completed. +#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -21; + +// ERR_SHOULD_WAIT: The operation cannot be performed currently but +// potentially could succeed if the caller waits for a prerequisite +// to be satisfied, for example waiting for a handle to be readable +// or writable. +// Example: Attempting to read from a message pipe that has no +// messages waiting but has an open remote will return ERR_SHOULD_WAIT. +// Attempting to read from a message pipe that has no messages waiting +// and has a closed remote end will return ERR_REMOTE_CLOSED. +#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -22; + +// ERR_CANCELED: The in-progress operation (e.g. a wait) has been +// // canceled. +#[allow(unused)] pub const ERR_CANCELED: mx_status_t = -23; + +// ERR_PEER_CLOSED: The operation failed because the remote end +// of the subject of the operation was closed. +#[allow(unused)] pub const ERR_PEER_CLOSED: mx_status_t = -24; + // ERR_NOT_FOUND: The requested entity is not found. -#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -3; +#[allow(unused)] pub const ERR_NOT_FOUND: mx_status_t = -25; // ERR_ALREADY_EXISTS: An object with the specified identifier // already exists. // Example: Attempting to create a file when a file already exists // with that name. -#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -15; +#[allow(unused)] pub const ERR_ALREADY_EXISTS: mx_status_t = -26; // ERR_ALREADY_BOUND: The operation failed because the named entity // is already owned or controlled by another entity. The operation // could succeed later if the current owner releases the entity. -#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -16; - -// ERR_TIMED_OUT: The time limit for the operation elapsed before -// the operation completed. -#[allow(unused)] pub const ERR_TIMED_OUT: mx_status_t = -23; - -// ERR_HANDLE_CLOSED: a handle being waited on was closed -#[allow(unused)] pub const ERR_HANDLE_CLOSED: mx_status_t = -24; - -// ERR_REMOTE_CLOSED: The operation failed because the remote end -// of the subject of the operation was closed. -#[allow(unused)] pub const ERR_REMOTE_CLOSED: mx_status_t = -25; +#[allow(unused)] pub const ERR_ALREADY_BOUND: mx_status_t = -27; // ERR_UNAVAILABLE: The subject of the operation is currently unable // to perform the operation. // Note: This is used when there's no direct way for the caller to // observe when the subject will be able to perform the operation // and should thus retry. -#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -26; - -// ERR_SHOULD_WAIT: The operation cannot be performed currently but -// potentially could succeed if the caller waits for a prerequisite -// to be satisfied, for example waiting for a handle to be readable -// or writable. -// Example: Attempting to read from a message pipe that has no -// messages waiting but has an open remote will return ERR_SHOULD_WAIT. -// Attempting to read from a message pipe that has no messages waiting -// and has a closed remote end will return ERR_REMOTE_CLOSED. -#[allow(unused)] pub const ERR_SHOULD_WAIT: mx_status_t = -27; +#[allow(unused)] pub const ERR_UNAVAILABLE: mx_status_t = -28; // ======= Permission check errors ======= // ERR_ACCESS_DENIED: The caller did not have permission to perform @@ -312,3 +317,7 @@ pub const LP_CLONE_MXIO_CWD: u32 = 0x0002; #[allow(unused)] pub const ERR_BAD_PATH: mx_status_t = -50; #[allow(unused)] pub const ERR_NOT_DIR: mx_status_t = -51; #[allow(unused)] pub const ERR_NOT_FILE: mx_status_t = -52; +// ERR_FILE_BIG: A file exceeds a filesystem-specific size limit. +#[allow(unused)] pub const ERR_FILE_BIG: mx_status_t = -53; +// ERR_NO_SPACE: Filesystem or device space is exhausted. +#[allow(unused)] pub const ERR_NO_SPACE: mx_status_t = -54; diff --git a/src/libstd/sys/unix/process/process_common.rs b/src/libstd/sys/unix/process/process_common.rs index a4536520376..e9f41009064 100644 --- a/src/libstd/sys/unix/process/process_common.rs +++ b/src/libstd/sys/unix/process/process_common.rs @@ -417,13 +417,27 @@ mod tests { } } + // Android with api less than 21 define sig* functions inline, so it is not + // available for dynamic link. Implementing sigemptyset and sigaddset allow us + // to support older Android version (independent of libc version). + // The following implementations are based on https://git.io/vSkNf + #[cfg(not(target_os = "android"))] extern { + #[cfg_attr(target_os = "netbsd", link_name = "__sigemptyset14")] + fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int; + #[cfg_attr(target_os = "netbsd", link_name = "__sigaddset14")] fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int; } #[cfg(target_os = "android")] + unsafe fn sigemptyset(set: *mut libc::sigset_t) -> libc::c_int { + libc::memset(set as *mut _, 0, mem::size_of::<libc::sigset_t>()); + return 0; + } + + #[cfg(target_os = "android")] unsafe fn sigaddset(set: *mut libc::sigset_t, signum: libc::c_int) -> libc::c_int { use slice; @@ -434,8 +448,8 @@ mod tests { } // See #14232 for more information, but it appears that signal delivery to a - // newly spawned process may just be raced in the OSX, so to prevent this - // test from being flaky we ignore it on OSX. + // newly spawned process may just be raced in the macOS, so to prevent this + // 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. @@ -450,7 +464,7 @@ mod tests { let mut set: libc::sigset_t = mem::uninitialized(); let mut old_set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); + t!(cvt(sigemptyset(&mut set))); t!(cvt(sigaddset(&mut set, libc::SIGINT))); t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, &mut old_set))); diff --git a/src/libstd/sys/unix/process/process_unix.rs b/src/libstd/sys/unix/process/process_unix.rs index bbc987209e3..edd322ca6fa 100644 --- a/src/libstd/sys/unix/process/process_unix.rs +++ b/src/libstd/sys/unix/process/process_unix.rs @@ -129,7 +129,7 @@ impl Command { // mutex, and then after the fork they unlock it. // // Despite this information, libnative's spawn has been witnessed to - // deadlock on both OSX and FreeBSD. I'm not entirely sure why, but + // deadlock on both macOS and FreeBSD. I'm not entirely sure why, but // all collected backtraces point at malloc/free traffic in the // child spawned process. // @@ -193,7 +193,16 @@ impl Command { // need to clean things up now to avoid confusing the program // we're about to run. let mut set: libc::sigset_t = mem::uninitialized(); - t!(cvt(libc::sigemptyset(&mut set))); + if cfg!(target_os = "android") { + // Implementing sigemptyset allow us to support older Android + // versions. See the comment about Android and sig* functions in + // process_common.rs + libc::memset(&mut set as *mut _ as *mut _, + 0, + mem::size_of::<libc::sigset_t>()); + } else { + t!(cvt(libc::sigemptyset(&mut set))); + } t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, &set, ptr::null_mut()))); let ret = sys::signal(libc::SIGPIPE, libc::SIG_DFL); diff --git a/src/libstd/sys/unix/stack_overflow.rs b/src/libstd/sys/unix/stack_overflow.rs index 22d47ba0f62..51adbc24ae0 100644 --- a/src/libstd/sys/unix/stack_overflow.rs +++ b/src/libstd/sys/unix/stack_overflow.rs @@ -187,7 +187,7 @@ mod imp { let stack = libc::stack_t { ss_sp: ptr::null_mut(), ss_flags: SS_DISABLE, - // Workaround for bug in MacOS implementation of sigaltstack + // Workaround for bug in macOS implementation of sigaltstack // UNIX2003 which returns ENOMEM when disabling a stack while // passing ss_size smaller than MINSIGSTKSZ. According to POSIX // both ss_sp and ss_size should be ignored in this case. diff --git a/src/libstd/sys/unix/thread_local.rs b/src/libstd/sys/unix/thread_local.rs index d22118d4d79..2487f6bcaf7 100644 --- a/src/libstd/sys/unix/thread_local.rs +++ b/src/libstd/sys/unix/thread_local.rs @@ -38,3 +38,8 @@ pub unsafe fn destroy(key: Key) { let r = libc::pthread_key_delete(key); debug_assert_eq!(r, 0); } + +#[inline] +pub fn requires_synchronized_create() -> bool { + false +} diff --git a/src/libstd/sys/unix/time.rs b/src/libstd/sys/unix/time.rs index a08cec38f73..a1ad94872de 100644 --- a/src/libstd/sys/unix/time.rs +++ b/src/libstd/sys/unix/time.rs @@ -157,7 +157,7 @@ mod inner { pub fn sub_duration(&self, other: &Duration) -> Instant { Instant { t: self.t.checked_sub(dur2intervals(other)) - .expect("overflow when adding duration to instant"), + .expect("overflow when subtracting duration from instant"), } } } diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 4daab31c28f..1646f8cce72 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -14,8 +14,9 @@ #![cfg_attr(test, allow(dead_code))] #![unstable(issue = "0", feature = "windows_c")] -use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort,}; -use os::raw::{c_char, c_ulonglong}; +use os::raw::{c_int, c_uint, c_ulong, c_long, c_longlong, c_ushort, c_char}; +#[cfg(target_arch = "x86_64")] +use os::raw::c_ulonglong; use libc::{wchar_t, size_t, c_void}; use ptr; @@ -45,7 +46,7 @@ pub type SIZE_T = usize; pub type WORD = u16; pub type CHAR = c_char; pub type HCRYPTPROV = LONG_PTR; -pub type ULONG_PTR = c_ulonglong; +pub type ULONG_PTR = usize; pub type ULONG = c_ulong; #[cfg(target_arch = "x86_64")] pub type ULONGLONG = u64; @@ -198,7 +199,10 @@ pub const ERROR_TIMEOUT: DWORD = 0x5B4; pub const INVALID_HANDLE_VALUE: HANDLE = !0 as HANDLE; +pub const FACILITY_NT_BIT: DWORD = 0x1000_0000; + pub const FORMAT_MESSAGE_FROM_SYSTEM: DWORD = 0x00001000; +pub const FORMAT_MESSAGE_FROM_HMODULE: DWORD = 0x00000800; pub const FORMAT_MESSAGE_IGNORE_INSERTS: DWORD = 0x00000200; pub const TLS_OUT_OF_INDEXES: DWORD = 0xFFFFFFFF; @@ -935,7 +939,6 @@ extern "system" { args: *const c_void) -> DWORD; pub fn TlsAlloc() -> DWORD; - pub fn TlsFree(dwTlsIndex: DWORD) -> BOOL; pub fn TlsGetValue(dwTlsIndex: DWORD) -> LPVOID; pub fn TlsSetValue(dwTlsIndex: DWORD, lpTlsvalue: LPVOID) -> BOOL; pub fn GetLastError() -> DWORD; diff --git a/src/libstd/sys/windows/ext/ffi.rs b/src/libstd/sys/windows/ext/ffi.rs index 253787546c1..3f6c2827a3f 100644 --- a/src/libstd/sys/windows/ext/ffi.rs +++ b/src/libstd/sys/windows/ext/ffi.rs @@ -26,8 +26,22 @@ pub trait OsStringExt { /// Creates an `OsString` from a potentially ill-formed UTF-16 slice of /// 16-bit code units. /// - /// This is lossless: calling `.encode_wide()` on the resulting string + /// This is lossless: calling [`encode_wide`] on the resulting string /// will always return the original code units. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// use std::os::windows::prelude::*; + /// + /// // UTF-16 encoding for "Unicode". + /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065]; + /// + /// let string = OsString::from_wide(&source[..]); + /// ``` + /// + /// [`encode_wide`]: ./trait.OsStrExt.html#tymethod.encode_wide #[stable(feature = "rust1", since = "1.0.0")] fn from_wide(wide: &[u16]) -> Self; } @@ -42,11 +56,29 @@ impl OsStringExt for OsString { /// Windows-specific extensions to `OsStr`. #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { - /// Re-encodes an `OsStr` as a wide character sequence, - /// i.e. potentially ill-formed UTF-16. + /// Re-encodes an `OsStr` as a wide character sequence, i.e. potentially + /// ill-formed UTF-16. + /// + /// This is lossless: calling [`OsString::from_wide`] and then + /// `encode_wide` on the result will yield the original code units. + /// Note that the encoding does not add a final null terminator. + /// + /// # Examples + /// + /// ``` + /// use std::ffi::OsString; + /// use std::os::windows::prelude::*; + /// + /// // UTF-16 encoding for "Unicode". + /// let source = [0x0055, 0x006E, 0x0069, 0x0063, 0x006F, 0x0064, 0x0065]; + /// + /// let string = OsString::from_wide(&source[..]); + /// + /// let result: Vec<u16> = string.encode_wide().collect(); + /// assert_eq!(&source[..], &result[..]); + /// ``` /// - /// This is lossless. Note that the encoding does not include a final - /// null. + /// [`OsString::from_wide`]: ./trait.OsStringExt.html#tymethod.from_wide #[stable(feature = "rust1", since = "1.0.0")] fn encode_wide(&self) -> EncodeWide; } diff --git a/src/libstd/sys/windows/ext/fs.rs b/src/libstd/sys/windows/ext/fs.rs index c63dd8a47ca..2d00cb38ec4 100644 --- a/src/libstd/sys/windows/ext/fs.rs +++ b/src/libstd/sys/windows/ext/fs.rs @@ -8,7 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Windows-specific extensions for the primitives in `std::fs` +//! Windows-specific extensions for the primitives in the `std::fs` module. #![stable(feature = "rust1", since = "1.0.0")] @@ -18,7 +18,9 @@ use path::Path; use sys; use sys_common::{AsInnerMut, AsInner}; -/// Windows-specific extensions to `File` +/// Windows-specific extensions to [`File`]. +/// +/// [`File`]: ../../../fs/struct.File.html #[stable(feature = "file_offset", since = "1.15.0")] pub trait FileExt { /// Seeks to a given position and reads a number of bytes. @@ -35,6 +37,24 @@ pub trait FileExt { /// 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 /// still updated. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs::File; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let mut file = File::open("foo.txt")?; + /// let mut buffer = [0; 10]; + /// + /// // Read 10 bytes, starting 72 bytes from the + /// // start of the file. + /// file.seek_read(&mut buffer[..], 72)?; + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn seek_read(&self, buf: &mut [u8], offset: u64) -> io::Result<usize>; @@ -52,6 +72,22 @@ pub trait FileExt { /// Note that similar to `File::write`, it is not an error to return a /// short write. When returning from such a short write, the file pointer /// is still updated. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::File; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> std::io::Result<()> { + /// let mut buffer = File::create("foo.txt")?; + /// + /// // Write a byte string starting 72 bytes from + /// // the start of the file. + /// buffer.seek_write(b"some bytes", 72)?; + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "file_offset", since = "1.15.0")] fn seek_write(&self, buf: &[u8], offset: u64) -> io::Result<usize>; } @@ -67,84 +103,97 @@ impl FileExt for fs::File { } } -/// Windows-specific extensions to `OpenOptions` +/// Windows-specific extensions to [`OpenOptions`]. +/// +/// [`OpenOptions`]: ../../../fs/struct.OpenOptions.html #[stable(feature = "open_options_ext", since = "1.10.0")] pub trait OpenOptionsExt { - /// Overrides the `dwDesiredAccess` argument to the call to `CreateFile` + /// Overrides the `dwDesiredAccess` argument to the call to [`CreateFile`] /// with the specified value. /// /// This will override the `read`, `write`, and `append` flags on the /// `OpenOptions` structure. This method provides fine-grained control over /// the permissions to read, write and append data, attributes (like hidden - /// and system) and extended attributes. + /// and system), and extended attributes. /// /// # Examples /// /// ```no_run /// use std::fs::OpenOptions; - /// use std::os::windows::fs::OpenOptionsExt; + /// use std::os::windows::prelude::*; /// /// // Open without read and write permission, for example if you only need - /// // to call `stat()` on the file + /// // to call `stat` on the file /// let file = OpenOptions::new().access_mode(0).open("foo.txt"); /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn access_mode(&mut self, access: u32) -> &mut Self; - /// Overrides the `dwShareMode` argument to the call to `CreateFile` with + /// Overrides the `dwShareMode` argument to the call to [`CreateFile`] with /// the specified value. /// /// By default `share_mode` is set to - /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. Specifying - /// less permissions denies others to read from, write to and/or delete the - /// file while it is open. + /// `FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE`. This allows + /// other processes to to read, write, and delete/rename the same file + /// while it is open. Removing any of the flags will prevent other + /// processes from performing the corresponding operation until the file + /// handle is closed. /// /// # Examples /// /// ```no_run /// use std::fs::OpenOptions; - /// use std::os::windows::fs::OpenOptionsExt; + /// use std::os::windows::prelude::*; /// /// // Do not allow others to read or modify this file while we have it open - /// // for writing - /// let file = OpenOptions::new().write(true) - /// .share_mode(0) - /// .open("foo.txt"); + /// // for writing. + /// let file = OpenOptions::new() + /// .write(true) + /// .share_mode(0) + /// .open("foo.txt"); /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn share_mode(&mut self, val: u32) -> &mut Self; /// Sets extra flags for the `dwFileFlags` argument to the call to - /// `CreateFile2` (or combines it with `attributes` and `security_qos_flags` - /// to set the `dwFlagsAndAttributes` for `CreateFile`). + /// [`CreateFile2`] to the specified value (or combines it with + /// `attributes` and `security_qos_flags` to set the `dwFlagsAndAttributes` + /// for [`CreateFile`]). /// - /// Custom flags can only set flags, not remove flags set by Rusts options. - /// This options overwrites any previously set custom flags. + /// Custom flags can only set flags, not remove flags set by Rust's options. + /// This option overwrites any previously set custom flags. /// /// # Examples /// - /// ```rust,ignore + /// ```ignore /// extern crate winapi; + /// /// use std::fs::OpenOptions; - /// use std::os::windows::fs::OpenOptionsExt; - /// - /// let mut options = OpenOptions::new(); - /// options.create(true).write(true); - /// if cfg!(windows) { - /// options.custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE); - /// } - /// let file = options.open("foo.txt"); + /// use std::os::windows::prelude::*; + /// + /// let file = OpenOptions::new() + /// .create(true) + /// .write(true) + /// .custom_flags(winapi::FILE_FLAG_DELETE_ON_CLOSE) + /// .open("foo.txt"); /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx + /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn custom_flags(&mut self, flags: u32) -> &mut Self; - /// Sets the `dwFileAttributes` argument to the call to `CreateFile2` to + /// Sets the `dwFileAttributes` argument to the call to [`CreateFile2`] to /// the specified value (or combines it with `custom_flags` and /// `security_qos_flags` to set the `dwFlagsAndAttributes` for - /// `CreateFile`). + /// [`CreateFile`]). /// /// If a _new_ file is created because it does not yet exist and - ///`.create(true)` or `.create_new(true)` are specified, the new file is + /// `.create(true)` or `.create_new(true)` are specified, the new file is /// given the attributes declared with `.attributes()`. /// /// If an _existing_ file is opened with `.create(true).truncate(true)`, its @@ -155,21 +204,52 @@ pub trait OpenOptionsExt { /// /// # Examples /// - /// ```rust,ignore + /// ```ignore /// extern crate winapi; + /// /// use std::fs::OpenOptions; - /// use std::os::windows::fs::OpenOptionsExt; + /// use std::os::windows::prelude::*; /// - /// let file = OpenOptions::new().write(true).create(true) - /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN) - /// .open("foo.txt"); + /// let file = OpenOptions::new() + /// .write(true) + /// .create(true) + /// .attributes(winapi::FILE_ATTRIBUTE_HIDDEN) + /// .open("foo.txt"); /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx + /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn attributes(&mut self, val: u32) -> &mut Self; - /// Sets the `dwSecurityQosFlags` argument to the call to `CreateFile2` to + /// Sets the `dwSecurityQosFlags` argument to the call to [`CreateFile2`] to /// the specified value (or combines it with `custom_flags` and `attributes` - /// to set the `dwFlagsAndAttributes` for `CreateFile`). + /// to set the `dwFlagsAndAttributes` for [`CreateFile`]). + /// + /// By default, `security_qos_flags` is set to `SECURITY_ANONYMOUS`. For + /// information about possible values, see [Impersonation Levels] on the + /// Windows Dev Center site. + /// + /// # Examples + /// + /// ```no_run + /// use std::fs::OpenOptions; + /// use std::os::windows::prelude::*; + /// + /// let file = OpenOptions::new() + /// .write(true) + /// .create(true) + /// + /// // Sets the flag value to `SecurityIdentification`. + /// .security_qos_flags(1) + /// + /// .open("foo.txt"); + /// ``` + /// + /// [`CreateFile`]: https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858.aspx + /// [`CreateFile2`]: https://msdn.microsoft.com/en-us/library/windows/desktop/hh449422.aspx + /// [Impersonation Levels]: + /// https://msdn.microsoft.com/en-us/library/windows/desktop/aa379572.aspx #[stable(feature = "open_options_ext", since = "1.10.0")] fn security_qos_flags(&mut self, flags: u32) -> &mut OpenOptions; } @@ -197,35 +277,136 @@ impl OpenOptionsExt for OpenOptions { } } -/// Extension methods for `fs::Metadata` to access the raw fields contained +/// Extension methods for [`fs::Metadata`] to access the raw fields contained /// within. +/// +/// The data members that this trait exposes correspond to the members +/// of the [`BY_HANDLE_FILE_INFORMATION`] structure. +/// +/// [`fs::Metadata`]: ../../../fs/struct.Metadata.html +/// [`BY_HANDLE_FILE_INFORMATION`]: +/// https://msdn.microsoft.com/en-us/library/windows/desktop/aa363788.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] pub trait MetadataExt { /// Returns the value of the `dwFileAttributes` field of this metadata. /// /// This field contains the file system attribute information for a file - /// or directory. + /// or directory. For possible values and their descriptions, see + /// [File Attribute Constants] in the Windows Dev Center. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let attributes = metadata.file_attributes(); + /// # Ok(()) + /// # } + /// ``` + /// + /// [File Attribute Constants]: + /// https://msdn.microsoft.com/en-us/library/windows/desktop/gg258117.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] fn file_attributes(&self) -> u32; /// Returns the value of the `ftCreationTime` field of this metadata. /// - /// The returned 64-bit value represents the number of 100-nanosecond - /// intervals since January 1, 1601 (UTC). + /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, + /// which represents the number of 100-nanosecond intervals since + /// January 1, 1601 (UTC). The struct is automatically + /// converted to a `u64` value, as that is the recommended way + /// to use it. + /// + /// If the underlying filesystem does not support creation time, the + /// returned value is 0. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let creation_time = metadata.creation_time(); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] fn creation_time(&self) -> u64; /// Returns the value of the `ftLastAccessTime` field of this metadata. /// - /// The returned 64-bit value represents the number of 100-nanosecond - /// intervals since January 1, 1601 (UTC). + /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, + /// which represents the number of 100-nanosecond intervals since + /// January 1, 1601 (UTC). The struct is automatically + /// converted to a `u64` value, as that is the recommended way + /// to use it. + /// + /// For a file, the value specifies the last time that a file was read + /// from or written to. For a directory, the value specifies when + /// the directory was created. For both files and directories, the + /// specified date is correct, but the time of day is always set to + /// midnight. + /// + /// If the underlying filesystem does not support last access time, the + /// returned value is 0. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let last_access_time = metadata.last_access_time(); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] fn last_access_time(&self) -> u64; /// Returns the value of the `ftLastWriteTime` field of this metadata. /// - /// The returned 64-bit value represents the number of 100-nanosecond - /// intervals since January 1, 1601 (UTC). + /// The returned 64-bit value is equivalent to a [`FILETIME`] struct, + /// which represents the number of 100-nanosecond intervals since + /// January 1, 1601 (UTC). The struct is automatically + /// converted to a `u64` value, as that is the recommended way + /// to use it. + /// + /// For a file, the value specifies the last time that a file was written + /// 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. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let last_write_time = metadata.last_write_time(); + /// # Ok(()) + /// # } + /// ``` + /// + /// [`FILETIME`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms724284.aspx #[stable(feature = "metadata_ext", since = "1.1.0")] fn last_write_time(&self) -> u64; @@ -233,6 +414,20 @@ pub trait MetadataExt { /// metadata. /// /// The returned value does not have meaning for directories. + /// + /// # Examples + /// + /// ```no_run + /// use std::io; + /// use std::fs; + /// use std::os::windows::prelude::*; + /// + /// # fn foo() -> io::Result<()> { + /// let metadata = fs::metadata("foo.txt")?; + /// let file_size = metadata.file_size(); + /// # Ok(()) + /// # } + /// ``` #[stable(feature = "metadata_ext", since = "1.1.0")] fn file_size(&self) -> u64; } @@ -253,7 +448,7 @@ impl MetadataExt for Metadata { /// /// # Examples /// -/// ```ignore +/// ```no_run /// use std::os::windows::fs; /// /// # fn foo() -> std::io::Result<()> { @@ -274,7 +469,7 @@ pub fn symlink_file<P: AsRef<Path>, Q: AsRef<Path>>(src: P, dst: Q) /// /// # Examples /// -/// ```ignore +/// ```no_run /// use std::os::windows::fs; /// /// # fn foo() -> std::io::Result<()> { diff --git a/src/libstd/sys/windows/ext/mod.rs b/src/libstd/sys/windows/ext/mod.rs index f12e50cc923..11b1337a8ae 100644 --- a/src/libstd/sys/windows/ext/mod.rs +++ b/src/libstd/sys/windows/ext/mod.rs @@ -8,11 +8,13 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! Experimental extensions to `std` for Windows. +//! Platform-specific extensions to `std` for Windows. //! -//! For now, this module is limited to extracting handles, file -//! descriptors, and sockets, but its functionality will grow over -//! time. +//! Provides access to platform-level information for Windows, and exposes +//! Windows-specific idioms that would otherwise be inappropriate as part +//! the core `std` library. These extensions allow developers to use +//! `std` types and idioms with Windows in a way that the normal +//! platform-agnostic idioms would not normally support. #![stable(feature = "rust1", since = "1.0.0")] diff --git a/src/libstd/sys/windows/ext/process.rs b/src/libstd/sys/windows/ext/process.rs index 1419a4af427..759f055c4b1 100644 --- a/src/libstd/sys/windows/ext/process.rs +++ b/src/libstd/sys/windows/ext/process.rs @@ -104,6 +104,7 @@ pub trait CommandExt { /// Sets the [process creation flags][1] to be passed to `CreateProcess`. /// /// These will always be ORed with `CREATE_UNICODE_ENVIRONMENT`. + /// /// [1]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms684863(v=vs.85).aspx #[stable(feature = "windows_process_extensions", since = "1.16.0")] fn creation_flags(&mut self, flags: u32) -> &mut process::Command; diff --git a/src/libstd/sys/windows/os.rs b/src/libstd/sys/windows/os.rs index 7e28dd1e259..a51b458451e 100644 --- a/src/libstd/sys/windows/os.rs +++ b/src/libstd/sys/windows/os.rs @@ -32,7 +32,7 @@ pub fn errno() -> i32 { } /// Gets a detailed string description for the given error number. -pub fn error_string(errnum: i32) -> String { +pub fn error_string(mut errnum: i32) -> String { // This value is calculated from the macro // MAKELANGID(LANG_SYSTEM_DEFAULT, SUBLANG_SYS_DEFAULT) let langId = 0x0800 as c::DWORD; @@ -40,9 +40,27 @@ pub fn error_string(errnum: i32) -> String { let mut buf = [0 as c::WCHAR; 2048]; unsafe { - let res = c::FormatMessageW(c::FORMAT_MESSAGE_FROM_SYSTEM | + let mut module = ptr::null_mut(); + let mut flags = 0; + + // NTSTATUS errors may be encoded as HRESULT, which may returned from + // GetLastError. For more information about Windows error codes, see + // `[MS-ERREF]`: https://msdn.microsoft.com/en-us/library/cc231198.aspx + if (errnum & c::FACILITY_NT_BIT as i32) != 0 { + // format according to https://support.microsoft.com/en-us/help/259693 + const NTDLL_DLL: &'static [u16] = &['N' as _, 'T' as _, 'D' as _, 'L' as _, 'L' as _, + '.' as _, 'D' as _, 'L' as _, 'L' as _, 0]; + module = c::GetModuleHandleW(NTDLL_DLL.as_ptr()); + + if module != ptr::null_mut() { + errnum ^= c::FACILITY_NT_BIT as i32; + flags = c::FORMAT_MESSAGE_FROM_HMODULE; + } + } + + let res = c::FormatMessageW(flags | c::FORMAT_MESSAGE_FROM_SYSTEM | c::FORMAT_MESSAGE_IGNORE_INSERTS, - ptr::null_mut(), + module, errnum as c::DWORD, langId, buf.as_mut_ptr(), @@ -299,3 +317,17 @@ pub fn home_dir() -> Option<PathBuf> { pub fn exit(code: i32) -> ! { unsafe { c::ExitProcess(code as c::UINT) } } + +#[cfg(test)] +mod tests { + use io::Error; + use sys::c; + + // tests `error_string` above + #[test] + fn ntstatus_error() { + const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; + assert!(!Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) + .to_string().contains("FormatMessageW() returned error")); + } +} diff --git a/src/libstd/sys/windows/os_str.rs b/src/libstd/sys/windows/os_str.rs index b02b06e1ef2..f401e7b35c8 100644 --- a/src/libstd/sys/windows/os_str.rs +++ b/src/libstd/sys/windows/os_str.rs @@ -97,6 +97,12 @@ impl Buf { pub fn into_box(self) -> Box<Slice> { unsafe { mem::transmute(self.inner.into_box()) } } + + #[inline] + pub fn from_box(boxed: Box<Slice>) -> Buf { + let inner: Box<Wtf8> = unsafe { mem::transmute(boxed) }; + Buf { inner: Wtf8Buf::from_box(inner) } + } } impl Slice { diff --git a/src/libstd/sys/windows/process.rs b/src/libstd/sys/windows/process.rs index 1afb3728c9d..dfbc1b581ee 100644 --- a/src/libstd/sys/windows/process.rs +++ b/src/libstd/sys/windows/process.rs @@ -257,8 +257,13 @@ impl Stdio { // INVALID_HANDLE_VALUE. Stdio::Inherit => { match stdio::get(stdio_id) { - Ok(io) => io.handle().duplicate(0, true, - c::DUPLICATE_SAME_ACCESS), + Ok(io) => { + let io = Handle::new(io.handle()); + let ret = io.duplicate(0, true, + c::DUPLICATE_SAME_ACCESS); + io.into_raw(); + return ret + } Err(..) => Ok(Handle::new(c::INVALID_HANDLE_VALUE)), } } diff --git a/src/libstd/sys/windows/stdio.rs b/src/libstd/sys/windows/stdio.rs index b1a57c349fb..d72e4b4438b 100644 --- a/src/libstd/sys/windows/stdio.rs +++ b/src/libstd/sys/windows/stdio.rs @@ -22,42 +22,43 @@ use sys::cvt; use sys::handle::Handle; use sys_common::io::read_to_end_uninitialized; -pub struct NoClose(Option<Handle>); - pub enum Output { - Console(NoClose), - Pipe(NoClose), + Console(c::HANDLE), + Pipe(c::HANDLE), } pub struct Stdin { - handle: Output, utf8: Mutex<io::Cursor<Vec<u8>>>, } -pub struct Stdout(Output); -pub struct Stderr(Output); +pub struct Stdout; +pub struct Stderr; pub fn get(handle: c::DWORD) -> io::Result<Output> { let handle = unsafe { c::GetStdHandle(handle) }; if handle == c::INVALID_HANDLE_VALUE { Err(io::Error::last_os_error()) } else if handle.is_null() { - Err(io::Error::new(io::ErrorKind::Other, - "no stdio handle available for this process")) + Err(io::Error::from_raw_os_error(c::ERROR_INVALID_HANDLE as i32)) } else { - let ret = NoClose::new(handle); let mut out = 0; match unsafe { c::GetConsoleMode(handle, &mut out) } { - 0 => Ok(Output::Pipe(ret)), - _ => Ok(Output::Console(ret)), + 0 => Ok(Output::Pipe(handle)), + _ => Ok(Output::Console(handle)), } } } -fn write(out: &Output, data: &[u8]) -> io::Result<usize> { - let handle = match *out { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().write(data), +fn write(handle: c::DWORD, data: &[u8]) -> io::Result<usize> { + let handle = match try!(get(handle)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.write(data); + handle.into_raw(); + return ret + } }; + // As with stdin on windows, stdout often can't handle writes of large // sizes. For an example, see #14940. For this reason, don't try to // write the entire output buffer on windows. @@ -93,18 +94,20 @@ fn write(out: &Output, data: &[u8]) -> io::Result<usize> { impl Stdin { pub fn new() -> io::Result<Stdin> { - get(c::STD_INPUT_HANDLE).map(|handle| { - Stdin { - handle: handle, - utf8: Mutex::new(Cursor::new(Vec::new())), - } + Ok(Stdin { + utf8: Mutex::new(Cursor::new(Vec::new())), }) } pub fn read(&self, buf: &mut [u8]) -> io::Result<usize> { - let handle = match self.handle { - Output::Console(ref c) => c.get().raw(), - Output::Pipe(ref p) => return p.get().read(buf), + let handle = match try!(get(c::STD_INPUT_HANDLE)) { + Output::Console(c) => c, + Output::Pipe(p) => { + let handle = Handle::new(p); + let ret = handle.read(buf); + handle.into_raw(); + return ret + } }; let mut utf8 = self.utf8.lock().unwrap(); // Read more if the buffer is empty @@ -125,11 +128,9 @@ impl Stdin { Ok(utf8) => utf8.into_bytes(), Err(..) => return Err(invalid_encoding()), }; - if let Output::Console(_) = self.handle { - if let Some(&last_byte) = data.last() { - if last_byte == CTRL_Z { - data.pop(); - } + if let Some(&last_byte) = data.last() { + if last_byte == CTRL_Z { + data.pop(); } } *utf8 = Cursor::new(data); @@ -158,11 +159,11 @@ impl<'a> Read for &'a Stdin { impl Stdout { pub fn new() -> io::Result<Stdout> { - get(c::STD_OUTPUT_HANDLE).map(Stdout) + Ok(Stdout) } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - write(&self.0, data) + write(c::STD_OUTPUT_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -172,11 +173,11 @@ impl Stdout { impl Stderr { pub fn new() -> io::Result<Stderr> { - get(c::STD_ERROR_HANDLE).map(Stderr) + Ok(Stderr) } pub fn write(&self, data: &[u8]) -> io::Result<usize> { - write(&self.0, data) + write(c::STD_ERROR_HANDLE, data) } pub fn flush(&self) -> io::Result<()> { @@ -197,27 +198,12 @@ impl io::Write for Stderr { } } -impl NoClose { - fn new(handle: c::HANDLE) -> NoClose { - NoClose(Some(Handle::new(handle))) - } - - fn get(&self) -> &Handle { self.0.as_ref().unwrap() } -} - -impl Drop for NoClose { - fn drop(&mut self) { - self.0.take().unwrap().into_raw(); - } -} - impl Output { - pub fn handle(&self) -> &Handle { - let nc = match *self { - Output::Console(ref c) => c, - Output::Pipe(ref c) => c, - }; - nc.0.as_ref().unwrap() + pub fn handle(&self) -> c::HANDLE { + match *self { + Output::Console(c) => c, + Output::Pipe(c) => c, + } } } diff --git a/src/libstd/sys/windows/thread_local.rs b/src/libstd/sys/windows/thread_local.rs index 597f05622a5..ad57f87dc1f 100644 --- a/src/libstd/sys/windows/thread_local.rs +++ b/src/libstd/sys/windows/thread_local.rs @@ -8,10 +8,11 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use mem; use ptr; +use sync::atomic::AtomicPtr; +use sync::atomic::Ordering::SeqCst; use sys::c; -use sys_common::mutex::Mutex; -use sys_common; pub type Key = c::DWORD; pub type Dtor = unsafe extern fn(*mut u8); @@ -34,8 +35,6 @@ pub type Dtor = unsafe extern fn(*mut u8); // * All TLS destructors are tracked by *us*, not the windows runtime. This // means that we have a global list of destructors for each TLS key that // we know about. -// * When a TLS key is destroyed, we're sure to remove it from the dtor list -// if it's in there. // * When a thread exits, we run over the entire list and run dtors for all // non-null keys. This attempts to match Unix semantics in this regard. // @@ -50,13 +49,6 @@ pub type Dtor = unsafe extern fn(*mut u8); // [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base // /threading/thread_local_storage_win.cc#L42 -// NB these are specifically not types from `std::sync` as they currently rely -// on poisoning and this module needs to operate at a lower level than requiring -// the thread infrastructure to be in place (useful on the borders of -// initialization/destruction). -static DTOR_LOCK: Mutex = Mutex::new(); -static mut DTORS: *mut Vec<(Key, Dtor)> = ptr::null_mut(); - // ------------------------------------------------------------------------- // Native bindings // @@ -85,81 +77,64 @@ pub unsafe fn get(key: Key) -> *mut u8 { } #[inline] -pub unsafe fn destroy(key: Key) { - if unregister_dtor(key) { - // FIXME: Currently if a key has a destructor associated with it we - // can't actually ever unregister it. If we were to - // unregister it, then any key destruction would have to be - // serialized with respect to actually running destructors. - // - // We want to avoid a race where right before run_dtors runs - // some destructors TlsFree is called. Allowing the call to - // TlsFree would imply that the caller understands that *all - // known threads* are not exiting, which is quite a difficult - // thing to know! - // - // For now we just leak all keys with dtors to "fix" this. - // Note that source [2] above shows precedent for this sort - // of strategy. - } else { - let r = c::TlsFree(key); - debug_assert!(r != 0); - } +pub unsafe fn destroy(_key: Key) { + rtabort!("can't destroy tls keys on windows") +} + +#[inline] +pub fn requires_synchronized_create() -> bool { + true } // ------------------------------------------------------------------------- // Dtor registration // -// These functions are associated with registering and unregistering -// destructors. They're pretty simple, they just push onto a vector and scan -// a vector currently. +// Windows has no native support for running destructors so we manage our own +// list of destructors to keep track of how to destroy keys. We then install a +// callback later to get invoked whenever a thread exits, running all +// appropriate destructors. // -// FIXME: This could probably be at least a little faster with a BTree. - -unsafe fn init_dtors() { - if !DTORS.is_null() { return } +// Currently unregistration from this list is not supported. A destructor can be +// registered but cannot be unregistered. There's various simplifying reasons +// for doing this, the big ones being: +// +// 1. Currently we don't even support deallocating TLS keys, so normal operation +// doesn't need to deallocate a destructor. +// 2. There is no point in time where we know we can unregister a destructor +// because it could always be getting run by some remote thread. +// +// Typically processes have a statically known set of TLS keys which is pretty +// small, and we'd want to keep this memory alive for the whole process anyway +// really. +// +// Perhaps one day we can fold the `Box` here into a static allocation, +// expanding the `StaticKey` structure to contain not only a slot for the TLS +// key but also a slot for the destructor queue on windows. An optimization for +// another day! - let dtors = box Vec::<(Key, Dtor)>::new(); +static DTORS: AtomicPtr<Node> = AtomicPtr::new(ptr::null_mut()); - let res = sys_common::at_exit(move|| { - DTOR_LOCK.lock(); - let dtors = DTORS; - DTORS = 1 as *mut _; - Box::from_raw(dtors); - assert!(DTORS as usize == 1); // can't re-init after destructing - DTOR_LOCK.unlock(); - }); - if res.is_ok() { - DTORS = Box::into_raw(dtors); - } else { - DTORS = 1 as *mut _; - } +struct Node { + dtor: Dtor, + key: Key, + next: *mut Node, } unsafe fn register_dtor(key: Key, dtor: Dtor) { - DTOR_LOCK.lock(); - init_dtors(); - assert!(DTORS as usize != 0); - assert!(DTORS as usize != 1, - "cannot create new TLS keys after the main thread has exited"); - (*DTORS).push((key, dtor)); - DTOR_LOCK.unlock(); -} + let mut node = Box::new(Node { + key: key, + dtor: dtor, + next: ptr::null_mut(), + }); -unsafe fn unregister_dtor(key: Key) -> bool { - DTOR_LOCK.lock(); - init_dtors(); - assert!(DTORS as usize != 0); - assert!(DTORS as usize != 1, - "cannot unregister destructors after the main thread has exited"); - let ret = { - let dtors = &mut *DTORS; - let before = dtors.len(); - dtors.retain(|&(k, _)| k != key); - dtors.len() != before - }; - DTOR_LOCK.unlock(); - ret + let mut head = DTORS.load(SeqCst); + loop { + node.next = head; + match DTORS.compare_exchange(head, &mut *node, SeqCst, SeqCst) { + Ok(_) => return mem::forget(node), + Err(cur) => head = cur, + } + } } // ------------------------------------------------------------------------- @@ -196,16 +171,12 @@ unsafe fn unregister_dtor(key: Key) -> bool { // # Ok, what's up with running all these destructors? // // This will likely need to be improved over time, but this function -// attempts a "poor man's" destructor callback system. To do this we clone a -// local copy of the dtor list to start out with. This is our fudgy attempt -// to not hold the lock while destructors run and not worry about the list -// changing while we're looking at it. -// -// Once we've got a list of what to run, we iterate over all keys, check -// their values, and then run destructors if the values turn out to be non -// null (setting them to null just beforehand). We do this a few times in a -// loop to basically match Unix semantics. If we don't reach a fixed point -// after a short while then we just inevitably leak something most likely. +// attempts a "poor man's" destructor callback system. Once we've got a list +// of what to run, we iterate over all keys, check their values, and then run +// destructors if the values turn out to be non null (setting them to null just +// beforehand). We do this a few times in a loop to basically match Unix +// semantics. If we don't reach a fixed point after a short while then we just +// inevitably leak something most likely. // // # The article mentions weird stuff about "/INCLUDE"? // @@ -259,25 +230,21 @@ unsafe extern "system" fn on_tls_callback(h: c::LPVOID, unsafe fn run_dtors() { let mut any_run = true; for _ in 0..5 { - if !any_run { break } + if !any_run { + break + } any_run = false; - let dtors = { - DTOR_LOCK.lock(); - let ret = if DTORS as usize <= 1 { - Vec::new() - } else { - (*DTORS).iter().map(|s| *s).collect() - }; - DTOR_LOCK.unlock(); - ret - }; - for &(key, dtor) in &dtors { - let ptr = c::TlsGetValue(key); + let mut cur = DTORS.load(SeqCst); + while !cur.is_null() { + let ptr = c::TlsGetValue((*cur).key); + if !ptr.is_null() { - c::TlsSetValue(key, ptr::null_mut()); - dtor(ptr as *mut _); + c::TlsSetValue((*cur).key, ptr::null_mut()); + ((*cur).dtor)(ptr as *mut _); any_run = true; } + + cur = (*cur).next; } } } |
