]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys_common/thread_local.rs
Auto merge of #69482 - lqd:poloniusup, r=nikomatsakis
[rust.git] / src / libstd / sys_common / thread_local.rs
1 //! OS-based thread local storage
2 //!
3 //! This module provides an implementation of OS-based thread local storage,
4 //! using the native OS-provided facilities (think `TlsAlloc` or
5 //! `pthread_setspecific`). The interface of this differs from the other types
6 //! of thread-local-storage provided in this crate in that OS-based TLS can only
7 //! get/set pointers,
8 //!
9 //! This module also provides two flavors of TLS. One is intended for static
10 //! initialization, and does not contain a `Drop` implementation to deallocate
11 //! the OS-TLS key. The other is a type which does implement `Drop` and hence
12 //! has a safe interface.
13 //!
14 //! # Usage
15 //!
16 //! This module should likely not be used directly unless other primitives are
17 //! being built on. types such as `thread_local::spawn::Key` are likely much
18 //! more useful in practice than this OS-based version which likely requires
19 //! unsafe code to interoperate with.
20 //!
21 //! # Examples
22 //!
23 //! Using a dynamically allocated TLS key. Note that this key can be shared
24 //! among many threads via an `Arc`.
25 //!
26 //! ```ignore (cannot-doctest-private-modules)
27 //! let key = Key::new(None);
28 //! assert!(key.get().is_null());
29 //! key.set(1 as *mut u8);
30 //! assert!(!key.get().is_null());
31 //!
32 //! drop(key); // deallocate this TLS slot.
33 //! ```
34 //!
35 //! Sometimes a statically allocated key is either required or easier to work
36 //! with, however.
37 //!
38 //! ```ignore (cannot-doctest-private-modules)
39 //! static KEY: StaticKey = INIT;
40 //!
41 //! unsafe {
42 //!     assert!(KEY.get().is_null());
43 //!     KEY.set(1 as *mut u8);
44 //! }
45 //! ```
46
47 #![allow(non_camel_case_types)]
48 #![unstable(feature = "thread_local_internals", issue = "none")]
49 #![allow(dead_code)] // sys isn't exported yet
50
51 use crate::ptr;
52 use crate::sync::atomic::{self, AtomicUsize, Ordering};
53 use crate::sys::thread_local as imp;
54 use crate::sys_common::mutex::Mutex;
55
56 /// A type for TLS keys that are statically allocated.
57 ///
58 /// This type is entirely `unsafe` to use as it does not protect against
59 /// use-after-deallocation or use-during-deallocation.
60 ///
61 /// The actual OS-TLS key is lazily allocated when this is used for the first
62 /// time. The key is also deallocated when the Rust runtime exits or `destroy`
63 /// is called, whichever comes first.
64 ///
65 /// # Examples
66 ///
67 /// ```ignore (cannot-doctest-private-modules)
68 /// use tls::os::{StaticKey, INIT};
69 ///
70 /// static KEY: StaticKey = INIT;
71 ///
72 /// unsafe {
73 ///     assert!(KEY.get().is_null());
74 ///     KEY.set(1 as *mut u8);
75 /// }
76 /// ```
77 pub struct StaticKey {
78     /// Inner static TLS key (internals).
79     key: AtomicUsize,
80     /// Destructor for the TLS value.
81     ///
82     /// See `Key::new` for information about when the destructor runs and how
83     /// it runs.
84     dtor: Option<unsafe extern "C" fn(*mut u8)>,
85 }
86
87 /// A type for a safely managed OS-based TLS slot.
88 ///
89 /// This type allocates an OS TLS key when it is initialized and will deallocate
90 /// the key when it falls out of scope. When compared with `StaticKey`, this
91 /// type is entirely safe to use.
92 ///
93 /// Implementations will likely, however, contain unsafe code as this type only
94 /// operates on `*mut u8`, a raw pointer.
95 ///
96 /// # Examples
97 ///
98 /// ```ignore (cannot-doctest-private-modules)
99 /// use tls::os::Key;
100 ///
101 /// let key = Key::new(None);
102 /// assert!(key.get().is_null());
103 /// key.set(1 as *mut u8);
104 /// assert!(!key.get().is_null());
105 ///
106 /// drop(key); // deallocate this TLS slot.
107 /// ```
108 pub struct Key {
109     key: imp::Key,
110 }
111
112 /// Constant initialization value for static TLS keys.
113 ///
114 /// This value specifies no destructor by default.
115 pub const INIT: StaticKey = StaticKey::new(None);
116
117 impl StaticKey {
118     pub const fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> StaticKey {
119         StaticKey { key: atomic::AtomicUsize::new(0), dtor }
120     }
121
122     /// Gets the value associated with this TLS key
123     ///
124     /// This will lazily allocate a TLS key from the OS if one has not already
125     /// been allocated.
126     #[inline]
127     pub unsafe fn get(&self) -> *mut u8 {
128         imp::get(self.key())
129     }
130
131     /// Sets this TLS key to a new value.
132     ///
133     /// This will lazily allocate a TLS key from the OS if one has not already
134     /// been allocated.
135     #[inline]
136     pub unsafe fn set(&self, val: *mut u8) {
137         imp::set(self.key(), val)
138     }
139
140     #[inline]
141     unsafe fn key(&self) -> imp::Key {
142         match self.key.load(Ordering::Relaxed) {
143             0 => self.lazy_init() as imp::Key,
144             n => n as imp::Key,
145         }
146     }
147
148     unsafe fn lazy_init(&self) -> usize {
149         // Currently the Windows implementation of TLS is pretty hairy, and
150         // it greatly simplifies creation if we just synchronize everything.
151         //
152         // Additionally a 0-index of a tls key hasn't been seen on windows, so
153         // we just simplify the whole branch.
154         if imp::requires_synchronized_create() {
155             // We never call `INIT_LOCK.init()`, so it is UB to attempt to
156             // acquire this mutex reentrantly!
157             static INIT_LOCK: Mutex = Mutex::new();
158             let _guard = INIT_LOCK.lock();
159             let mut key = self.key.load(Ordering::SeqCst);
160             if key == 0 {
161                 key = imp::create(self.dtor) as usize;
162                 self.key.store(key, Ordering::SeqCst);
163             }
164             rtassert!(key != 0);
165             return key;
166         }
167
168         // POSIX allows the key created here to be 0, but the compare_and_swap
169         // below relies on using 0 as a sentinel value to check who won the
170         // race to set the shared TLS key. As far as I know, there is no
171         // guaranteed value that cannot be returned as a posix_key_create key,
172         // so there is no value we can initialize the inner key with to
173         // prove that it has not yet been set. As such, we'll continue using a
174         // value of 0, but with some gyrations to make sure we have a non-0
175         // value returned from the creation routine.
176         // FIXME: this is clearly a hack, and should be cleaned up.
177         let key1 = imp::create(self.dtor);
178         let key = if key1 != 0 {
179             key1
180         } else {
181             let key2 = imp::create(self.dtor);
182             imp::destroy(key1);
183             key2
184         };
185         rtassert!(key != 0);
186         match self.key.compare_and_swap(0, key as usize, Ordering::SeqCst) {
187             // The CAS succeeded, so we've created the actual key
188             0 => key as usize,
189             // If someone beat us to the punch, use their key instead
190             n => {
191                 imp::destroy(key);
192                 n
193             }
194         }
195     }
196 }
197
198 impl Key {
199     /// Creates a new managed OS TLS key.
200     ///
201     /// This key will be deallocated when the key falls out of scope.
202     ///
203     /// The argument provided is an optionally-specified destructor for the
204     /// value of this TLS key. When a thread exits and the value for this key
205     /// is non-null the destructor will be invoked. The TLS value will be reset
206     /// to null before the destructor is invoked.
207     ///
208     /// Note that the destructor will not be run when the `Key` goes out of
209     /// scope.
210     #[inline]
211     pub fn new(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key {
212         Key { key: unsafe { imp::create(dtor) } }
213     }
214
215     /// See StaticKey::get
216     #[inline]
217     pub fn get(&self) -> *mut u8 {
218         unsafe { imp::get(self.key) }
219     }
220
221     /// See StaticKey::set
222     #[inline]
223     pub fn set(&self, val: *mut u8) {
224         unsafe { imp::set(self.key, val) }
225     }
226 }
227
228 impl Drop for Key {
229     fn drop(&mut self) {
230         // Right now Windows doesn't support TLS key destruction, but this also
231         // isn't used anywhere other than tests, so just leak the TLS key.
232         // unsafe { imp::destroy(self.key) }
233     }
234 }
235
236 pub unsafe fn register_dtor_fallback(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) {
237     // The fallback implementation uses a vanilla OS-based TLS key to track
238     // the list of destructors that need to be run for this thread. The key
239     // then has its own destructor which runs all the other destructors.
240     //
241     // The destructor for DTORS is a little special in that it has a `while`
242     // loop to continuously drain the list of registered destructors. It
243     // *should* be the case that this loop always terminates because we
244     // provide the guarantee that a TLS key cannot be set after it is
245     // flagged for destruction.
246
247     static DTORS: StaticKey = StaticKey::new(Some(run_dtors));
248     type List = Vec<(*mut u8, unsafe extern "C" fn(*mut u8))>;
249     if DTORS.get().is_null() {
250         let v: Box<List> = box Vec::new();
251         DTORS.set(Box::into_raw(v) as *mut u8);
252     }
253     let list: &mut List = &mut *(DTORS.get() as *mut List);
254     list.push((t, dtor));
255
256     unsafe extern "C" fn run_dtors(mut ptr: *mut u8) {
257         while !ptr.is_null() {
258             let list: Box<List> = Box::from_raw(ptr as *mut List);
259             for (ptr, dtor) in list.into_iter() {
260                 dtor(ptr);
261             }
262             ptr = DTORS.get();
263             DTORS.set(ptr::null_mut());
264         }
265     }
266 }
267
268 #[cfg(test)]
269 mod tests {
270     use super::{Key, StaticKey};
271
272     fn assert_sync<T: Sync>() {}
273     fn assert_send<T: Send>() {}
274
275     #[test]
276     fn smoke() {
277         assert_sync::<Key>();
278         assert_send::<Key>();
279
280         let k1 = Key::new(None);
281         let k2 = Key::new(None);
282         assert!(k1.get().is_null());
283         assert!(k2.get().is_null());
284         k1.set(1 as *mut _);
285         k2.set(2 as *mut _);
286         assert_eq!(k1.get() as usize, 1);
287         assert_eq!(k2.get() as usize, 2);
288     }
289
290     #[test]
291     fn statik() {
292         static K1: StaticKey = StaticKey::new(None);
293         static K2: StaticKey = StaticKey::new(None);
294
295         unsafe {
296             assert!(K1.get().is_null());
297             assert!(K2.get().is_null());
298             K1.set(1 as *mut _);
299             K2.set(2 as *mut _);
300             assert_eq!(K1.get() as usize, 1);
301             assert_eq!(K2.get() as usize, 2);
302         }
303     }
304 }