@@ -14,7 +14,7 @@ use libc::types::os::arch::extra::{DWORD, LPVOID, BOOL};
14
14
15
15
use mem;
16
16
use rt;
17
- use sync :: { ONCE_INIT , Once , Mutex } ;
17
+ use sys_common :: mutex :: { MUTEX_INIT , Mutex } ;
18
18
19
19
pub type Key = DWORD ;
20
20
pub type Dtor = unsafe extern fn ( * mut u8 ) ;
@@ -53,8 +53,12 @@ pub type Dtor = unsafe extern fn(*mut u8);
53
53
// [2]: https://github.com/ChromiumWebApps/chromium/blob/master/base
54
54
// /threading/thread_local_storage_win.cc#L42
55
55
56
- static INIT_DTORS : Once = ONCE_INIT ;
57
- static mut DTORS : * mut Mutex < Vec < ( Key , Dtor ) > > = 0 as * mut _ ;
56
+ // NB these are specifically not types from `std::sync` as they currently rely
57
+ // on poisoning and this module needs to operate at a lower level than requiring
58
+ // the thread infrastructure to be in place (useful on the borders of
59
+ // initialization/destruction).
60
+ static DTOR_LOCK : Mutex = MUTEX_INIT ;
61
+ static mut DTORS : * mut Vec < ( Key , Dtor ) > = 0 as * mut _ ;
58
62
59
63
// -------------------------------------------------------------------------
60
64
// Native bindings
@@ -124,30 +128,40 @@ extern "system" {
124
128
//
125
129
// FIXME: This could probably be at least a little faster with a BTree.
126
130
127
- fn init_dtors ( ) {
128
- let dtors = box Mutex :: new ( Vec :: < ( Key , Dtor ) > :: new ( ) ) ;
129
- unsafe {
130
- DTORS = mem :: transmute ( dtors ) ;
131
- }
131
+ unsafe fn init_dtors ( ) {
132
+ if ! DTORS . is_null ( ) { return }
133
+
134
+ let dtors = box Vec :: < ( Key , Dtor ) > :: new ( ) ;
135
+ DTORS = mem :: transmute ( dtors ) ;
132
136
133
- rt:: at_exit ( move || unsafe {
134
- mem:: transmute :: < _ , Box < Mutex < Vec < ( Key , Dtor ) > > > > ( DTORS ) ;
137
+ rt:: at_exit ( move || {
138
+ DTOR_LOCK . lock ( ) ;
139
+ let dtors = DTORS ;
135
140
DTORS = 0 as * mut _ ;
141
+ mem:: transmute :: < _ , Box < Vec < ( Key , Dtor ) > > > ( dtors) ;
142
+ assert ! ( DTORS . is_null( ) ) ; // can't re-init after destructing
143
+ DTOR_LOCK . unlock ( ) ;
136
144
} ) ;
137
145
}
138
146
139
147
unsafe fn register_dtor ( key : Key , dtor : Dtor ) {
140
- INIT_DTORS . doit ( init_dtors) ;
141
- let mut dtors = ( * DTORS ) . lock ( ) ;
142
- dtors. push ( ( key, dtor) ) ;
148
+ DTOR_LOCK . lock ( ) ;
149
+ init_dtors ( ) ;
150
+ ( * DTORS ) . push ( ( key, dtor) ) ;
151
+ DTOR_LOCK . unlock ( ) ;
143
152
}
144
153
145
154
unsafe fn unregister_dtor ( key : Key ) -> bool {
146
- if DTORS . is_null ( ) { return false }
147
- let mut dtors = ( * DTORS ) . lock ( ) ;
148
- let before = dtors. len ( ) ;
149
- dtors. retain ( |& ( k, _) | k != key) ;
150
- dtors. len ( ) != before
155
+ DTOR_LOCK . lock ( ) ;
156
+ init_dtors ( ) ;
157
+ let ret = {
158
+ let dtors = & mut * DTORS ;
159
+ let before = dtors. len ( ) ;
160
+ dtors. retain ( |& ( k, _) | k != key) ;
161
+ dtors. len ( ) != before
162
+ } ;
163
+ DTOR_LOCK . unlock ( ) ;
164
+ ret
151
165
}
152
166
153
167
// -------------------------------------------------------------------------
@@ -219,12 +233,20 @@ unsafe extern "system" fn on_tls_callback(h: LPVOID,
219
233
}
220
234
221
235
unsafe fn run_dtors ( ) {
222
- if DTORS . is_null ( ) { return }
223
236
let mut any_run = true ;
224
237
for _ in range ( 0 , 5 i) {
225
238
if !any_run { break }
226
239
any_run = false ;
227
- let dtors = ( * DTORS ) . lock ( ) . iter ( ) . map ( |p| * p) . collect :: < Vec < _ > > ( ) ;
240
+ let dtors = {
241
+ DTOR_LOCK . lock ( ) ;
242
+ let ret = if DTORS . is_null ( ) {
243
+ Vec :: new ( )
244
+ } else {
245
+ ( * DTORS ) . iter ( ) . map ( |s| * s) . collect ( )
246
+ } ;
247
+ DTOR_LOCK . unlock ( ) ;
248
+ ret
249
+ } ;
228
250
for & ( key, dtor) in dtors. iter ( ) {
229
251
let ptr = TlsGetValue ( key) ;
230
252
if !ptr. is_null ( ) {
0 commit comments