@@ -23,61 +23,66 @@ pub type Dtor = unsafe extern "C" fn(*mut u8);
2323
2424const TLS_MEMORY_SIZE : usize = 4096 ;
2525
26- /// TLS keys start at `1` to mimic POSIX.
26+ /// TLS keys start at `1`. Index `0` is unused
27+ #[ cfg_attr( test, linkage = "available_externally" ) ]
28+ #[ export_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key13TLS_KEY_INDEXE" ]
2729static TLS_KEY_INDEX : AtomicUsize = AtomicUsize :: new ( 1 ) ;
2830
29- fn tls_ptr_addr ( ) -> * mut usize {
31+ #[ cfg_attr( test, linkage = "available_externally" ) ]
32+ #[ export_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key9DTORSE" ]
33+ static DTORS : AtomicPtr < Node > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
34+
35+ fn tls_ptr_addr ( ) -> * mut * mut u8 {
3036 let mut tp: usize ;
3137 unsafe {
3238 asm ! (
3339 "mv {}, tp" ,
3440 out( reg) tp,
3541 ) ;
3642 }
37- core:: ptr:: from_exposed_addr_mut :: < usize > ( tp)
43+ core:: ptr:: from_exposed_addr_mut :: < * mut u8 > ( tp)
3844}
3945
4046/// Create an area of memory that's unique per thread. This area will
4147/// contain all thread local pointers.
42- fn tls_ptr ( ) -> * mut usize {
43- let mut tp = tls_ptr_addr ( ) ;
48+ fn tls_table ( ) -> & ' static mut [ * mut u8 ] {
49+ let tp = tls_ptr_addr ( ) ;
4450
51+ if !tp. is_null ( ) {
52+ return unsafe {
53+ core:: slice:: from_raw_parts_mut ( tp, TLS_MEMORY_SIZE / core:: mem:: size_of :: < * mut u8 > ( ) )
54+ } ;
55+ }
4556 // If the TP register is `0`, then this thread hasn't initialized
4657 // its TLS yet. Allocate a new page to store this memory.
47- if tp. is_null ( ) {
48- tp = unsafe {
49- map_memory (
50- None ,
51- None ,
52- TLS_MEMORY_SIZE / core:: mem:: size_of :: < usize > ( ) ,
53- MemoryFlags :: R | MemoryFlags :: W ,
54- )
55- }
58+ let tp = unsafe {
59+ map_memory (
60+ None ,
61+ None ,
62+ TLS_MEMORY_SIZE / core:: mem:: size_of :: < * mut u8 > ( ) ,
63+ MemoryFlags :: R | MemoryFlags :: W ,
64+ )
5665 . expect ( "Unable to allocate memory for thread local storage" )
57- . as_mut_ptr ( ) ;
66+ } ;
5867
59- unsafe {
60- // Key #0 is currently unused.
61- ( tp ) . write_volatile ( 0 ) ;
68+ for val in tp . iter ( ) {
69+ assert ! ( * val as usize == 0 ) ;
70+ }
6271
63- // Set the thread's `$tp` register
64- asm ! (
65- "mv tp, {}" ,
66- in ( reg ) tp as usize ,
67- ) ;
68- }
72+ unsafe {
73+ // Set the thread's `$tp` register
74+ asm ! (
75+ "mv tp, {}" ,
76+ in ( reg ) tp . as_mut_ptr ( ) as usize ,
77+ ) ;
6978 }
7079 tp
7180}
7281
73- /// Allocate a new TLS key. These keys are shared among all threads.
74- fn tls_alloc ( ) -> usize {
75- TLS_KEY_INDEX . fetch_add ( 1 , SeqCst )
76- }
77-
7882#[ inline]
7983pub unsafe fn create ( dtor : Option < Dtor > ) -> Key {
80- let key = tls_alloc ( ) ;
84+ // Allocate a new TLS key. These keys are shared among all threads.
85+ let key = TLS_KEY_INDEX . fetch_add ( 1 , SeqCst ) ;
8186 if let Some ( f) = dtor {
8287 unsafe { register_dtor ( key, f) } ;
8388 }
@@ -87,18 +92,20 @@ pub unsafe fn create(dtor: Option<Dtor>) -> Key {
8792#[ inline]
8893pub unsafe fn set ( key : Key , value : * mut u8 ) {
8994 assert ! ( ( key < 1022 ) && ( key >= 1 ) ) ;
90- unsafe { tls_ptr ( ) . add ( key) . write_volatile ( value as usize ) } ;
95+ let table = tls_table ( ) ;
96+ table[ key] = value;
9197}
9298
9399#[ inline]
94100pub unsafe fn get ( key : Key ) -> * mut u8 {
95101 assert ! ( ( key < 1022 ) && ( key >= 1 ) ) ;
96- core :: ptr :: from_exposed_addr_mut :: < u8 > ( unsafe { tls_ptr ( ) . add ( key) . read_volatile ( ) } )
102+ tls_table ( ) [ key]
97103}
98104
99105#[ inline]
100106pub unsafe fn destroy ( _key : Key ) {
101- panic ! ( "can't destroy keys on Xous" ) ;
107+ // Just leak the key. Probably not great on long-running systems that create
108+ // lots of TLS variables, but in practice that's not an issue.
102109}
103110
104111// -------------------------------------------------------------------------
@@ -127,8 +134,6 @@ pub unsafe fn destroy(_key: Key) {
127134// key but also a slot for the destructor queue on windows. An optimization for
128135// another day!
129136
130- static DTORS : AtomicPtr < Node > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
131-
132137struct Node {
133138 dtor : Dtor ,
134139 key : Key ,
@@ -155,6 +160,7 @@ pub unsafe fn destroy_tls() {
155160 if tp. is_null ( ) {
156161 return ;
157162 }
163+
158164 unsafe { run_dtors ( ) } ;
159165
160166 // Finally, free the TLS array
@@ -169,6 +175,12 @@ pub unsafe fn destroy_tls() {
169175
170176unsafe fn run_dtors ( ) {
171177 let mut any_run = true ;
178+
179+ // Run the destructor "some" number of times. This is 5x on Windows,
180+ // so we copy it here. This allows TLS variables to create new
181+ // TLS variables upon destruction that will also get destroyed.
182+ // Keep going until we run out of tries or until we have nothing
183+ // left to destroy.
172184 for _ in 0 ..5 {
173185 if !any_run {
174186 break ;
0 commit comments