1 mod sync_bitset; 2 3 use self::sync_bitset::*; 4 use crate::cell::Cell; 5 use crate::mem; 6 use crate::num::NonZeroUsize; 7 use crate::ptr; 8 use crate::sync::atomic::{AtomicUsize, Ordering}; 9 10 #[cfg(target_pointer_width = "64")] 11 const USIZE_BITS: usize = 64; 12 const TLS_KEYS: usize = 128; // Same as POSIX minimum 13 const TLS_KEYS_BITSET_SIZE: usize = (TLS_KEYS + (USIZE_BITS - 1)) / USIZE_BITS; 14 15 #[cfg_attr(test, linkage = "available_externally")] 16 #[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_KEY_IN_USEE"] 17 static TLS_KEY_IN_USE: SyncBitset = SYNC_BITSET_INIT; 18 macro_rules! dup { 19 ((* $($exp:tt)*) $($val:tt)*) => (dup!( ($($exp)*) $($val)* $($val)* )); 20 (() $($val:tt)*) => ([$($val),*]) 21 } 22 #[cfg_attr(test, linkage = "available_externally")] 23 #[export_name = "_ZN16__rust_internals3std3sys3sgx3abi3tls14TLS_DESTRUCTORE"] 24 static TLS_DESTRUCTOR: [AtomicUsize; TLS_KEYS] = dup!((* * * * * * *) (AtomicUsize::new(0))); 25 26 extern "C" { get_tls_ptr() -> *const u827 fn get_tls_ptr() -> *const u8; set_tls_ptr(tls: *const u8)28 fn set_tls_ptr(tls: *const u8); 29 } 30 31 #[derive(Copy, Clone)] 32 #[repr(C)] 33 pub struct Key(NonZeroUsize); 34 35 impl Key { to_index(self) -> usize36 fn to_index(self) -> usize { 37 self.0.get() - 1 38 } 39 from_index(index: usize) -> Self40 fn from_index(index: usize) -> Self { 41 Key(NonZeroUsize::new(index + 1).unwrap()) 42 } 43 as_usize(self) -> usize44 pub fn as_usize(self) -> usize { 45 self.0.get() 46 } 47 from_usize(index: usize) -> Self48 pub fn from_usize(index: usize) -> Self { 49 Key(NonZeroUsize::new(index).unwrap()) 50 } 51 } 52 53 #[repr(C)] 54 pub struct Tls { 55 data: [Cell<*mut u8>; TLS_KEYS], 56 } 57 58 pub struct ActiveTls<'a> { 59 tls: &'a Tls, 60 } 61 62 impl<'a> Drop for ActiveTls<'a> { drop(&mut self)63 fn drop(&mut self) { 64 let value_with_destructor = |key: usize| { 65 let ptr = TLS_DESTRUCTOR[key].load(Ordering::Relaxed); 66 unsafe { mem::transmute::<_, Option<unsafe extern "C" fn(*mut u8)>>(ptr) } 67 .map(|dtor| (&self.tls.data[key], dtor)) 68 }; 69 70 let mut any_non_null_dtor = true; 71 while any_non_null_dtor { 72 any_non_null_dtor = false; 73 for (value, dtor) in TLS_KEY_IN_USE.iter().filter_map(&value_with_destructor) { 74 let value = value.replace(ptr::null_mut()); 75 if !value.is_null() { 76 any_non_null_dtor = true; 77 unsafe { dtor(value) } 78 } 79 } 80 } 81 } 82 } 83 84 impl Tls { new() -> Tls85 pub fn new() -> Tls { 86 Tls { data: dup!((* * * * * * *) (Cell::new(ptr::null_mut()))) } 87 } 88 activate(&self) -> ActiveTls<'_>89 pub unsafe fn activate(&self) -> ActiveTls<'_> { 90 // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. 91 unsafe { set_tls_ptr(self as *const Tls as _) }; 92 ActiveTls { tls: self } 93 } 94 95 #[allow(unused)] activate_persistent(self: Box<Self>)96 pub unsafe fn activate_persistent(self: Box<Self>) { 97 // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. 98 unsafe { set_tls_ptr((&*self) as *const Tls as _) }; 99 mem::forget(self); 100 } 101 current<'a>() -> &'a Tls102 unsafe fn current<'a>() -> &'a Tls { 103 // FIXME: Needs safety information. See entry.S for `set_tls_ptr` definition. 104 unsafe { &*(get_tls_ptr() as *const Tls) } 105 } 106 create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key107 pub fn create(dtor: Option<unsafe extern "C" fn(*mut u8)>) -> Key { 108 let index = if let Some(index) = TLS_KEY_IN_USE.set() { 109 index 110 } else { 111 rtabort!("TLS limit exceeded") 112 }; 113 TLS_DESTRUCTOR[index].store(dtor.map_or(0, |f| f as usize), Ordering::Relaxed); 114 unsafe { Self::current() }.data[index].set(ptr::null_mut()); 115 Key::from_index(index) 116 } 117 set(key: Key, value: *mut u8)118 pub fn set(key: Key, value: *mut u8) { 119 let index = key.to_index(); 120 rtassert!(TLS_KEY_IN_USE.get(index)); 121 unsafe { Self::current() }.data[index].set(value); 122 } 123 get(key: Key) -> *mut u8124 pub fn get(key: Key) -> *mut u8 { 125 let index = key.to_index(); 126 rtassert!(TLS_KEY_IN_USE.get(index)); 127 unsafe { Self::current() }.data[index].get() 128 } 129 destroy(key: Key)130 pub fn destroy(key: Key) { 131 TLS_KEY_IN_USE.clear(key.to_index()); 132 } 133 } 134