1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
// Take a look at the license at the top of the repository in the LICENSE file.
use std::{
mem::ManuallyDrop,
sync::atomic::{AtomicUsize, Ordering},
};
fn next_thread_id() -> usize {
static COUNTER: AtomicUsize = AtomicUsize::new(0);
COUNTER.fetch_add(1, Ordering::SeqCst)
}
// rustdoc-stripper-ignore-next
/// Returns a unique ID for the current thread.
///
/// Actual thread IDs can be reused by the OS once the old thread finished.
/// This works around ambiguity created by ID reuse by using a separate TLS counter for threads.
pub fn thread_id() -> usize {
thread_local!(static THREAD_ID: usize = next_thread_id());
THREAD_ID.with(|&x| x)
}
// rustdoc-stripper-ignore-next
/// Thread guard that only gives access to the contained value on the thread it was created on.
pub struct ThreadGuard<T> {
thread_id: usize,
// This is a `ManuallyDrop` so that the automatic drop glue does not drop `T`
// if this `ThreadGuard` is dropped on the wrong thread.
value: ManuallyDrop<T>,
}
impl<T> ThreadGuard<T> {
// rustdoc-stripper-ignore-next
/// Create a new thread guard around `value`.
///
/// The thread guard ensures that access to the value is only allowed from the thread it was
/// created on, and otherwise panics.
///
/// The thread guard implements the `Send` trait even if the contained value does not.
#[inline]
pub fn new(value: T) -> Self {
Self {
thread_id: thread_id(),
value: ManuallyDrop::new(value),
}
}
// rustdoc-stripper-ignore-next
/// Return a reference to the contained value from the thread guard.
///
/// # Panics
///
/// This function panics if called from a different thread than where the thread guard was
/// created.
#[inline]
pub fn get_ref(&self) -> &T {
assert!(
self.thread_id == thread_id(),
"Value accessed from different thread than where it was created"
);
&self.value
}
// rustdoc-stripper-ignore-next
/// Return a mutable reference to the contained value from the thread guard.
///
/// # Panics
///
/// This function panics if called from a different thread than where the thread guard was
/// created.
#[inline]
pub fn get_mut(&mut self) -> &mut T {
assert!(
self.thread_id == thread_id(),
"Value accessed from different thread than where it was created"
);
&mut self.value
}
// rustdoc-stripper-ignore-next
/// Return the contained value from the thread guard.
///
/// # Panics
///
/// This function panics if called from a different thread than where the thread guard was
/// created.
#[inline]
pub fn into_inner(self) -> T {
// We wrap `self` in `ManuallyDrop` to defuse `ThreadGuard`'s `Drop` impl.
let mut this = ManuallyDrop::new(self);
assert!(
this.thread_id == thread_id(),
"Value accessed from different thread than where it was created"
);
// SAFETY: We are on the right thread, and this.value will not be touched after this
unsafe { ManuallyDrop::take(&mut this.value) }
}
// rustdoc-stripper-ignore-next
/// Returns `true` if the current thread owns the value, i.e. it can be accessed safely.
#[inline]
pub fn is_owner(&self) -> bool {
self.thread_id == thread_id()
}
}
impl<T> Drop for ThreadGuard<T> {
#[inline]
fn drop(&mut self) {
assert!(
self.thread_id == thread_id(),
"Value dropped on a different thread than where it was created"
);
// SAFETY: We are on the right thread, and self.value will not be touched after this
unsafe { ManuallyDrop::drop(&mut self.value) }
}
}
unsafe impl<T> Send for ThreadGuard<T> {}
unsafe impl<T> Sync for ThreadGuard<T> {}
impl<T> std::ops::Deref for ThreadGuard<T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.get_ref()
}
}
impl<T> std::ops::DerefMut for ThreadGuard<T> {
fn deref_mut(&mut self) -> &mut Self::Target {
self.get_mut()
}
}