]> git.lizzy.rs Git - rust.git/blob - src/libstd/sys/sgx/abi/tls.rs
SGX target: add thread local storage
[rust.git] / src / libstd / sys / sgx / abi / tls.rs
1 // Copyright 2018 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 use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
12 use ptr;
13 use mem;
14 use cell::Cell;
15 use num::NonZeroUsize;
16 use self::sync_bitset::*;
17
18 #[cfg(target_pointer_width="64")]
19 const USIZE_BITS: usize = 64;
20 const TLS_KEYS: usize = 128; // Same as POSIX minimum
21 const TLS_KEYS_BITSET_SIZE: usize = (TLS_KEYS + (USIZE_BITS - 1)) / USIZE_BITS;
22
23 static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT;
24 macro_rules! dup {
25     ((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* ));
26     (() $($val:tt)*) => ([$($val),*])
27 }
28 static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) ATOMIC_USIZE_INIT);
29
30 extern "C" {
31     fn get_tls_ptr() -> *const u8;
32     fn set_tls_ptr(tls: *const u8);
33 }
34
35 #[derive(Copy, Clone)]
36 #[repr(C)]
37 pub struct Key(NonZeroUsize);
38
39 impl Key {
40     fn to_index(self) -> usize {
41         self.0.get() - 1
42     }
43
44     fn from_index(index: usize) -> Self {
45         Key(NonZeroUsize::new(index + 1).unwrap())
46     }
47
48     pub fn as_usize(self) -> usize {
49         self.0.get()
50     }
51
52     pub fn from_usize(index: usize) -> Self {
53         Key(NonZeroUsize::new(index).unwrap())
54     }
55 }
56
57 #[repr(C)]
58 pub struct Tls {
59     data: [Cell<*mut u8>; TLS_KEYS]
60 }
61
62 pub struct ActiveTls<'a> {
63     tls: &'a Tls
64 }
65
66 impl<'a> Drop for ActiveTls<'a> {
67     fn drop(&mut self) {
68         let value_with_destructor = |key: usize| {
69             let ptr = TLS_DESTRUCTOR[key].load(Ordering::Relaxed);
70             unsafe { mem::transmute::<_,Option<unsafe extern fn(*mut u8)>>(ptr) }
71                 .map(|dtor| (&self.tls.data[key], dtor))
72         };
73
74         let mut any_non_null_dtor = true;
75         while any_non_null_dtor {
76             any_non_null_dtor = false;
77             for (value, dtor) in TLS_KEY_IN_USE.iter().filter_map(&value_with_destructor) {
78                 let value = value.replace(ptr::null_mut());
79                 if value != ptr::null_mut() {
80                     any_non_null_dtor = true;
81                     unsafe { dtor(value) }
82                 }
83             }
84         }
85     }
86 }
87
88 impl Tls {
89     pub fn new() -> Tls {
90         Tls { data: dup!((* * * * * * *) (Cell::new(ptr::null_mut()))) }
91     }
92
93     pub unsafe fn activate(&self) -> ActiveTls {
94         set_tls_ptr(self as *const Tls as _);
95         ActiveTls { tls: self }
96     }
97
98     #[allow(unused)]
99     pub unsafe fn activate_persistent(self: Box<Self>) {
100         set_tls_ptr((&*self) as *const Tls as _);
101         mem::forget(self);
102     }
103
104     unsafe fn current<'a>() -> &'a Tls {
105         &*(get_tls_ptr() as *const Tls)
106     }
107
108     pub fn create(dtor: Option<unsafe extern fn(*mut u8)>) -> Key {
109         let index = TLS_KEY_IN_USE.set().expect("TLS limit exceeded");
110         TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed);
111         Key::from_index(index)
112     }
113
114     pub fn set(key: Key, value: *mut u8) {
115         let index = key.to_index();
116         assert!(TLS_KEY_IN_USE.get(index));
117         unsafe { Self::current() }.data[index].set(value);
118     }
119
120     pub fn get(key: Key) -> *mut u8 {
121         let index = key.to_index();
122         assert!(TLS_KEY_IN_USE.get(index));
123         unsafe { Self::current() }.data[index].get()
124     }
125
126     pub fn destroy(key: Key) {
127         TLS_KEY_IN_USE.clear(key.to_index());
128     }
129 }
130
131 mod sync_bitset {
132     use sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering};
133     use iter::{Enumerate, Peekable};
134     use slice::Iter;
135     use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS};
136
137     /// A bitset that can be used synchronously.
138     pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]);
139
140     pub(super) const SYNC_BITSET_INIT: SyncBitset =
141         SyncBitset([ATOMIC_USIZE_INIT, ATOMIC_USIZE_INIT]);
142
143     impl SyncBitset {
144         pub fn get(&self, index: usize) -> bool {
145             let (hi, lo) = Self::split(index);
146             (self.0[hi].load(Ordering::Relaxed) & lo) != 0
147         }
148
149         /// Not atomic.
150         pub fn iter(&self) -> SyncBitsetIter {
151             SyncBitsetIter {
152                 iter: self.0.iter().enumerate().peekable(),
153                 elem_idx: 0,
154             }
155         }
156
157         pub fn clear(&self, index: usize) {
158             let (hi, lo) = Self::split(index);
159             self.0[hi].fetch_and(!lo, Ordering::Relaxed);
160         }
161
162         /// Set any unset bit. Not atomic. Returns `None` if all bits were
163         /// observed to be set.
164         pub fn set(&self) -> Option<usize> {
165             'elems: for (idx, elem) in self.0.iter().enumerate() {
166                 let mut current = elem.load(Ordering::Relaxed);
167                 loop {
168                     if 0 == !current {
169                         continue 'elems;
170                     }
171                     let trailing_ones = (!current).trailing_zeros() as usize;
172                     match elem.compare_exchange(
173                         current,
174                         current | (1 << trailing_ones),
175                         Ordering::AcqRel,
176                         Ordering::Relaxed
177                     ) {
178                         Ok(_) => return Some(idx * USIZE_BITS + trailing_ones),
179                         Err(previous) => current = previous,
180                     }
181                 }
182             }
183             None
184         }
185
186         fn split(index: usize) -> (usize, usize) {
187             (index / USIZE_BITS, 1 << (index % USIZE_BITS))
188         }
189     }
190
191     pub(super) struct SyncBitsetIter<'a> {
192         iter: Peekable<Enumerate<Iter<'a, AtomicUsize>>>,
193         elem_idx: usize,
194     }
195
196     impl<'a> Iterator for SyncBitsetIter<'a> {
197         type Item = usize;
198
199         fn next(&mut self) -> Option<usize> {
200             self.iter.peek().cloned().and_then(|(idx, elem)| {
201                 let elem = elem.load(Ordering::Relaxed);
202                 let low_mask = (1 << self.elem_idx) - 1;
203                 let next = elem & !low_mask;
204                 let next_idx = next.trailing_zeros() as usize;
205                 self.elem_idx = next_idx + 1;
206                 if self.elem_idx >= 64 {
207                     self.elem_idx = 0;
208                     self.iter.next();
209                 }
210                 match next_idx {
211                     64 => self.next(),
212                     _ => Some(idx * USIZE_BITS + next_idx),
213                 }
214             })
215         }
216     }
217
218     #[cfg(test)]
219     mod tests {
220         use super::*;
221
222         fn test_data(bitset: [usize; 2], bit_indices: &[usize]) {
223             let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]);
224             assert_eq!(set.iter().collect::<Vec<_>>(), bit_indices);
225             for &i in bit_indices {
226                 assert!(set.get(i));
227             }
228         }
229
230         #[test]
231         fn iter() {
232             test_data([0b0110_1001, 0], &[0, 3, 5, 6]);
233             test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]);
234             test_data([0, 0], &[]);
235         }
236
237         #[test]
238         fn set_get_clear() {
239             let set = SYNC_BITSET_INIT;
240             let key = set.set().unwrap();
241             assert!(set.get(key));
242             set.clear(key);
243             assert!(!set.get(key));
244         }
245     }
246 }