@@ -23,61 +23,76 @@ 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( not( test) ) ]
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( not( test) ) ]
32+ #[ export_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key9DTORSE" ]
33+ static DTORS : AtomicPtr < Node > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
34+
35+ #[ cfg( test) ]
36+ extern "Rust" {
37+ #[ link_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key13TLS_KEY_INDEXE" ]
38+ static TLS_KEY_INDEX : AtomicUsize ;
39+
40+ #[ link_name = "_ZN16__rust_internals3std3sys4xous16thread_local_key9DTORSE" ]
41+ static DTORS : AtomicPtr < Node > ;
42+ }
43+
44+ fn tls_ptr_addr ( ) -> * mut * mut u8 {
3045 let mut tp: usize ;
3146 unsafe {
3247 asm ! (
3348 "mv {}, tp" ,
3449 out( reg) tp,
3550 ) ;
3651 }
37- core:: ptr:: from_exposed_addr_mut :: < usize > ( tp)
52+ core:: ptr:: from_exposed_addr_mut :: < * mut u8 > ( tp)
3853}
3954
4055/// Create an area of memory that's unique per thread. This area will
4156/// contain all thread local pointers.
42- fn tls_ptr ( ) -> * mut usize {
43- let mut tp = tls_ptr_addr ( ) ;
57+ fn tls_table ( ) -> & ' static mut [ * mut u8 ] {
58+ let tp = tls_ptr_addr ( ) ;
4459
60+ if !tp. is_null ( ) {
61+ return unsafe {
62+ core:: slice:: from_raw_parts_mut ( tp, TLS_MEMORY_SIZE / core:: mem:: size_of :: < * mut u8 > ( ) )
63+ } ;
64+ }
4565 // If the TP register is `0`, then this thread hasn't initialized
4666 // 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- }
67+ let tp = unsafe {
68+ map_memory (
69+ None ,
70+ None ,
71+ TLS_MEMORY_SIZE / core:: mem:: size_of :: < * mut u8 > ( ) ,
72+ MemoryFlags :: R | MemoryFlags :: W ,
73+ )
5674 . expect ( "Unable to allocate memory for thread local storage" )
57- . as_mut_ptr ( ) ;
75+ } ;
5876
59- unsafe {
60- // Key #0 is currently unused.
61- ( tp ) . write_volatile ( 0 ) ;
77+ for val in tp . iter ( ) {
78+ assert ! ( * val as usize == 0 ) ;
79+ }
6280
63- // Set the thread's `$tp` register
64- asm ! (
65- "mv tp, {}" ,
66- in ( reg ) tp as usize ,
67- ) ;
68- }
81+ unsafe {
82+ // Set the thread's `$tp` register
83+ asm ! (
84+ "mv tp, {}" ,
85+ in ( reg ) tp . as_mut_ptr ( ) as usize ,
86+ ) ;
6987 }
7088 tp
7189}
7290
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-
7891#[ inline]
7992pub unsafe fn create ( dtor : Option < Dtor > ) -> Key {
80- let key = tls_alloc ( ) ;
93+ // Allocate a new TLS key. These keys are shared among all threads.
94+ #[ allow( unused_unsafe) ]
95+ let key = unsafe { TLS_KEY_INDEX . fetch_add ( 1 , SeqCst ) } ;
8196 if let Some ( f) = dtor {
8297 unsafe { register_dtor ( key, f) } ;
8398 }
@@ -87,18 +102,20 @@ pub unsafe fn create(dtor: Option<Dtor>) -> Key {
87102#[ inline]
88103pub unsafe fn set ( key : Key , value : * mut u8 ) {
89104 assert ! ( ( key < 1022 ) && ( key >= 1 ) ) ;
90- unsafe { tls_ptr ( ) . add ( key) . write_volatile ( value as usize ) } ;
105+ let table = tls_table ( ) ;
106+ table[ key] = value;
91107}
92108
93109#[ inline]
94110pub unsafe fn get ( key : Key ) -> * mut u8 {
95111 assert ! ( ( key < 1022 ) && ( key >= 1 ) ) ;
96- core :: ptr :: from_exposed_addr_mut :: < u8 > ( unsafe { tls_ptr ( ) . add ( key) . read_volatile ( ) } )
112+ tls_table ( ) [ key]
97113}
98114
99115#[ inline]
100116pub unsafe fn destroy ( _key : Key ) {
101- panic ! ( "can't destroy keys on Xous" ) ;
117+ // Just leak the key. Probably not great on long-running systems that create
118+ // lots of TLS variables, but in practice that's not an issue.
102119}
103120
104121// -------------------------------------------------------------------------
@@ -127,8 +144,6 @@ pub unsafe fn destroy(_key: Key) {
127144// key but also a slot for the destructor queue on windows. An optimization for
128145// another day!
129146
130- static DTORS : AtomicPtr < Node > = AtomicPtr :: new ( ptr:: null_mut ( ) ) ;
131-
132147struct Node {
133148 dtor : Dtor ,
134149 key : Key ,
@@ -138,10 +153,12 @@ struct Node {
138153unsafe fn register_dtor ( key : Key , dtor : Dtor ) {
139154 let mut node = ManuallyDrop :: new ( Box :: new ( Node { key, dtor, next : ptr:: null_mut ( ) } ) ) ;
140155
141- let mut head = DTORS . load ( SeqCst ) ;
156+ #[ allow( unused_unsafe) ]
157+ let mut head = unsafe { DTORS . load ( SeqCst ) } ;
142158 loop {
143159 node. next = head;
144- match DTORS . compare_exchange ( head, & mut * * node, SeqCst , SeqCst ) {
160+ #[ allow( unused_unsafe) ]
161+ match unsafe { DTORS . compare_exchange ( head, & mut * * node, SeqCst , SeqCst ) } {
145162 Ok ( _) => return , // nothing to drop, we successfully added the node to the list
146163 Err ( cur) => head = cur,
147164 }
@@ -155,6 +172,7 @@ pub unsafe fn destroy_tls() {
155172 if tp. is_null ( ) {
156173 return ;
157174 }
175+
158176 unsafe { run_dtors ( ) } ;
159177
160178 // Finally, free the TLS array
@@ -169,12 +187,19 @@ pub unsafe fn destroy_tls() {
169187
170188unsafe fn run_dtors ( ) {
171189 let mut any_run = true ;
190+
191+ // Run the destructor "some" number of times. This is 5x on Windows,
192+ // so we copy it here. This allows TLS variables to create new
193+ // TLS variables upon destruction that will also get destroyed.
194+ // Keep going until we run out of tries or until we have nothing
195+ // left to destroy.
172196 for _ in 0 ..5 {
173197 if !any_run {
174198 break ;
175199 }
176200 any_run = false ;
177- let mut cur = DTORS . load ( SeqCst ) ;
201+ #[ allow( unused_unsafe) ]
202+ let mut cur = unsafe { DTORS . load ( SeqCst ) } ;
178203 while !cur. is_null ( ) {
179204 let ptr = unsafe { get ( ( * cur) . key ) } ;
180205
0 commit comments