]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/windows/mutex.rs
Auto merge of #35856 - phimuemue:master, r=brson
[rust.git] / src / libstd / sys / windows / mutex.rs
1 // Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 //! System Mutexes
12 //!
13 //! The Windows implementation of mutexes is a little odd and it may not be
14 //! immediately obvious what's going on. The primary oddness is that SRWLock is
15 //! used instead of CriticalSection, and this is done because:
16 //!
17 //! 1. SRWLock is several times faster than CriticalSection according to
18 //!    benchmarks performed on both Windows 8 and Windows 7.
19 //!
20 //! 2. CriticalSection allows recursive locking while SRWLock deadlocks. The
21 //!    Unix implementation deadlocks so consistency is preferred. See #19962 for
22 //!    more details.
23 //!
24 //! 3. While CriticalSection is fair and SRWLock is not, the current Rust policy
25 //!    is that there are no guarantees of fairness.
26 //!
27 //! The downside of this approach, however, is that SRWLock is not available on
28 //! Windows XP, so we continue to have a fallback implementation where
29 //! CriticalSection is used and we keep track of who's holding the mutex to
30 //! detect recursive locks.
31
32 use cell::UnsafeCell;
33 use mem;
34 use sync::atomic::{AtomicUsize, Ordering};
35 use sys::c;
36 use sys::compat;
37
38 pub struct Mutex {
39     lock: AtomicUsize,
40     held: UnsafeCell<bool>,
41 }
42
43 unsafe impl Send for Mutex {}
44 unsafe impl Sync for Mutex {}
45
46 #[derive(Clone, Copy)]
47 enum Kind {
48     SRWLock = 1,
49     CriticalSection = 2,
50 }
51
52 #[inline]
53 pub unsafe fn raw(m: &Mutex) -> c::PSRWLOCK {
54     debug_assert!(mem::size_of::<c::SRWLOCK>() <= mem::size_of_val(&m.lock));
55     &m.lock as *const _ as *mut _
56 }
57
58 impl Mutex {
59     pub const fn new() -> Mutex {
60         Mutex {
61             lock: AtomicUsize::new(0),
62             held: UnsafeCell::new(false),
63         }
64     }
65     #[inline]
66     pub unsafe fn init(&mut self) {}
67     pub unsafe fn lock(&self) {
68         match kind() {
69             Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)),
70             Kind::CriticalSection => {
71                 let re = self.remutex();
72                 (*re).lock();
73                 if !self.flag_locked() {
74                     (*re).unlock();
75                     panic!("cannot recursively lock a mutex");
76                 }
77             }
78         }
79     }
80     pub unsafe fn try_lock(&self) -> bool {
81         match kind() {
82             Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0,
83             Kind::CriticalSection => {
84                 let re = self.remutex();
85                 if !(*re).try_lock() {
86                     false
87                 } else if self.flag_locked() {
88                     true
89                 } else {
90                     (*re).unlock();
91                     false
92                 }
93             }
94         }
95     }
96     pub unsafe fn unlock(&self) {
97         *self.held.get() = false;
98         match kind() {
99             Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)),
100             Kind::CriticalSection => (*self.remutex()).unlock(),
101         }
102     }
103     pub unsafe fn destroy(&self) {
104         match kind() {
105             Kind::SRWLock => {}
106             Kind::CriticalSection => {
107                 match self.lock.load(Ordering::SeqCst) {
108                     0 => {}
109                     n => { Box::from_raw(n as *mut ReentrantMutex).destroy(); }
110                 }
111             }
112         }
113     }
114
115     unsafe fn remutex(&self) -> *mut ReentrantMutex {
116         match self.lock.load(Ordering::SeqCst) {
117             0 => {}
118             n => return n as *mut _,
119         }
120         let mut re = Box::new(ReentrantMutex::uninitialized());
121         re.init();
122         let re = Box::into_raw(re);
123         match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) {
124             0 => re,
125             n => { Box::from_raw(re).destroy(); n as *mut _ }
126         }
127     }
128
129     unsafe fn flag_locked(&self) -> bool {
130         if *self.held.get() {
131             false
132         } else {
133             *self.held.get() = true;
134             true
135         }
136
137     }
138 }
139
140 fn kind() -> Kind {
141     static KIND: AtomicUsize = AtomicUsize::new(0);
142
143     let val = KIND.load(Ordering::SeqCst);
144     if val == Kind::SRWLock as usize {
145         return Kind::SRWLock
146     } else if val == Kind::CriticalSection as usize {
147         return Kind::CriticalSection
148     }
149
150     let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") {
151         None => Kind::CriticalSection,
152         Some(..) => Kind::SRWLock,
153     };
154     KIND.store(ret as usize, Ordering::SeqCst);
155     return ret;
156 }
157
158 pub struct ReentrantMutex { inner: UnsafeCell<c::CRITICAL_SECTION> }
159
160 unsafe impl Send for ReentrantMutex {}
161 unsafe impl Sync for ReentrantMutex {}
162
163 impl ReentrantMutex {
164     pub unsafe fn uninitialized() -> ReentrantMutex {
165         mem::uninitialized()
166     }
167
168     pub unsafe fn init(&mut self) {
169         c::InitializeCriticalSection(self.inner.get());
170     }
171
172     pub unsafe fn lock(&self) {
173         c::EnterCriticalSection(self.inner.get());
174     }
175
176     #[inline]
177     pub unsafe fn try_lock(&self) -> bool {
178         c::TryEnterCriticalSection(self.inner.get()) != 0
179     }
180
181     pub unsafe fn unlock(&self) {
182         c::LeaveCriticalSection(self.inner.get());
183     }
184
185     pub unsafe fn destroy(&self) {
186         c::DeleteCriticalSection(self.inner.get());
187     }
188 }