diff --git a/src/libstd/build.rs b/src/libstd/build.rs index 743a1778fbda3..c8500d23ed314 100644 --- a/src/libstd/build.rs +++ b/src/libstd/build.rs @@ -51,6 +51,7 @@ fn main() { println!("cargo:rustc-link-lib=bcrypt"); } else if target.contains("windows") { println!("cargo:rustc-link-lib=advapi32"); + println!("cargo:rustc-link-lib=ntdll"); println!("cargo:rustc-link-lib=ws2_32"); println!("cargo:rustc-link-lib=userenv"); } else if target.contains("fuchsia") { diff --git a/src/libstd/sys/windows/c.rs b/src/libstd/sys/windows/c.rs index 6115d652b0cea..b4aaeb2759bef 100644 --- a/src/libstd/sys/windows/c.rs +++ b/src/libstd/sys/windows/c.rs @@ -5,7 +5,6 @@ #![unstable(issue = "none", feature = "windows_c")] use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort}; -use crate::ptr; use libc::{c_void, size_t, wchar_t}; @@ -37,6 +36,7 @@ pub type LPBYTE = *mut BYTE; pub type LPCSTR = *const CHAR; pub type LPCWSTR = *const WCHAR; pub type LPDWORD = *mut DWORD; +pub type LPLONG = *mut LONG; pub type LPHANDLE = *mut HANDLE; pub type LPOVERLAPPED = *mut OVERLAPPED; pub type LPPROCESS_INFORMATION = *mut PROCESS_INFORMATION; @@ -54,9 +54,7 @@ pub type LPWSABUF = *mut WSABUF; pub type LPWSAOVERLAPPED = *mut c_void; pub type LPWSAOVERLAPPED_COMPLETION_ROUTINE = *mut c_void; -pub type PCONDITION_VARIABLE = *mut CONDITION_VARIABLE; pub type PLARGE_INTEGER = *mut c_longlong; -pub type PSRWLOCK = *mut SRWLOCK; pub type SOCKET = crate::os::windows::raw::SOCKET; pub type socklen_t = c_int; @@ -198,9 +196,6 @@ pub const INFINITE: DWORD = !0; pub const DUPLICATE_SAME_ACCESS: DWORD = 0x00000002; -pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = CONDITION_VARIABLE { ptr: ptr::null_mut() }; -pub const SRWLOCK_INIT: SRWLOCK = SRWLOCK { ptr: ptr::null_mut() }; - pub const DETACHED_PROCESS: DWORD = 0x00000008; pub const CREATE_NEW_PROCESS_GROUP: DWORD = 0x00000200; pub const CREATE_UNICODE_ENVIRONMENT: DWORD = 0x00000400; @@ -245,7 +240,6 @@ pub struct ipv6_mreq { pub ipv6mr_interface: c_uint, } -pub const VOLUME_NAME_DOS: DWORD = 0x0; pub const MOVEFILE_REPLACE_EXISTING: DWORD = 1; pub const FILE_BEGIN: DWORD = 0; @@ -418,14 +412,6 @@ pub type LPPROGRESS_ROUTINE = crate::option::Option< ) -> DWORD, >; -#[repr(C)] -pub struct CONDITION_VARIABLE { - pub ptr: LPVOID, -} -#[repr(C)] -pub struct SRWLOCK { - pub ptr: LPVOID, -} #[repr(C)] pub struct CRITICAL_SECTION { CriticalSectionDebug: LPVOID, @@ -738,6 +724,21 @@ if #[cfg(target_vendor = "uwp")] { } // Shared between Desktop & UWP +pub type NTSTATUS = LONG; + +#[repr(C)] +union IO_STATUS_BLOCK_u { + Status: NTSTATUS, + Pointer: LPVOID, +} + +#[repr(C)] +pub struct IO_STATUS_BLOCK { + u: IO_STATUS_BLOCK_u, + Information: ULONG_PTR, +} +pub type PIO_STATUS_BLOCK = *mut IO_STATUS_BLOCK; + extern "system" { pub fn WSAStartup(wVersionRequested: WORD, lpWSAData: LPWSADATA) -> c_int; pub fn WSACleanup() -> c_int; @@ -775,7 +776,7 @@ extern "system" { dwFlags: DWORD, ) -> SOCKET; pub fn ioctlsocket(s: SOCKET, cmd: c_long, argp: *mut c_ulong) -> c_int; - pub fn InitializeCriticalSection(CriticalSection: *mut CRITICAL_SECTION); + pub fn InitializeCriticalSectionAndSpinCount(CriticalSection: *mut CRITICAL_SECTION, dwSpinCount: DWORD) -> BOOL; pub fn EnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION); pub fn TryEnterCriticalSection(CriticalSection: *mut CRITICAL_SECTION) -> BOOL; pub fn LeaveCriticalSection(CriticalSection: *mut CRITICAL_SECTION); @@ -809,6 +810,10 @@ extern "system" { lpThreadId: LPDWORD, ) -> HANDLE; pub fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD; + pub fn SetEvent(hEvent: HANDLE) -> BOOL; + pub fn CreateSemaphoreW(lpSemaphoreAttributes: LPSECURITY_ATTRIBUTES, lInitialCount: LONG, lMaximumCount: LONG, lpName: LPCWSTR) -> HANDLE; + pub fn ReleaseSemaphore(hSemaphore: HANDLE, lReleaseCount: LONG, lpPreviousCount: LPLONG) -> BOOL; + pub fn ResetEvent(hEvent: HANDLE) -> BOOL; pub fn SwitchToThread() -> BOOL; pub fn Sleep(dwMilliseconds: DWORD); pub fn GetProcessId(handle: HANDLE) -> DWORD; @@ -1012,6 +1017,10 @@ extern "system" { pub fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) -> LPVOID; pub fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID, dwBytes: SIZE_T) -> LPVOID; pub fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: LPVOID) -> BOOL; + pub fn NtSetInformationFile(hFile: HANDLE, IoStatusBlock: PIO_STATUS_BLOCK, FileInformation: LPVOID, Length: ULONG, FileInformationClass: UINT) -> NTSTATUS; + pub fn NtQueryObject(Handle: HANDLE, ObjectInformationClass: UINT, ObjectInformation: LPCWSTR, ObjectInformationLength: ULONG, ReturnLength: *mut ULONG) -> NTSTATUS; + pub fn QueryDosDeviceW(lpDeviceName: LPCWSTR, lpTargetPath: LPWSTR, ucchMax: DWORD) -> DWORD; + pub fn GetLogicalDriveStringsW(nBufferLength: DWORD, lpBuffer: LPWSTR) -> DWORD; } // Functions that aren't available on every version of Windows that we support, @@ -1024,12 +1033,6 @@ compat_fn! { _dwFlags: DWORD) -> BOOLEAN { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 } - pub fn GetFinalPathNameByHandleW(_hFile: HANDLE, - _lpszFilePath: LPCWSTR, - _cchFilePath: DWORD, - _dwFlags: DWORD) -> DWORD { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } #[cfg(not(target_vendor = "uwp"))] pub fn SetThreadStackGuarantee(_size: *mut c_ulong) -> BOOL { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 @@ -1038,46 +1041,8 @@ compat_fn! { lpThreadDescription: LPCWSTR) -> HRESULT { SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); E_NOTIMPL } - pub fn SetFileInformationByHandle(_hFile: HANDLE, - _FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, - _lpFileInformation: LPVOID, - _dwBufferSize: DWORD) -> BOOL { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED as DWORD); 0 - } pub fn GetSystemTimePreciseAsFileTime(lpSystemTimeAsFileTime: LPFILETIME) -> () { GetSystemTimeAsFileTime(lpSystemTimeAsFileTime) } - pub fn SleepConditionVariableSRW(ConditionVariable: PCONDITION_VARIABLE, - SRWLock: PSRWLOCK, - dwMilliseconds: DWORD, - Flags: ULONG) -> BOOL { - panic!("condition variables not available") - } - pub fn WakeConditionVariable(ConditionVariable: PCONDITION_VARIABLE) - -> () { - panic!("condition variables not available") - } - pub fn WakeAllConditionVariable(ConditionVariable: PCONDITION_VARIABLE) - -> () { - panic!("condition variables not available") - } - pub fn AcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn AcquireSRWLockShared(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn ReleaseSRWLockExclusive(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn ReleaseSRWLockShared(SRWLock: PSRWLOCK) -> () { - panic!("rwlocks not available") - } - pub fn TryAcquireSRWLockExclusive(SRWLock: PSRWLOCK) -> BOOLEAN { - panic!("rwlocks not available") - } - pub fn TryAcquireSRWLockShared(SRWLock: PSRWLOCK) -> BOOLEAN { - panic!("rwlocks not available") - } } diff --git a/src/libstd/sys/windows/condvar.rs b/src/libstd/sys/windows/condvar.rs index 8f7f6854cc22c..4fa270c4837cd 100644 --- a/src/libstd/sys/windows/condvar.rs +++ b/src/libstd/sys/windows/condvar.rs @@ -1,11 +1,20 @@ +use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::cell::UnsafeCell; +use crate::ptr; use crate::sys::c; -use crate::sys::mutex::{self, Mutex}; -use crate::sys::os; +use crate::sys::mutex::Mutex; use crate::time::Duration; -pub struct Condvar { - inner: UnsafeCell, +const WAKEUP_MODE_NONE: usize = 0; +const WAKEUP_MODE_ONE: usize = 0x40000000; +const WAKEUP_MODE_ALL: usize = 0x80000000; +const WAKEUP_MODE_MASK: usize = WAKEUP_MODE_ONE | WAKEUP_MODE_ALL; +const SLEEPERS_COUNT_MASK: usize = !WAKEUP_MODE_MASK; + +pub struct Condvar { sleepersCountAndWakeupMode: AtomicUsize, + sleepWakeupSemaphore: UnsafeCell, + wakeOneEvent: UnsafeCell, + wakeAllEvent: UnsafeCell, } unsafe impl Send for Condvar {} @@ -13,44 +22,117 @@ unsafe impl Sync for Condvar {} impl Condvar { pub const fn new() -> Condvar { - Condvar { inner: UnsafeCell::new(c::CONDITION_VARIABLE_INIT) } + Condvar { + sleepersCountAndWakeupMode: AtomicUsize::new(WAKEUP_MODE_NONE), + sleepWakeupSemaphore: UnsafeCell::new(ptr::null_mut()), + wakeOneEvent: UnsafeCell::new(ptr::null_mut()), + wakeAllEvent: UnsafeCell::new(ptr::null_mut()), + } } - #[inline] - pub unsafe fn init(&mut self) {} + pub unsafe fn init(&mut self) { + *self.sleepWakeupSemaphore.get() = c::CreateSemaphoreW(ptr::null_mut(), 1, 1, ptr::null_mut()); + assert!(*self.sleepWakeupSemaphore.get() != ptr::null_mut()); + *self.wakeOneEvent.get() = c::CreateEventW(ptr::null_mut(), c::FALSE, c::FALSE, ptr::null_mut()); + assert!(*self.wakeOneEvent.get() != ptr::null_mut()); + *self.wakeAllEvent.get() = c::CreateEventW(ptr::null_mut(), c::TRUE, c::FALSE, ptr::null_mut()); + assert!(*self.wakeAllEvent.get() != ptr::null_mut()); + } - #[inline] pub unsafe fn wait(&self, mutex: &Mutex) { - let r = c::SleepConditionVariableSRW(self.inner.get(), mutex::raw(mutex), c::INFINITE, 0); - debug_assert!(r != 0); + Condvar::wait_timeout(self, mutex, Duration::from_secs(1000 * 365 * 86400)); } pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - let r = c::SleepConditionVariableSRW( - self.inner.get(), - mutex::raw(mutex), - super::dur2timeout(dur), - 0, - ); - if r == 0 { - debug_assert_eq!(os::errno() as usize, c::ERROR_TIMEOUT as usize); - false + let result = c::WaitForSingleObject(*self.sleepWakeupSemaphore.get(), c::INFINITE); + assert!(result == c::WAIT_OBJECT_0); + self.sleepersCountAndWakeupMode.fetch_add(1, Ordering::SeqCst); + let mut wcwm = self.sleepersCountAndWakeupMode.load(Ordering::SeqCst); + assert!((wcwm & WAKEUP_MODE_MASK) == 0); + let mut success = c::ReleaseSemaphore(*self.sleepWakeupSemaphore.get(), 1, ptr::null_mut()); + assert!(success != 0); + mutex.unlock(); + let handeles = [*self.wakeOneEvent.get(), *self.wakeAllEvent.get()]; + let waitResult = c::WaitForMultipleObjects(2, handeles.as_ptr(), c::FALSE, super::dur2timeout(dur)); + + let sub: i32; + if waitResult == c::WAIT_OBJECT_0 { + sub = 1 | WAKEUP_MODE_ONE as i32; + } else { + sub = 1; + } + + wcwm = self.sleepersCountAndWakeupMode.fetch_add(-sub as usize, Ordering::SeqCst) - sub as usize; + + let wakeupMode = wcwm & WAKEUP_MODE_MASK; + let sleepersCount = wcwm & SLEEPERS_COUNT_MASK; + + let mut releaseSleepWakeupSemaphore = false; + + if waitResult == c::WAIT_OBJECT_0 { + releaseSleepWakeupSemaphore = true; + } else if waitResult == c::WAIT_TIMEOUT && wakeupMode == WAKEUP_MODE_ONE && sleepersCount == 0 { + success = c::ResetEvent(*self.wakeOneEvent.get()); + assert!(success != 0); + self.sleepersCountAndWakeupMode.store(WAKEUP_MODE_NONE, Ordering::SeqCst); + releaseSleepWakeupSemaphore = true; + } else if wakeupMode == WAKEUP_MODE_ALL && sleepersCount == 0 { + success = c::ResetEvent(*self.wakeAllEvent.get()); + assert!(success != 0); + self.sleepersCountAndWakeupMode.store(WAKEUP_MODE_NONE, Ordering::SeqCst); + releaseSleepWakeupSemaphore = true; + } else if waitResult == c::WAIT_TIMEOUT && super::dur2timeout(dur) != c::INFINITE || + (waitResult == c::WAIT_OBJECT_0 + 1 &&wakeupMode == WAKEUP_MODE_ALL) { } else { - true + panic!("invalid wakeup condition"); + } + + if releaseSleepWakeupSemaphore { + success = c::ReleaseSemaphore(*self.sleepWakeupSemaphore.get(), 1, ptr::null_mut()); + assert!(success != 0); } + + mutex.lock(); + + if waitResult == c::WAIT_TIMEOUT { + c::SetLastError(c::ERROR_TIMEOUT); + return false; + } + + true } - #[inline] pub unsafe fn notify_one(&self) { - c::WakeConditionVariable(self.inner.get()) + Condvar::wakeup(self, WAKEUP_MODE_ONE, *self.wakeOneEvent.get()); } - #[inline] pub unsafe fn notify_all(&self) { - c::WakeAllConditionVariable(self.inner.get()) + Condvar::wakeup(self, WAKEUP_MODE_ALL, *self.wakeAllEvent.get()); } pub unsafe fn destroy(&self) { - // ... + assert!(self.sleepersCountAndWakeupMode.load(Ordering::SeqCst) == 0); + let mut r = c::CloseHandle(*self.sleepWakeupSemaphore.get()); + assert!(r != 0); + r = c::CloseHandle(*self.wakeOneEvent.get()); + assert!(r != 0); + r = c::CloseHandle(*self.wakeAllEvent.get()); + assert!(r != 0); + } + + unsafe fn wakeup(&self, wakeupMode: usize, wakeEvent: c::HANDLE) { + let result = c::WaitForSingleObject(*self.sleepWakeupSemaphore.get(), c::INFINITE); + assert!(result == c::WAIT_OBJECT_0); + let wcwm = self.sleepersCountAndWakeupMode.fetch_add(wakeupMode, Ordering::SeqCst); + let sleepersCount = wcwm & SLEEPERS_COUNT_MASK; + if sleepersCount > 0 { + let success = c::SetEvent(wakeEvent); + assert!(success != 0); + } else { + self.sleepersCountAndWakeupMode.store(WAKEUP_MODE_NONE, Ordering::SeqCst); + let success = c::ReleaseSemaphore(*self.sleepWakeupSemaphore.get(), 1, ptr::null_mut()); + assert!(success != 0); + } + } } diff --git a/src/libstd/sys/windows/fs.rs b/src/libstd/sys/windows/fs.rs index cdbfac267b9a1..b20671ea4b121 100644 --- a/src/libstd/sys/windows/fs.rs +++ b/src/libstd/sys/windows/fs.rs @@ -311,15 +311,19 @@ impl File { pub fn truncate(&self, size: u64) -> io::Result<()> { let mut info = c::FILE_END_OF_FILE_INFO { EndOfFile: size as c::LARGE_INTEGER }; let size = mem::size_of_val(&info); - cvt(unsafe { - c::SetFileInformationByHandle( - self.handle.raw(), - c::FileEndOfFileInfo, - &mut info as *mut _ as *mut _, - size as c::DWORD, - ) - })?; - Ok(()) + unsafe { + let mut io: c::IO_STATUS_BLOCK = mem::zeroed(); + if c::NtSetInformationFile(self.handle.raw(), + &mut io as *mut _ as *mut _, + &mut info as *mut _ as *mut _, + size as c::DWORD, + 20) == 0 { + Ok(()) + } + else { + Err(crate::io::Error::last_os_error()) + } + } } #[cfg(not(target_vendor = "uwp"))] @@ -539,15 +543,19 @@ impl File { FileAttributes: perm.attrs, }; let size = mem::size_of_val(&info); - cvt(unsafe { - c::SetFileInformationByHandle( - self.handle.raw(), - c::FileBasicInfo, - &mut info as *mut _ as *mut _, - size as c::DWORD, - ) - })?; - Ok(()) + unsafe { + let mut io: c::IO_STATUS_BLOCK = mem::zeroed(); + if c::NtSetInformationFile(self.handle.raw(), + &mut io as *mut _ as *mut _, + &mut info as *mut _ as *mut _, + size as c::DWORD, + 4) == 0 { + Ok(()) + } + else { + Err(crate::io::Error::last_os_error()) + } + } } } @@ -831,12 +839,53 @@ pub fn set_perm(p: &Path, perm: FilePermissions) -> io::Result<()> { } fn get_path(f: &File) -> io::Result { - super::fill_utf16_buf( - |buf, sz| unsafe { - c::GetFinalPathNameByHandleW(f.handle.raw(), buf, sz, c::VOLUME_NAME_DOS) - }, - |buf| PathBuf::from(OsString::from_wide(buf)), - ) + const MAX_PATH: c::DWORD = 1024; + const MAXSIZE: c::DWORD = MAX_PATH+4; + unsafe { + let mut drives = [0u16; MAX_PATH as usize]; + let mut path = [0u16; MAXSIZE as usize]; + let mut path2 = [0u16; MAX_PATH as usize]; + let mut sz: c::DWORD=MAXSIZE; + let mut ss: usize; + if c::NtQueryObject(f.handle.raw(),1,&mut path as *mut _ as *mut _,sz,&mut sz as *mut _ as *mut _) == 0 { + let mut i=0; + while path[i] != '\\' as u16 && i io::Result { diff --git a/src/libstd/sys/windows/mutex.rs b/src/libstd/sys/windows/mutex.rs index 63dfc640908e9..dbbae908c4a4f 100644 --- a/src/libstd/sys/windows/mutex.rs +++ b/src/libstd/sys/windows/mutex.rs @@ -20,10 +20,9 @@ //! detect recursive locks. use crate::cell::UnsafeCell; -use crate::mem::{self, MaybeUninit}; +use crate::mem::{MaybeUninit}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; -use crate::sys::compat; pub struct Mutex { lock: AtomicUsize, @@ -33,18 +32,6 @@ pub struct Mutex { unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} -#[derive(Clone, Copy)] -enum Kind { - SRWLock = 1, - CriticalSection = 2, -} - -#[inline] -pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK { - debug_assert!(mem::size_of::() <= mem::size_of_val(&m.lock)); - &m.lock as *const _ as *mut _ -} - impl Mutex { pub const fn new() -> Mutex { Mutex { @@ -57,22 +44,14 @@ impl Mutex { #[inline] pub unsafe fn init(&mut self) {} pub unsafe fn lock(&self) { - match kind() { - Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), - Kind::CriticalSection => { let re = self.remutex(); (*re).lock(); if !self.flag_locked() { (*re).unlock(); panic!("cannot recursively lock a mutex"); } - } - } } pub unsafe fn try_lock(&self) -> bool { - match kind() { - Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, - Kind::CriticalSection => { let re = self.remutex(); if !(*re).try_lock() { false @@ -82,26 +61,18 @@ impl Mutex { (*re).unlock(); false } - } - } } pub unsafe fn unlock(&self) { *self.held.get() = false; - match kind() { - Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), - Kind::CriticalSection => (*self.remutex()).unlock(), - } + (*self.remutex()).unlock() } pub unsafe fn destroy(&self) { - match kind() { - Kind::SRWLock => {} - Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) { + match self.lock.load(Ordering::SeqCst) { 0 => {} n => { Box::from_raw(n as *mut ReentrantMutex).destroy(); } - }, - } + } } unsafe fn remutex(&self) -> *mut ReentrantMutex { @@ -131,24 +102,6 @@ impl Mutex { } } -fn kind() -> Kind { - static KIND: AtomicUsize = AtomicUsize::new(0); - - let val = KIND.load(Ordering::SeqCst); - if val == Kind::SRWLock as usize { - return Kind::SRWLock; - } else if val == Kind::CriticalSection as usize { - return Kind::CriticalSection; - } - - let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") { - None => Kind::CriticalSection, - Some(..) => Kind::SRWLock, - }; - KIND.store(ret as usize, Ordering::SeqCst); - ret -} - pub struct ReentrantMutex { inner: UnsafeCell>, } @@ -162,7 +115,7 @@ impl ReentrantMutex { } pub unsafe fn init(&self) { - c::InitializeCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::InitializeCriticalSectionAndSpinCount((&mut *self.inner.get()).as_mut_ptr(), 2000); } pub unsafe fn lock(&self) { diff --git a/src/libstd/sys/windows/rwlock.rs b/src/libstd/sys/windows/rwlock.rs index a769326352c40..e14f7565b5121 100644 --- a/src/libstd/sys/windows/rwlock.rs +++ b/src/libstd/sys/windows/rwlock.rs @@ -1,8 +1,10 @@ use crate::cell::UnsafeCell; -use crate::sys::c; +use crate::sys::mutex::ReentrantMutex; +use crate::sync::atomic::{AtomicUsize, Ordering}; pub struct RWLock { - inner: UnsafeCell, + lock: AtomicUsize, + held: UnsafeCell, } unsafe impl Send for RWLock {} @@ -10,35 +12,79 @@ unsafe impl Sync for RWLock {} impl RWLock { pub const fn new() -> RWLock { - RWLock { inner: UnsafeCell::new(c::SRWLOCK_INIT) } + RWLock { + lock: AtomicUsize::new(0), + held: UnsafeCell::new(false), + } } #[inline] pub unsafe fn read(&self) { - c::AcquireSRWLockShared(self.inner.get()) + let re = self.remutex(); + (*re).lock(); + if !self.flag_locked() { + (*re).unlock(); + panic!("cannot recursively lock a mutex"); + } } #[inline] pub unsafe fn try_read(&self) -> bool { - c::TryAcquireSRWLockShared(self.inner.get()) != 0 + let re = self.remutex(); + if !(*re).try_lock() { + false + } else if self.flag_locked() { + true + } else { + (*re).unlock(); + false + } } #[inline] pub unsafe fn write(&self) { - c::AcquireSRWLockExclusive(self.inner.get()) + RWLock::read(&self); } #[inline] pub unsafe fn try_write(&self) -> bool { - c::TryAcquireSRWLockExclusive(self.inner.get()) != 0 + RWLock::try_read(&self) } #[inline] pub unsafe fn read_unlock(&self) { - c::ReleaseSRWLockShared(self.inner.get()) + *self.held.get() = false; + (*self.remutex()).unlock(); } #[inline] pub unsafe fn write_unlock(&self) { - c::ReleaseSRWLockExclusive(self.inner.get()) + RWLock::read_unlock(&self) } #[inline] pub unsafe fn destroy(&self) { - // ... + match self.lock.load(Ordering::SeqCst) { + 0 => {} + n => { Box::from_raw(n as *mut ReentrantMutex).destroy(); } + } + } + + unsafe fn remutex(&self) -> *mut ReentrantMutex { + match self.lock.load(Ordering::SeqCst) { + 0 => {} + n => return n as *mut _, + } + let re = box ReentrantMutex::uninitialized(); + re.init(); + let re = Box::into_raw(re); + match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { + 0 => re, + n => { Box::from_raw(re).destroy(); n as *mut _ } + } + } + + unsafe fn flag_locked(&self) -> bool { + if *self.held.get() { + false + } else { + *self.held.get() = true; + true + } + } }