]> git.lizzy.rs Git - rust.git/blob - src/librustrt/mutex.rs
auto merge of #14788 : Sawyer47/rust/issue-13214, r=huonw
[rust.git] / src / librustrt / mutex.rs
1 // Copyright 2013-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 //! A native mutex and condition variable type.
12 //!
13 //! This module contains bindings to the platform's native mutex/condition
14 //! variable primitives. It provides two types: `StaticNativeMutex`, which can
15 //! be statically initialized via the `NATIVE_MUTEX_INIT` value, and a simple
16 //! wrapper `NativeMutex` that has a destructor to clean up after itself. These
17 //! objects serve as both mutexes and condition variables simultaneously.
18 //!
19 //! The static lock is lazily initialized, but it can only be unsafely
20 //! destroyed. A statically initialized lock doesn't necessarily have a time at
21 //! which it can get deallocated. For this reason, there is no `Drop`
22 //! implementation of the static mutex, but rather the `destroy()` method must
23 //! be invoked manually if destruction of the mutex is desired.
24 //!
25 //! The non-static `NativeMutex` type does have a destructor, but cannot be
26 //! statically initialized.
27 //!
28 //! It is not recommended to use this type for idiomatic rust use. These types
29 //! are appropriate where no other options are available, but other rust
30 //! concurrency primitives should be used before them: the `sync` crate defines
31 //! `StaticMutex` and `Mutex` types.
32 //!
33 //! # Example
34 //!
35 //! ```rust
36 //! use std::rt::mutex::{NativeMutex, StaticNativeMutex, NATIVE_MUTEX_INIT};
37 //!
38 //! // Use a statically initialized mutex
39 //! static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
40 //!
41 //! unsafe {
42 //!     let _guard = LOCK.lock();
43 //! } // automatically unlocked here
44 //!
45 //! // Use a normally initialized mutex
46 //! unsafe {
47 //!     let mut lock = NativeMutex::new();
48 //!
49 //!     {
50 //!         let _guard = lock.lock();
51 //!     } // unlocked here
52 //!
53 //!     // sometimes the RAII guard isn't appropriate
54 //!     lock.lock_noguard();
55 //!     lock.unlock_noguard();
56 //! } // `lock` is deallocated here
57 //! ```
58
59 #![allow(non_camel_case_types)]
60
61 use core::prelude::*;
62
63 /// A native mutex suitable for storing in statics (that is, it has
64 /// the `destroy` method rather than a destructor).
65 ///
66 /// Prefer the `NativeMutex` type where possible, since that does not
67 /// require manual deallocation.
68 pub struct StaticNativeMutex {
69     inner: imp::Mutex,
70 }
71
72 /// A native mutex with a destructor for clean-up.
73 ///
74 /// See `StaticNativeMutex` for a version that is suitable for storing in
75 /// statics.
76 pub struct NativeMutex {
77     inner: StaticNativeMutex
78 }
79
80 /// Automatically unlocks the mutex that it was created from on
81 /// destruction.
82 ///
83 /// Using this makes lock-based code resilient to unwinding/task
84 /// failure, because the lock will be automatically unlocked even
85 /// then.
86 #[must_use]
87 pub struct LockGuard<'a> {
88     lock: &'a StaticNativeMutex
89 }
90
91 pub static NATIVE_MUTEX_INIT: StaticNativeMutex = StaticNativeMutex {
92     inner: imp::MUTEX_INIT,
93 };
94
95 impl StaticNativeMutex {
96     /// Creates a new mutex.
97     ///
98     /// Note that a mutex created in this way needs to be explicit
99     /// freed with a call to `destroy` or it will leak.
100     /// Also it is important to avoid locking until mutex has stopped moving
101     pub unsafe fn new() -> StaticNativeMutex {
102         StaticNativeMutex { inner: imp::Mutex::new() }
103     }
104
105     /// Acquires this lock. This assumes that the current thread does not
106     /// already hold the lock.
107     ///
108     /// # Example
109     ///
110     /// ```rust
111     /// use std::rt::mutex::{StaticNativeMutex, NATIVE_MUTEX_INIT};
112     /// static mut LOCK: StaticNativeMutex = NATIVE_MUTEX_INIT;
113     /// unsafe {
114     ///     let _guard = LOCK.lock();
115     ///     // critical section...
116     /// } // automatically unlocked in `_guard`'s destructor
117     /// ```
118     pub unsafe fn lock<'a>(&'a self) -> LockGuard<'a> {
119         self.inner.lock();
120
121         LockGuard { lock: self }
122     }
123
124     /// Attempts to acquire the lock. The value returned is `Some` if
125     /// the attempt succeeded.
126     pub unsafe fn trylock<'a>(&'a self) -> Option<LockGuard<'a>> {
127         if self.inner.trylock() {
128             Some(LockGuard { lock: self })
129         } else {
130             None
131         }
132     }
133
134     /// Acquire the lock without creating a `LockGuard`.
135     ///
136     /// These needs to be paired with a call to `.unlock_noguard`. Prefer using
137     /// `.lock`.
138     pub unsafe fn lock_noguard(&self) { self.inner.lock() }
139
140     /// Attempts to acquire the lock without creating a
141     /// `LockGuard`. The value returned is whether the lock was
142     /// acquired or not.
143     ///
144     /// If `true` is returned, this needs to be paired with a call to
145     /// `.unlock_noguard`. Prefer using `.trylock`.
146     pub unsafe fn trylock_noguard(&self) -> bool {
147         self.inner.trylock()
148     }
149
150     /// Unlocks the lock. This assumes that the current thread already holds the
151     /// lock.
152     pub unsafe fn unlock_noguard(&self) { self.inner.unlock() }
153
154     /// Block on the internal condition variable.
155     ///
156     /// This function assumes that the lock is already held. Prefer
157     /// using `LockGuard.wait` since that guarantees that the lock is
158     /// held.
159     pub unsafe fn wait_noguard(&self) { self.inner.wait() }
160
161     /// Signals a thread in `wait` to wake up
162     pub unsafe fn signal_noguard(&self) { self.inner.signal() }
163
164     /// This function is especially unsafe because there are no guarantees made
165     /// that no other thread is currently holding the lock or waiting on the
166     /// condition variable contained inside.
167     pub unsafe fn destroy(&self) { self.inner.destroy() }
168 }
169
170 impl NativeMutex {
171     /// Creates a new mutex.
172     ///
173     /// The user must be careful to ensure the mutex is not locked when its is
174     /// being destroyed.
175     /// Also it is important to avoid locking until mutex has stopped moving
176     pub unsafe fn new() -> NativeMutex {
177         NativeMutex { inner: StaticNativeMutex::new() }
178     }
179
180     /// Acquires this lock. This assumes that the current thread does not
181     /// already hold the lock.
182     ///
183     /// # Example
184     /// ```rust
185     /// use std::rt::mutex::NativeMutex;
186     /// unsafe {
187     ///     let mut lock = NativeMutex::new();
188     ///
189     ///     {
190     ///         let _guard = lock.lock();
191     ///         // critical section...
192     ///     } // automatically unlocked in `_guard`'s destructor
193     /// }
194     /// ```
195     pub unsafe fn lock<'a>(&'a self) -> LockGuard<'a> {
196         self.inner.lock()
197     }
198
199     /// Attempts to acquire the lock. The value returned is `Some` if
200     /// the attempt succeeded.
201     pub unsafe fn trylock<'a>(&'a self) -> Option<LockGuard<'a>> {
202         self.inner.trylock()
203     }
204
205     /// Acquire the lock without creating a `LockGuard`.
206     ///
207     /// These needs to be paired with a call to `.unlock_noguard`. Prefer using
208     /// `.lock`.
209     pub unsafe fn lock_noguard(&self) { self.inner.lock_noguard() }
210
211     /// Attempts to acquire the lock without creating a
212     /// `LockGuard`. The value returned is whether the lock was
213     /// acquired or not.
214     ///
215     /// If `true` is returned, this needs to be paired with a call to
216     /// `.unlock_noguard`. Prefer using `.trylock`.
217     pub unsafe fn trylock_noguard(&self) -> bool {
218         self.inner.trylock_noguard()
219     }
220
221     /// Unlocks the lock. This assumes that the current thread already holds the
222     /// lock.
223     pub unsafe fn unlock_noguard(&self) { self.inner.unlock_noguard() }
224
225     /// Block on the internal condition variable.
226     ///
227     /// This function assumes that the lock is already held. Prefer
228     /// using `LockGuard.wait` since that guarantees that the lock is
229     /// held.
230     pub unsafe fn wait_noguard(&self) { self.inner.wait_noguard() }
231
232     /// Signals a thread in `wait` to wake up
233     pub unsafe fn signal_noguard(&self) { self.inner.signal_noguard() }
234 }
235
236 impl Drop for NativeMutex {
237     fn drop(&mut self) {
238         unsafe {self.inner.destroy()}
239     }
240 }
241
242 impl<'a> LockGuard<'a> {
243     /// Block on the internal condition variable.
244     pub unsafe fn wait(&self) {
245         self.lock.wait_noguard()
246     }
247
248     /// Signals a thread in `wait` to wake up.
249     pub unsafe fn signal(&self) {
250         self.lock.signal_noguard()
251     }
252 }
253
254 #[unsafe_destructor]
255 impl<'a> Drop for LockGuard<'a> {
256     fn drop(&mut self) {
257         unsafe {self.lock.unlock_noguard()}
258     }
259 }
260
261 #[cfg(unix)]
262 mod imp {
263     use libc;
264     use self::os::{PTHREAD_MUTEX_INITIALIZER, PTHREAD_COND_INITIALIZER,
265                    pthread_mutex_t, pthread_cond_t};
266     use core::ty::Unsafe;
267     use core::kinds::marker;
268
269     type pthread_mutexattr_t = libc::c_void;
270     type pthread_condattr_t = libc::c_void;
271
272     #[cfg(target_os = "freebsd")]
273     mod os {
274         use libc;
275
276         pub type pthread_mutex_t = *libc::c_void;
277         pub type pthread_cond_t = *libc::c_void;
278
279         pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t =
280             0 as pthread_mutex_t;
281         pub static PTHREAD_COND_INITIALIZER: pthread_cond_t =
282             0 as pthread_cond_t;
283     }
284
285     #[cfg(target_os = "macos")]
286     mod os {
287         use libc;
288
289         #[cfg(target_arch = "x86_64")]
290         static __PTHREAD_MUTEX_SIZE__: uint = 56;
291         #[cfg(target_arch = "x86_64")]
292         static __PTHREAD_COND_SIZE__: uint = 40;
293         #[cfg(target_arch = "x86")]
294         static __PTHREAD_MUTEX_SIZE__: uint = 40;
295         #[cfg(target_arch = "x86")]
296         static __PTHREAD_COND_SIZE__: uint = 24;
297
298         static _PTHREAD_MUTEX_SIG_init: libc::c_long = 0x32AAABA7;
299         static _PTHREAD_COND_SIG_init: libc::c_long = 0x3CB0B1BB;
300
301         #[repr(C)]
302         pub struct pthread_mutex_t {
303             __sig: libc::c_long,
304             __opaque: [u8, ..__PTHREAD_MUTEX_SIZE__],
305         }
306         #[repr(C)]
307         pub struct pthread_cond_t {
308             __sig: libc::c_long,
309             __opaque: [u8, ..__PTHREAD_COND_SIZE__],
310         }
311
312         pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
313             __sig: _PTHREAD_MUTEX_SIG_init,
314             __opaque: [0, ..__PTHREAD_MUTEX_SIZE__],
315         };
316         pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
317             __sig: _PTHREAD_COND_SIG_init,
318             __opaque: [0, ..__PTHREAD_COND_SIZE__],
319         };
320     }
321
322     #[cfg(target_os = "linux")]
323     mod os {
324         use libc;
325
326         // minus 8 because we have an 'align' field
327         #[cfg(target_arch = "x86_64")]
328         static __SIZEOF_PTHREAD_MUTEX_T: uint = 40 - 8;
329         #[cfg(target_arch = "x86")]
330         static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
331         #[cfg(target_arch = "arm")]
332         static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
333         #[cfg(target_arch = "mips")]
334         static __SIZEOF_PTHREAD_MUTEX_T: uint = 24 - 8;
335         #[cfg(target_arch = "x86_64")]
336         static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
337         #[cfg(target_arch = "x86")]
338         static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
339         #[cfg(target_arch = "arm")]
340         static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
341         #[cfg(target_arch = "mips")]
342         static __SIZEOF_PTHREAD_COND_T: uint = 48 - 8;
343
344         #[repr(C)]
345         pub struct pthread_mutex_t {
346             __align: libc::c_longlong,
347             size: [u8, ..__SIZEOF_PTHREAD_MUTEX_T],
348         }
349         #[repr(C)]
350         pub struct pthread_cond_t {
351             __align: libc::c_longlong,
352             size: [u8, ..__SIZEOF_PTHREAD_COND_T],
353         }
354
355         pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
356             __align: 0,
357             size: [0, ..__SIZEOF_PTHREAD_MUTEX_T],
358         };
359         pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
360             __align: 0,
361             size: [0, ..__SIZEOF_PTHREAD_COND_T],
362         };
363     }
364     #[cfg(target_os = "android")]
365     mod os {
366         use libc;
367
368         #[repr(C)]
369         pub struct pthread_mutex_t { value: libc::c_int }
370         #[repr(C)]
371         pub struct pthread_cond_t { value: libc::c_int }
372
373         pub static PTHREAD_MUTEX_INITIALIZER: pthread_mutex_t = pthread_mutex_t {
374             value: 0,
375         };
376         pub static PTHREAD_COND_INITIALIZER: pthread_cond_t = pthread_cond_t {
377             value: 0,
378         };
379     }
380
381     pub struct Mutex {
382         lock: Unsafe<pthread_mutex_t>,
383         cond: Unsafe<pthread_cond_t>,
384     }
385
386     pub static MUTEX_INIT: Mutex = Mutex {
387         lock: Unsafe {
388             value: PTHREAD_MUTEX_INITIALIZER,
389             marker1: marker::InvariantType,
390         },
391         cond: Unsafe {
392             value: PTHREAD_COND_INITIALIZER,
393             marker1: marker::InvariantType,
394         },
395     };
396
397     impl Mutex {
398         pub unsafe fn new() -> Mutex {
399             // As mutex might be moved and address is changing it
400             // is better to avoid initialization of potentially
401             // opaque OS data before it landed
402             let m = Mutex {
403                 lock: Unsafe::new(PTHREAD_MUTEX_INITIALIZER),
404                 cond: Unsafe::new(PTHREAD_COND_INITIALIZER),
405             };
406
407             return m;
408         }
409
410         pub unsafe fn lock(&self) { pthread_mutex_lock(self.lock.get()); }
411         pub unsafe fn unlock(&self) { pthread_mutex_unlock(self.lock.get()); }
412         pub unsafe fn signal(&self) { pthread_cond_signal(self.cond.get()); }
413         pub unsafe fn wait(&self) {
414             pthread_cond_wait(self.cond.get(), self.lock.get());
415         }
416         pub unsafe fn trylock(&self) -> bool {
417             pthread_mutex_trylock(self.lock.get()) == 0
418         }
419         pub unsafe fn destroy(&self) {
420             pthread_mutex_destroy(self.lock.get());
421             pthread_cond_destroy(self.cond.get());
422         }
423     }
424
425     extern {
426         fn pthread_mutex_destroy(lock: *mut pthread_mutex_t) -> libc::c_int;
427         fn pthread_cond_destroy(cond: *mut pthread_cond_t) -> libc::c_int;
428         fn pthread_mutex_lock(lock: *mut pthread_mutex_t) -> libc::c_int;
429         fn pthread_mutex_trylock(lock: *mut pthread_mutex_t) -> libc::c_int;
430         fn pthread_mutex_unlock(lock: *mut pthread_mutex_t) -> libc::c_int;
431
432         fn pthread_cond_wait(cond: *mut pthread_cond_t,
433                              lock: *mut pthread_mutex_t) -> libc::c_int;
434         fn pthread_cond_signal(cond: *mut pthread_cond_t) -> libc::c_int;
435     }
436 }
437
438 #[cfg(windows)]
439 mod imp {
440     use alloc::libc_heap::malloc_raw;
441     use core::atomics;
442     use core::ptr;
443     use libc::{HANDLE, BOOL, LPSECURITY_ATTRIBUTES, c_void, DWORD, LPCSTR};
444     use libc;
445
446     type LPCRITICAL_SECTION = *mut c_void;
447     static SPIN_COUNT: DWORD = 4000;
448     #[cfg(target_arch = "x86")]
449     static CRIT_SECTION_SIZE: uint = 24;
450     #[cfg(target_arch = "x86_64")]
451     static CRIT_SECTION_SIZE: uint = 40;
452
453     pub struct Mutex {
454         // pointers for the lock/cond handles, atomically updated
455         lock: atomics::AtomicUint,
456         cond: atomics::AtomicUint,
457     }
458
459     pub static MUTEX_INIT: Mutex = Mutex {
460         lock: atomics::INIT_ATOMIC_UINT,
461         cond: atomics::INIT_ATOMIC_UINT,
462     };
463
464     impl Mutex {
465         pub unsafe fn new() -> Mutex {
466             Mutex {
467                 lock: atomics::AtomicUint::new(init_lock()),
468                 cond: atomics::AtomicUint::new(init_cond()),
469             }
470         }
471         pub unsafe fn lock(&self) {
472             EnterCriticalSection(self.getlock() as LPCRITICAL_SECTION)
473         }
474         pub unsafe fn trylock(&self) -> bool {
475             TryEnterCriticalSection(self.getlock() as LPCRITICAL_SECTION) != 0
476         }
477         pub unsafe fn unlock(&self) {
478             LeaveCriticalSection(self.getlock() as LPCRITICAL_SECTION)
479         }
480
481         pub unsafe fn wait(&self) {
482             self.unlock();
483             WaitForSingleObject(self.getcond() as HANDLE, libc::INFINITE);
484             self.lock();
485         }
486
487         pub unsafe fn signal(&self) {
488             assert!(SetEvent(self.getcond() as HANDLE) != 0);
489         }
490
491         /// This function is especially unsafe because there are no guarantees made
492         /// that no other thread is currently holding the lock or waiting on the
493         /// condition variable contained inside.
494         pub unsafe fn destroy(&self) {
495             let lock = self.lock.swap(0, atomics::SeqCst);
496             let cond = self.cond.swap(0, atomics::SeqCst);
497             if lock != 0 { free_lock(lock) }
498             if cond != 0 { free_cond(cond) }
499         }
500
501         unsafe fn getlock(&self) -> *mut c_void {
502             match self.lock.load(atomics::SeqCst) {
503                 0 => {}
504                 n => return n as *mut c_void
505             }
506             let lock = init_lock();
507             match self.lock.compare_and_swap(0, lock, atomics::SeqCst) {
508                 0 => return lock as *mut c_void,
509                 _ => {}
510             }
511             free_lock(lock);
512             return self.lock.load(atomics::SeqCst) as *mut c_void;
513         }
514
515         unsafe fn getcond(&self) -> *mut c_void {
516             match self.cond.load(atomics::SeqCst) {
517                 0 => {}
518                 n => return n as *mut c_void
519             }
520             let cond = init_cond();
521             match self.cond.compare_and_swap(0, cond, atomics::SeqCst) {
522                 0 => return cond as *mut c_void,
523                 _ => {}
524             }
525             free_cond(cond);
526             return self.cond.load(atomics::SeqCst) as *mut c_void;
527         }
528     }
529
530     pub unsafe fn init_lock() -> uint {
531         let block = malloc_raw(CRIT_SECTION_SIZE as uint) as *mut c_void;
532         InitializeCriticalSectionAndSpinCount(block, SPIN_COUNT);
533         return block as uint;
534     }
535
536     pub unsafe fn init_cond() -> uint {
537         return CreateEventA(ptr::mut_null(), libc::FALSE, libc::FALSE,
538                             ptr::null()) as uint;
539     }
540
541     pub unsafe fn free_lock(h: uint) {
542         DeleteCriticalSection(h as LPCRITICAL_SECTION);
543         libc::free(h as *mut c_void);
544     }
545
546     pub unsafe fn free_cond(h: uint) {
547         let block = h as HANDLE;
548         libc::CloseHandle(block);
549     }
550
551     #[allow(non_snake_case_functions)]
552     extern "system" {
553         fn CreateEventA(lpSecurityAttributes: LPSECURITY_ATTRIBUTES,
554                         bManualReset: BOOL,
555                         bInitialState: BOOL,
556                         lpName: LPCSTR) -> HANDLE;
557         fn InitializeCriticalSectionAndSpinCount(
558                         lpCriticalSection: LPCRITICAL_SECTION,
559                         dwSpinCount: DWORD) -> BOOL;
560         fn DeleteCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
561         fn EnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
562         fn LeaveCriticalSection(lpCriticalSection: LPCRITICAL_SECTION);
563         fn TryEnterCriticalSection(lpCriticalSection: LPCRITICAL_SECTION) -> BOOL;
564         fn SetEvent(hEvent: HANDLE) -> BOOL;
565         fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) -> DWORD;
566     }
567 }
568
569 #[cfg(test)]
570 mod test {
571     use std::prelude::*;
572
573     use std::mem::drop;
574     use super::{StaticNativeMutex, NATIVE_MUTEX_INIT};
575     use std::rt::thread::Thread;
576
577     #[test]
578     fn smoke_lock() {
579         static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
580         unsafe {
581             let _guard = lock.lock();
582         }
583     }
584
585     #[test]
586     fn smoke_cond() {
587         static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
588         unsafe {
589             let guard = lock.lock();
590             let t = Thread::start(proc() {
591                 let guard = lock.lock();
592                 guard.signal();
593             });
594             guard.wait();
595             drop(guard);
596
597             t.join();
598         }
599     }
600
601     #[test]
602     fn smoke_lock_noguard() {
603         static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
604         unsafe {
605             lock.lock_noguard();
606             lock.unlock_noguard();
607         }
608     }
609
610     #[test]
611     fn smoke_cond_noguard() {
612         static mut lock: StaticNativeMutex = NATIVE_MUTEX_INIT;
613         unsafe {
614             lock.lock_noguard();
615             let t = Thread::start(proc() {
616                 lock.lock_noguard();
617                 lock.signal_noguard();
618                 lock.unlock_noguard();
619             });
620             lock.wait_noguard();
621             lock.unlock_noguard();
622
623             t.join();
624         }
625     }
626
627     #[test]
628     fn destroy_immediately() {
629         unsafe {
630             let m = StaticNativeMutex::new();
631             m.destroy();
632         }
633     }
634 }