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/windows | |
| 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/windows')
| -rw-r--r-- | src/libstd/sys/windows/c.rs | 11 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/ffi.rs | 42 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/fs.rs | 293 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/mod.rs | 10 | ||||
| -rw-r--r-- | src/libstd/sys/windows/ext/process.rs | 1 | ||||
| -rw-r--r-- | src/libstd/sys/windows/os.rs | 38 | ||||
| -rw-r--r-- | src/libstd/sys/windows/os_str.rs | 6 | ||||
| -rw-r--r-- | src/libstd/sys/windows/process.rs | 9 | ||||
| -rw-r--r-- | src/libstd/sys/windows/stdio.rs | 92 | ||||
| -rw-r--r-- | src/libstd/sys/windows/thread_local.rs | 165 |
10 files changed, 448 insertions, 219 deletions
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; } } } |
