]>
Commit | Line | Data |
---|---|---|
1a4d82fc JJ |
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 | ||
c34b1796 AL |
11 | use prelude::v1::*; |
12 | ||
d9579d0f | 13 | use libc; |
1a4d82fc JJ |
14 | use cell::UnsafeCell; |
15 | use sys::sync as ffi; | |
16 | ||
17 | pub struct RWLock { inner: UnsafeCell<ffi::pthread_rwlock_t> } | |
18 | ||
19 | pub const RWLOCK_INIT: RWLock = RWLock { | |
20 | inner: UnsafeCell { value: ffi::PTHREAD_RWLOCK_INITIALIZER }, | |
21 | }; | |
22 | ||
c34b1796 AL |
23 | unsafe impl Send for RWLock {} |
24 | unsafe impl Sync for RWLock {} | |
25 | ||
1a4d82fc | 26 | impl RWLock { |
1a4d82fc JJ |
27 | #[inline] |
28 | pub unsafe fn read(&self) { | |
29 | let r = ffi::pthread_rwlock_rdlock(self.inner.get()); | |
d9579d0f AL |
30 | |
31 | // According to the pthread_rwlock_rdlock spec, this function **may** | |
32 | // fail with EDEADLK if a deadlock is detected. On the other hand | |
33 | // pthread mutexes will *never* return EDEADLK if they are initialized | |
34 | // as the "fast" kind (which ours always are). As a result, a deadlock | |
35 | // situation may actually return from the call to pthread_rwlock_rdlock | |
36 | // instead of blocking forever (as mutexes and Windows rwlocks do). Note | |
37 | // that not all unix implementations, however, will return EDEADLK for | |
38 | // their rwlocks. | |
39 | // | |
40 | // We roughly maintain the deadlocking behavior by panicking to ensure | |
41 | // that this lock acquisition does not succeed. | |
42 | if r == libc::EDEADLK { | |
43 | panic!("rwlock read lock would result in deadlock"); | |
44 | } else { | |
45 | debug_assert_eq!(r, 0); | |
46 | } | |
1a4d82fc JJ |
47 | } |
48 | #[inline] | |
49 | pub unsafe fn try_read(&self) -> bool { | |
50 | ffi::pthread_rwlock_tryrdlock(self.inner.get()) == 0 | |
51 | } | |
52 | #[inline] | |
53 | pub unsafe fn write(&self) { | |
54 | let r = ffi::pthread_rwlock_wrlock(self.inner.get()); | |
d9579d0f AL |
55 | // see comments above for why we check for EDEADLK |
56 | if r == libc::EDEADLK { | |
57 | panic!("rwlock write lock would result in deadlock"); | |
58 | } else { | |
59 | debug_assert_eq!(r, 0); | |
60 | } | |
1a4d82fc JJ |
61 | } |
62 | #[inline] | |
63 | pub unsafe fn try_write(&self) -> bool { | |
64 | ffi::pthread_rwlock_trywrlock(self.inner.get()) == 0 | |
65 | } | |
66 | #[inline] | |
67 | pub unsafe fn read_unlock(&self) { | |
68 | let r = ffi::pthread_rwlock_unlock(self.inner.get()); | |
69 | debug_assert_eq!(r, 0); | |
70 | } | |
71 | #[inline] | |
72 | pub unsafe fn write_unlock(&self) { self.read_unlock() } | |
73 | #[inline] | |
85aaf69f | 74 | pub unsafe fn destroy(&self) { |
85aaf69f SL |
75 | let r = ffi::pthread_rwlock_destroy(self.inner.get()); |
76 | // On DragonFly pthread_rwlock_destroy() returns EINVAL if called on a | |
77 | // rwlock that was just initialized with | |
78 | // ffi::PTHREAD_RWLOCK_INITIALIZER. Once it is used (locked/unlocked) | |
79 | // or pthread_rwlock_init() is called, this behaviour no longer occurs. | |
d9579d0f AL |
80 | if cfg!(target_os = "dragonfly") { |
81 | debug_assert!(r == 0 || r == libc::EINVAL); | |
82 | } else { | |
83 | debug_assert_eq!(r, 0); | |
84 | } | |
85aaf69f | 85 | } |
1a4d82fc | 86 | } |