Skip to content

Commit d375525

Browse files
committed
Add parking_lot::remutex
1 parent 1427463 commit d375525

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed
Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11

22
pub mod condvar;
3+
pub mod elision;
34
pub mod raw_rwlock;
45
pub mod raw_mutex;
5-
pub mod elision;
6+
pub mod remutex;
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
// Copyright 2016 Amanieu d'Antras
2+
//
3+
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4+
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5+
// http://opensource.org/licenses/MIT>, at your option. This file may not be
6+
// copied, modified, or distributed except according to those terms.
7+
8+
use super::raw_mutex::RawMutex;
9+
use cell::Cell;
10+
use mem;
11+
use sync::atomic::{AtomicUsize, Ordering};
12+
13+
/// Implementation of the `GetThreadId` trait for `lock_api::ReentrantMutex`.
14+
pub struct RawThreadId;
15+
16+
impl RawThreadId {
17+
pub const INIT: RawThreadId = RawThreadId;
18+
19+
pub fn nonzero_thread_id(&self) -> usize {
20+
// The address of a thread-local variable is guaranteed to be unique to the
21+
// current thread, and is also guaranteed to be non-zero.
22+
thread_local!(static KEY: u8 = unsafe { mem::uninitialized() });
23+
KEY.with(|x| x as *const _ as usize)
24+
}
25+
}
26+
27+
struct RawReentrantMutex {
28+
owner: AtomicUsize,
29+
lock_count: Cell<usize>,
30+
mutex: RawMutex,
31+
get_thread_id: RawThreadId,
32+
}
33+
34+
impl RawReentrantMutex {
35+
#[inline]
36+
fn lock_internal<F: FnOnce() -> bool>(&self, try_lock: F) -> bool {
37+
let id = self.get_thread_id.nonzero_thread_id();
38+
if self.owner.load(Ordering::Relaxed) == id {
39+
self.lock_count.set(
40+
self.lock_count
41+
.get()
42+
.checked_add(1)
43+
.expect("ReentrantMutex lock count overflow"),
44+
);
45+
} else {
46+
if !try_lock() {
47+
return false;
48+
}
49+
self.owner.store(id, Ordering::Relaxed);
50+
self.lock_count.set(1);
51+
}
52+
true
53+
}
54+
55+
#[inline]
56+
fn lock(&self) {
57+
self.lock_internal(|| {
58+
self.mutex.lock();
59+
true
60+
});
61+
}
62+
63+
#[inline]
64+
fn try_lock(&self) -> bool {
65+
self.lock_internal(|| self.mutex.try_lock())
66+
}
67+
68+
#[inline]
69+
fn unlock(&self) {
70+
let lock_count = self.lock_count.get() - 1;
71+
if lock_count == 0 {
72+
self.owner.store(0, Ordering::Relaxed);
73+
self.mutex.unlock();
74+
} else {
75+
self.lock_count.set(lock_count);
76+
}
77+
}
78+
}

0 commit comments

Comments
 (0)