diff options
| author | Chris Denton <chris@chrisdenton.dev> | 2024-03-03 22:06:00 +0000 |
|---|---|---|
| committer | Chris Denton <chris@chrisdenton.dev> | 2024-03-05 00:19:42 +0000 |
| commit | f700641bd9eb7ec3b36b4d44eafae35ba970eea4 (patch) | |
| tree | 2bcda35248fd9a6b15cd821e97e666549e44c36f /library/std/src/sys/locks | |
| parent | 89b78304e82dc5114e3b2faa0fbec747a28a2b37 (diff) | |
| download | rust-f700641bd9eb7ec3b36b4d44eafae35ba970eea4.tar.gz rust-f700641bd9eb7ec3b36b4d44eafae35ba970eea4.zip | |
Windows: Implement mutex using futex
Well, the Windows equivalent: `WaitOnAddress`, `WakeByAddressSingle` and `WakeByAddressAll`.
Diffstat (limited to 'library/std/src/sys/locks')
| -rw-r--r-- | library/std/src/sys/locks/condvar/mod.rs | 7 | ||||
| -rw-r--r-- | library/std/src/sys/locks/condvar/windows7.rs (renamed from library/std/src/sys/locks/condvar/windows.rs) | 0 | ||||
| -rw-r--r-- | library/std/src/sys/locks/mutex/futex.rs | 54 | ||||
| -rw-r--r-- | library/std/src/sys/locks/mutex/mod.rs | 7 | ||||
| -rw-r--r-- | library/std/src/sys/locks/mutex/windows7.rs (renamed from library/std/src/sys/locks/mutex/windows.rs) | 0 | ||||
| -rw-r--r-- | library/std/src/sys/locks/rwlock/mod.rs | 7 | ||||
| -rw-r--r-- | library/std/src/sys/locks/rwlock/windows7.rs (renamed from library/std/src/sys/locks/rwlock/windows.rs) | 0 |
7 files changed, 45 insertions, 30 deletions
diff --git a/library/std/src/sys/locks/condvar/mod.rs b/library/std/src/sys/locks/condvar/mod.rs index 126a42a2a4c..6849cacf88e 100644 --- a/library/std/src/sys/locks/condvar/mod.rs +++ b/library/std/src/sys/locks/condvar/mod.rs @@ -1,5 +1,6 @@ cfg_if::cfg_if! { if #[cfg(any( + all(target_os = "windows", not(target_vendor="win7")), target_os = "linux", target_os = "android", target_os = "freebsd", @@ -14,9 +15,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_family = "unix")] { mod pthread; pub use pthread::Condvar; - } else if #[cfg(target_os = "windows")] { - mod windows; - pub use windows::Condvar; + } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] { + mod windows7; + pub use windows7::Condvar; } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; pub use sgx::Condvar; diff --git a/library/std/src/sys/locks/condvar/windows.rs b/library/std/src/sys/locks/condvar/windows7.rs index 28a288335d2..28a288335d2 100644 --- a/library/std/src/sys/locks/condvar/windows.rs +++ b/library/std/src/sys/locks/condvar/windows7.rs diff --git a/library/std/src/sys/locks/mutex/futex.rs b/library/std/src/sys/locks/mutex/futex.rs index c01229586c3..7427cae94d6 100644 --- a/library/std/src/sys/locks/mutex/futex.rs +++ b/library/std/src/sys/locks/mutex/futex.rs @@ -1,30 +1,42 @@ use crate::sync::atomic::{ - AtomicU32, + self, Ordering::{Acquire, Relaxed, Release}, }; use crate::sys::futex::{futex_wait, futex_wake}; +cfg_if::cfg_if! { +if #[cfg(windows)] { + // On Windows we can have a smol futex + type Atomic = atomic::AtomicU8; + type State = u8; +} else { + type Atomic = atomic::AtomicU32; + type State = u32; +} +} + pub struct Mutex { - /// 0: unlocked - /// 1: locked, no other threads waiting - /// 2: locked, and other threads waiting (contended) - futex: AtomicU32, + futex: Atomic, } +const UNLOCKED: State = 0; +const LOCKED: State = 1; // locked, no other threads waiting +const CONTENDED: State = 2; // locked, and other threads waiting (contended) + impl Mutex { #[inline] pub const fn new() -> Self { - Self { futex: AtomicU32::new(0) } + Self { futex: Atomic::new(UNLOCKED) } } #[inline] pub fn try_lock(&self) -> bool { - self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_ok() + self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_ok() } #[inline] pub fn lock(&self) { - if self.futex.compare_exchange(0, 1, Acquire, Relaxed).is_err() { + if self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed).is_err() { self.lock_contended(); } } @@ -36,8 +48,8 @@ impl Mutex { // If it's unlocked now, attempt to take the lock // without marking it as contended. - if state == 0 { - match self.futex.compare_exchange(0, 1, Acquire, Relaxed) { + if state == UNLOCKED { + match self.futex.compare_exchange(UNLOCKED, LOCKED, Acquire, Relaxed) { Ok(_) => return, // Locked! Err(s) => state = s, } @@ -45,31 +57,31 @@ impl Mutex { loop { // Put the lock in contended state. - // We avoid an unnecessary write if it as already set to 2, + // We avoid an unnecessary write if it as already set to CONTENDED, // to be friendlier for the caches. - if state != 2 && self.futex.swap(2, Acquire) == 0 { - // We changed it from 0 to 2, so we just successfully locked it. + if state != CONTENDED && self.futex.swap(CONTENDED, Acquire) == UNLOCKED { + // We changed it from UNLOCKED to CONTENDED, so we just successfully locked it. return; } - // Wait for the futex to change state, assuming it is still 2. - futex_wait(&self.futex, 2, None); + // Wait for the futex to change state, assuming it is still CONTENDED. + futex_wait(&self.futex, CONTENDED, None); // Spin again after waking up. state = self.spin(); } } - fn spin(&self) -> u32 { + fn spin(&self) -> State { let mut spin = 100; loop { // We only use `load` (and not `swap` or `compare_exchange`) // while spinning, to be easier on the caches. let state = self.futex.load(Relaxed); - // We stop spinning when the mutex is unlocked (0), - // but also when it's contended (2). - if state != 1 || spin == 0 { + // We stop spinning when the mutex is UNLOCKED, + // but also when it's CONTENDED. + if state != LOCKED || spin == 0 { return state; } @@ -80,9 +92,9 @@ impl Mutex { #[inline] pub unsafe fn unlock(&self) { - if self.futex.swap(0, Release) == 2 { + if self.futex.swap(UNLOCKED, Release) == CONTENDED { // We only wake up one thread. When that thread locks the mutex, it - // will mark the mutex as contended (2) (see lock_contended above), + // will mark the mutex as CONTENDED (see lock_contended above), // which makes sure that any other waiting threads will also be // woken up eventually. self.wake(); diff --git a/library/std/src/sys/locks/mutex/mod.rs b/library/std/src/sys/locks/mutex/mod.rs index 710cb91fb14..73d9bd273de 100644 --- a/library/std/src/sys/locks/mutex/mod.rs +++ b/library/std/src/sys/locks/mutex/mod.rs @@ -1,5 +1,6 @@ cfg_if::cfg_if! { if #[cfg(any( + all(target_os = "windows", not(target_vendor = "win7")), target_os = "linux", target_os = "android", target_os = "freebsd", @@ -19,9 +20,9 @@ cfg_if::cfg_if! { ))] { mod pthread; pub use pthread::{Mutex, raw}; - } else if #[cfg(target_os = "windows")] { - mod windows; - pub use windows::{Mutex, raw}; + } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] { + mod windows7; + pub use windows7::{Mutex, raw}; } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; pub use sgx::Mutex; diff --git a/library/std/src/sys/locks/mutex/windows.rs b/library/std/src/sys/locks/mutex/windows7.rs index ef2f84082cd..ef2f84082cd 100644 --- a/library/std/src/sys/locks/mutex/windows.rs +++ b/library/std/src/sys/locks/mutex/windows7.rs diff --git a/library/std/src/sys/locks/rwlock/mod.rs b/library/std/src/sys/locks/rwlock/mod.rs index 0564f1fe6fa..675931c64bd 100644 --- a/library/std/src/sys/locks/rwlock/mod.rs +++ b/library/std/src/sys/locks/rwlock/mod.rs @@ -1,5 +1,6 @@ cfg_if::cfg_if! { if #[cfg(any( + all(target_os = "windows", not(target_vendor = "win7")), target_os = "linux", target_os = "android", target_os = "freebsd", @@ -14,9 +15,9 @@ cfg_if::cfg_if! { } else if #[cfg(target_family = "unix")] { mod queue; pub use queue::RwLock; - } else if #[cfg(target_os = "windows")] { - mod windows; - pub use windows::RwLock; + } else if #[cfg(all(target_os = "windows", target_vendor = "win7"))] { + mod windows7; + pub use windows7::RwLock; } else if #[cfg(all(target_vendor = "fortanix", target_env = "sgx"))] { mod sgx; pub use sgx::RwLock; diff --git a/library/std/src/sys/locks/rwlock/windows.rs b/library/std/src/sys/locks/rwlock/windows7.rs index e69415baac4..e69415baac4 100644 --- a/library/std/src/sys/locks/rwlock/windows.rs +++ b/library/std/src/sys/locks/rwlock/windows7.rs |
