@@ -186,8 +186,65 @@ fn join_orders_after_tls_destructors() {
186186 }
187187}
188188
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+
189245fn main ( ) {
190246 check_destructors ( ) ;
191247 check_blocking ( ) ;
192248 join_orders_after_tls_destructors ( ) ;
249+ dtors_in_dtors_in_dtors ( ) ;
193250}
0 commit comments