@@ -186,8 +186,65 @@ fn join_orders_after_tls_destructors() {
186
186
}
187
187
}
188
188
189
+ fn dtors_in_dtors_in_dtors ( ) {
190
+ use std:: cell:: UnsafeCell ;
191
+ use std:: sync:: { Arc , Condvar , Mutex } ;
192
+
193
+ #[ derive( Clone , Default ) ]
194
+ struct Signal ( Arc < ( Mutex < bool > , Condvar ) > ) ;
195
+
196
+ impl Signal {
197
+ fn notify ( & self ) {
198
+ let ( set, cvar) = & * self . 0 ;
199
+ * set. lock ( ) . unwrap ( ) = true ;
200
+ cvar. notify_one ( ) ;
201
+ }
202
+
203
+ fn wait ( & self ) {
204
+ let ( set, cvar) = & * self . 0 ;
205
+ let mut set = set. lock ( ) . unwrap ( ) ;
206
+ while !* set {
207
+ set = cvar. wait ( set) . unwrap ( ) ;
208
+ }
209
+ }
210
+ }
211
+
212
+ struct NotifyOnDrop ( Signal ) ;
213
+
214
+ impl Drop for NotifyOnDrop {
215
+ fn drop ( & mut self ) {
216
+ let NotifyOnDrop ( ref f) = * self ;
217
+ f. notify ( ) ;
218
+ }
219
+ }
220
+
221
+ struct S1 ( Signal ) ;
222
+ thread_local ! ( static K1 : UnsafeCell <Option <S1 >> = UnsafeCell :: new( None ) ) ;
223
+ thread_local ! ( static K2 : UnsafeCell <Option <NotifyOnDrop >> = UnsafeCell :: new( None ) ) ;
224
+
225
+ impl Drop for S1 {
226
+ fn drop ( & mut self ) {
227
+ let S1 ( ref signal) = * self ;
228
+ unsafe {
229
+ let _ = K2 . try_with ( |s| * s. get ( ) = Some ( NotifyOnDrop ( signal. clone ( ) ) ) ) ;
230
+ }
231
+ }
232
+ }
233
+
234
+ let signal = Signal :: default ( ) ;
235
+ let signal2 = signal. clone ( ) ;
236
+ let _t = thread:: spawn ( move || unsafe {
237
+ let mut signal = Some ( signal2) ;
238
+ K1 . with ( |s| * s. get ( ) = Some ( S1 ( signal. take ( ) . unwrap ( ) ) ) ) ;
239
+ } ) ;
240
+ // Note that this test will deadlock if TLS destructors aren't run (this
241
+ // requires the destructor to be run to pass the test).
242
+ signal. wait ( ) ;
243
+ }
244
+
189
245
fn main ( ) {
190
246
check_destructors ( ) ;
191
247
check_blocking ( ) ;
192
248
join_orders_after_tls_destructors ( ) ;
249
+ dtors_in_dtors_in_dtors ( ) ;
193
250
}
0 commit comments