1#![cfg(any(elf, mach_o, coff))]
2
3mod exit_manager {
4 use crate::lazy_sequentializer::SyncSequentializer as SubSequentializer;
5 use crate::phase_locker::{LockNature, LockResult, SyncPhaseGuard, SyncReadPhaseGuard};
6 use crate::phase_locker::{Mutex, SyncPhaseLocker};
7 use crate::Finaly;
8 use crate::{
9 FinalizableLazySequentializer, GeneratorTolerance, LazySequentializer, Phase, Phased,
10 Sequential, Sequentializer,
11 };
12
13 #[cfg(any(feature = "parking_lot_core", debug_mode))]
14 use std::panic::{RefUnwindSafe, UnwindSafe};
15
16 trait OnExit {
17 fn take_next(&self) -> Option<&'static Node>;
18 fn execute(&self);
19 }
20
21 type Node = dyn 'static + OnExit + Sync;
22
23 struct ExitSequentializerBase<G> {
24 sub: SubSequentializer<G>,
25 next: Mutex<Option<&'static Node>>,
26 }
27
28 #[cfg(any(feature = "parking_lot_core", debug_mode))]
32 impl<G> RefUnwindSafe for ExitSequentializerBase<G> {}
33 #[cfg(any(feature = "parking_lot_core", debug_mode))]
34 impl<G> UnwindSafe for ExitSequentializerBase<G> {}
35
36 pub(crate) struct ExitSequentializer<Tol>(ExitSequentializerBase<Tol>);
39
40 mod reg {
41
42 use super::{ExitSequentializer, Node};
43 use crate::{destructor, Finaly, GeneratorTolerance, Sequential};
44
45 use crate::phase_locker::Mutex;
46
47 struct Register {
48 first: Option<&'static Node>,
49 registration_opened: bool,
50 }
51 static REGISTER: Mutex<Register> = Mutex::new(Register {
52 first: None,
53 registration_opened: true,
54 });
55
56 #[destructor(0)]
57 extern "C" fn execute_at_exit() {
58 let mut l = REGISTER.lock();
59 let mut list: Option<&'static Node> = l.first.take();
60 drop(l);
61 while let Some(on_exit) = list {
62 on_exit.execute();
69 list = on_exit.take_next().or_else(|| {
70 let mut reg = REGISTER.lock();
71 if reg.first.is_none() {
72 reg.registration_opened = false;
73 }
74 reg.first.take()
75 });
76 }
77 }
78
79 pub(crate) fn finalize_at_exit<
82 T: 'static + Sequential<Sequentializer = ExitSequentializer<Tol>> + Sync,
83 Tol: 'static + GeneratorTolerance,
84 >(
85 st: &'static T,
86 ) -> bool
87 where
88 T::Data: 'static + Finaly,
89 {
90 let mut l = REGISTER.lock();
91 if l.registration_opened {
92 let mut next = Sequential::sequentializer(st).0.next.lock();
93 assert!(
94 next.is_none(),
95 "Double registration of an ExitSequentializer for finalization at program exit"
96 );
97 *next = l.first.replace(st as &Node);
98 true
99 } else {
100 false
101 }
102 }
103 }
104 pub(crate) use reg::finalize_at_exit;
105
106 #[allow(clippy::declare_interior_mutable_const)]
107 const MUTEX_INIT: Mutex<Option<&'static Node>> = Mutex::new(None);
109
110 impl<Tol> ExitSequentializer<Tol> {
111 #[inline(always)]
112 pub const fn new(l: SyncPhaseLocker) -> Self {
116 Self(ExitSequentializerBase {
118 sub: SubSequentializer::new(l),
119 next: MUTEX_INIT,
120 })
121 }
122 }
123
124 impl<Tol> AsRef<SubSequentializer<Tol>> for ExitSequentializer<Tol> {
125 #[inline(always)]
126 fn as_ref(&self) -> &SubSequentializer<Tol> {
127 &self.0.sub
128 }
129 }
130 impl<Tol> AsMut<SubSequentializer<Tol>> for ExitSequentializer<Tol> {
131 #[inline(always)]
132 fn as_mut(&mut self) -> &mut SubSequentializer<Tol> {
133 &mut self.0.sub
134 }
135 }
136
137 impl<Tol: GeneratorTolerance> Phased for ExitSequentializer<Tol> {
138 #[inline(always)]
139 fn phase(this: &Self) -> Phase {
140 Phased::phase(&this.0.sub)
141 }
142 }
143 unsafe impl<'a, T: 'a + Sequential<Sequentializer = Self>, Tol: GeneratorTolerance + 'static>
145 Sequentializer<'a, T> for ExitSequentializer<Tol>
146 where
147 T: 'static + Sync,
148 T::Data: 'static + Finaly,
149 {
150 type ReadGuard = SyncReadPhaseGuard<'a, T::Data>;
151 type WriteGuard = SyncPhaseGuard<'a, T::Data>;
152 #[inline(always)]
153 fn lock(
154 st: &'a T,
155 lock_nature: impl Fn(Phase) -> LockNature,
156 hint: Phase,
157 ) -> LockResult<SyncReadPhaseGuard<'a, T::Data>, SyncPhaseGuard<'a, T::Data>> {
158 <SubSequentializer<Tol> as Sequentializer<T>>::lock(st, lock_nature, hint)
159 }
160 #[inline(always)]
161 fn try_lock(
162 st: &'a T,
163 lock_nature: impl Fn(Phase) -> LockNature,
164 hint: Phase,
165 ) -> Option<LockResult<Self::ReadGuard, Self::WriteGuard>> {
166 <SubSequentializer<Tol> as Sequentializer<T>>::try_lock(st, lock_nature, hint)
167 }
168 #[inline(always)]
169 fn lock_mut(st: &'a mut T) -> SyncPhaseGuard<'a, T::Data> {
170 <SubSequentializer<Tol> as Sequentializer<T>>::lock_mut(st)
171 }
172 }
173
174 unsafe impl<T: 'static + Sequential<Sequentializer = Self>, Tol: GeneratorTolerance + 'static>
176 LazySequentializer<'static, T> for ExitSequentializer<Tol>
177 where
178 T: 'static + Sync,
179 T::Data: 'static + Finaly,
180 {
181 const INITIALIZED_HINT: Phase = Phase::INITIALIZED_AND_REGISTERED;
182
183 #[inline(always)]
184 fn init(
185 st: &'static T,
186 shall_init: impl Fn(Phase) -> bool,
187 init: impl FnOnce(&'static <T as Sequential>::Data),
188 ) -> Phase {
189 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::init(
190 st,
191 shall_init,
192 init,
193 finalize_at_exit,
194 )
195 }
196 #[inline(always)]
197 fn init_then_read_guard(
198 st: &'static T,
199 shall_init: impl Fn(Phase) -> bool,
200 init: impl FnOnce(&'static <T as Sequential>::Data),
201 ) -> Self::ReadGuard {
202 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::init_then_read_guard(
203 st,
204 shall_init,
205 init,
206 finalize_at_exit,
207 )
208 }
209 #[inline(always)]
210 fn init_then_write_guard(
211 st: &'static T,
212 shall_init: impl Fn(Phase) -> bool,
213 init: impl FnOnce(&'static <T as Sequential>::Data),
214 ) -> Self::WriteGuard {
215 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::init_then_write_guard(
216 st,
217 shall_init,
218 init,
219 finalize_at_exit,
220 )
221 }
222 #[inline(always)]
223 fn try_init_then_read_guard(
224 st: &'static T,
225 shall_init: impl Fn(Phase) -> bool,
226 init: impl FnOnce(&'static <T as Sequential>::Data),
227 ) -> Option<Self::ReadGuard> {
228 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::try_init_then_read_guard(
229 st,
230 shall_init,
231 init,
232 finalize_at_exit,
233 )
234 }
235 #[inline(always)]
236 fn try_init_then_write_guard(
237 st: &'static T,
238 shall_init: impl Fn(Phase) -> bool,
239 init: impl FnOnce(&'static <T as Sequential>::Data),
240 ) -> Option<Self::WriteGuard> {
241 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::try_init_then_write_guard(
242 st,
243 shall_init,
244 init,
245 finalize_at_exit,
246 )
247 }
248 }
249
250 impl<
251 T: Sequential<Sequentializer = ExitSequentializer<Tol>>,
252 Tol: 'static + GeneratorTolerance,
253 > OnExit for T
254 where
255 T::Data: 'static + Finaly,
256 {
257 fn take_next(&self) -> Option<&'static Node> {
258 Sequential::sequentializer(self).0.next.lock().take()
259 }
260 fn execute(&self) {
261 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::finalize_callback(
262 self,
263 Finaly::finaly,
264 );
265 }
266 }
267}
268pub(crate) use exit_manager::ExitSequentializer;
269
270#[cfg(feature = "thread_local")]
271pub(crate) use local_manager::ThreadExitSequentializer;
272
273#[cfg(feature = "thread_local")]
274mod local_manager {
275
276 use crate::lazy_sequentializer::UnSyncSequentializer as SubSequentializer;
277 use crate::{
278 FinalizableLazySequentializer, Finaly, GeneratorTolerance, LazySequentializer, Phase,
279 Phased, Sequential, Sequentializer,
280 };
281
282 use core::cell::Cell;
283
284 use crate::phase_locker::{
285 LockNature, LockResult, UnSyncPhaseGuard, UnSyncPhaseLocker, UnSyncReadPhaseGuard,
286 };
287
288 #[cfg(any(feature = "parking_lot_core", debug_mode))]
289 use std::panic::{RefUnwindSafe, UnwindSafe};
290
291 trait OnExit {
292 fn take_next(&self) -> Option<&'static Node>;
293 fn execute(&self);
294 }
295
296 type Node = dyn 'static + OnExit;
297
298 struct ThreadExitSequentializerBase<Tol> {
301 sub: SubSequentializer<Tol>,
302 next: Cell<Option<&'static Node>>,
303 }
304
305 #[cfg(any(feature = "parking_lot_core", debug_mode))]
309 impl<G> RefUnwindSafe for ThreadExitSequentializerBase<G> {}
310 #[cfg(any(feature = "parking_lot_core", debug_mode))]
311 impl<G> UnwindSafe for ThreadExitSequentializerBase<G> {}
312
313 #[cfg_attr(docsrs, doc(cfg(feature = "thread_local")))]
314 pub(crate) struct ThreadExitSequentializer<Tol>(ThreadExitSequentializerBase<Tol>);
317
318 #[allow(clippy::declare_interior_mutable_const)]
319 const CELL_INIT: Cell<Option<&'static Node>> = Cell::new(None);
321
322 impl<Tol> ThreadExitSequentializer<Tol> {
323 #[inline(always)]
324 pub const fn new(l: UnSyncPhaseLocker) -> Self {
326 Self(ThreadExitSequentializerBase {
328 sub: SubSequentializer::new(l),
329 next: CELL_INIT,
330 })
331 }
332 }
333
334 impl<Tol> AsRef<SubSequentializer<Tol>> for ThreadExitSequentializer<Tol> {
335 #[inline(always)]
336 fn as_ref(&self) -> &SubSequentializer<Tol> {
337 &self.0.sub
338 }
339 }
340 impl<Tol> AsMut<SubSequentializer<Tol>> for ThreadExitSequentializer<Tol> {
341 #[inline(always)]
342 fn as_mut(&mut self) -> &mut SubSequentializer<Tol> {
343 &mut self.0.sub
344 }
345 }
346
347 impl<Tol: GeneratorTolerance> Phased for ThreadExitSequentializer<Tol> {
348 #[inline(always)]
349 fn phase(this: &Self) -> Phase {
350 Phased::phase(&this.0.sub)
351 }
352 }
353 unsafe impl<'a, T: 'static + Sequential<Sequentializer = Self>, Tol: GeneratorTolerance + 'static>
355 Sequentializer<'a, T> for ThreadExitSequentializer<Tol>
356 where
357 T::Data: 'static + Finaly,
358 {
359 type ReadGuard = UnSyncReadPhaseGuard<'a, T::Data>;
360 type WriteGuard = UnSyncPhaseGuard<'a, T::Data>;
361
362 #[inline(always)]
363 fn lock(
364 st: &'a T,
365 lock_nature: impl Fn(Phase) -> LockNature,
366 hint: Phase,
367 ) -> LockResult<UnSyncReadPhaseGuard<'a, T::Data>, UnSyncPhaseGuard<'a, T::Data>> {
368 <SubSequentializer<Tol> as Sequentializer<T>>::lock(st, lock_nature, hint)
369 }
370 #[inline(always)]
371 fn try_lock(
372 st: &'a T,
373 lock_nature: impl Fn(Phase) -> LockNature,
374 hint: Phase,
375 ) -> Option<LockResult<Self::ReadGuard, Self::WriteGuard>> {
376 <SubSequentializer<Tol> as Sequentializer<T>>::try_lock(st, lock_nature, hint)
377 }
378 #[inline(always)]
379 fn lock_mut(st: &'a mut T) -> UnSyncPhaseGuard<'a, T::Data> {
380 <SubSequentializer<Tol> as Sequentializer<T>>::lock_mut(st)
381 }
382 }
383
384 unsafe impl<T: 'static + Sequential<Sequentializer = Self>, Tol: GeneratorTolerance + 'static>
386 LazySequentializer<'static, T> for ThreadExitSequentializer<Tol>
387 where
388 T::Data: 'static + Finaly,
389 {
390 const INITIALIZED_HINT: Phase = Phase::INITIALIZED_AND_REGISTERED;
391 #[inline(always)]
392 fn init(
393 st: &'static T,
394 shall_proceed: impl Fn(Phase) -> bool,
395 init: impl FnOnce(&'static <T as Sequential>::Data),
396 ) -> Phase {
397 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::init(
398 st,
399 shall_proceed,
400 init,
401 finalize_at_thread_exit,
402 )
403 }
404 #[inline(always)]
405 fn init_then_read_guard(
406 st: &'static T,
407 shall_proceed: impl Fn(Phase) -> bool,
408 init: impl FnOnce(&'static <T as Sequential>::Data),
409 ) -> Self::ReadGuard {
410 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::init_then_read_guard(
411 st,
412 shall_proceed,
413 init,
414 finalize_at_thread_exit,
415 )
416 }
417 #[inline(always)]
418 fn init_then_write_guard(
419 st: &'static T,
420 shall_proceed: impl Fn(Phase) -> bool,
421 init: impl FnOnce(&'static <T as Sequential>::Data),
422 ) -> Self::WriteGuard {
423 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::init_then_write_guard(
424 st,
425 shall_proceed,
426 init,
427 finalize_at_thread_exit,
428 )
429 }
430 #[inline(always)]
431 fn try_init_then_read_guard(
432 st: &'static T,
433 shall_proceed: impl Fn(Phase) -> bool,
434 init: impl FnOnce(&'static <T as Sequential>::Data),
435 ) -> Option<Self::ReadGuard> {
436 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::try_init_then_read_guard(
437 st,
438 shall_proceed,
439 init,
440 finalize_at_thread_exit,
441 )
442 }
443 #[inline(always)]
444 fn try_init_then_write_guard(
445 st: &'static T,
446 shall_proceed: impl Fn(Phase) -> bool,
447 init: impl FnOnce(&'static <T as Sequential>::Data),
448 ) -> Option<Self::WriteGuard> {
449 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::try_init_then_write_guard(
450 st,
451 shall_proceed,
452 init,
453 finalize_at_thread_exit,
454 )
455 }
456 }
457
458 impl<
459 T: 'static + Sequential<Sequentializer = ThreadExitSequentializer<Tol>>,
460 Tol: 'static + GeneratorTolerance,
461 > OnExit for T
462 where
463 T::Data: 'static + Finaly,
464 {
465 fn take_next(&self) -> Option<&'static Node> {
466 Sequential::sequentializer(self).0.next.take()
467 }
468 fn execute(&self) {
469 <SubSequentializer<Tol> as FinalizableLazySequentializer<T>>::finalize_callback(
470 self,
471 Finaly::finaly,
472 );
473 }
474 }
475
476 #[cfg(coff_thread_at_exit)]
477 mod windows {
478 use super::{Node, ThreadExitSequentializer};
479 use crate::{Finaly, GeneratorTolerance, Sequential};
480 use core::cell::Cell;
481
482 use winapi::shared::minwindef::{DWORD, LPVOID};
483 use winapi::um::winnt::{DLL_PROCESS_DETACH, DLL_THREAD_DETACH};
484
485 #[link_section = ".CRT$XLAZ"] #[used]
491 pub static AT_THEAD_EXIT: extern "system" fn(LPVOID, DWORD, LPVOID) = destroy;
492
493 extern "system" fn destroy(_: LPVOID, reason: DWORD, _: LPVOID) {
494 if reason == DLL_THREAD_DETACH || reason == DLL_PROCESS_DETACH {
495 let mut o_ptr = REGISTER.take();
496 while let Some(r) = o_ptr {
497 r.execute();
500 o_ptr = r.take_next();
501 o_ptr.or_else(|| REGISTER.take());
502 }
503 DONE.set(true)
504 }
505
506 unsafe { reference_tls_used() };
513 #[cfg(target_env = "msvc")]
514 unsafe fn reference_tls_used() {
515 extern "C" {
516 static _tls_used: u8;
517 }
518 core::ptr::read_volatile(&_tls_used);
519 }
520 #[cfg(not(target_env = "msvc"))]
521 unsafe fn reference_tls_used() {}
522 }
523
524 #[thread_local]
525 static REGISTER: Cell<Option<&'static Node>> = Cell::new(None);
526
527 #[thread_local]
528 static DONE: Cell<bool> = Cell::new(false);
529
530 #[cfg_attr(docsrs, doc(cfg(feature = "thread_local")))]
531 pub(crate) fn finalize_at_thread_exit<
534 T: Sequential<Sequentializer = ThreadExitSequentializer<Tol>>,
535 Tol: 'static + GeneratorTolerance,
536 >(
537 st: &'static T,
538 ) -> bool
539 where
540 T::Data: 'static + Finaly,
541 {
542 if DONE.get() {
543 false
544 } else {
545 Sequential::sequentializer(st).0.next.set(REGISTER.take());
546 REGISTER.set(Some(st as &Node));
547 true
548 }
549 }
550 }
551 #[cfg(coff_thread_at_exit)]
552 use windows::finalize_at_thread_exit;
553
554 #[cfg(all(cxa_thread_at_exit, not(feature = "test_pthread_support")))]
555 mod cxa {
556 use super::{Node, ThreadExitSequentializer};
557 use crate::{Finaly, GeneratorTolerance, Sequential};
558 use core::cell::Cell;
559 use core::ptr::null_mut;
560
561 extern "C" {
562 #[linkage = "extern_weak"]
563 static __dso_handle: *mut u8;
564 #[linkage = "extern_weak"]
565 static __cxa_thread_atexit_impl: *const core::ffi::c_void;
566 }
567
568 fn at_thread_exit(f: extern "C" fn(*mut u8), data: *mut u8) {
574 type CxaThreadAtExit =
575 extern "C" fn(f: extern "C" fn(*mut u8), data: *mut u8, dso_handle: *mut u8);
576
577 unsafe {
578 assert!(!__cxa_thread_atexit_impl.is_null()); let at_thread_exit_impl: CxaThreadAtExit =
580 core::mem::transmute(__cxa_thread_atexit_impl);
581 at_thread_exit_impl(f, data, __dso_handle);
582 }
583 }
584
585 #[thread_local]
586 static REGISTER: Cell<Option<&'static Node>> = Cell::new(None);
587
588 #[thread_local]
589 static DESTROYING: Cell<bool> = Cell::new(false);
590
591 extern "C" fn execute_destroy(_: *mut u8) {
592 DESTROYING.set(true);
593 let mut o_r = REGISTER.take();
594 while let Some(r) = o_r {
595 r.execute();
596 o_r = r.take_next().or_else(|| REGISTER.take());
597 }
598 DESTROYING.set(false);
599 }
600
601 #[cfg_attr(docsrs, doc(cfg(feature = "thread_local")))]
602 pub(crate) fn finalize_at_thread_exit<
605 T: 'static + Sequential<Sequentializer = ThreadExitSequentializer<Tol>>,
606 Tol: 'static + GeneratorTolerance,
607 >(
608 st: &'static T,
609 ) -> bool
610 where
611 T::Data: 'static + Finaly,
612 {
613 let old = REGISTER.take();
614 if let Some(old) = old {
615 Sequential::sequentializer(st).0.next.set(Some(old));
616 } else if !DESTROYING.get() {
617 at_thread_exit(execute_destroy, null_mut())
618 }
619 REGISTER.set(Some(st as &Node));
620 true
621 }
622 }
623 #[cfg(all(cxa_thread_at_exit, not(feature = "test_pthread_support")))]
624 use cxa::finalize_at_thread_exit;
625
626 #[cfg(any(pthread_thread_at_exit, feature = "test_pthread_support"))]
627 mod pthread {
628 use super::{Node, ThreadExitSequentializer};
629 use crate::{Finaly, GeneratorTolerance, Sequential};
630 use static_init_macro::destructor;
631
632 use core::cell::Cell;
633 use core::ffi::c_void;
634 use core::ptr::{self, NonNull};
635 use core::sync::atomic::{AtomicUsize, Ordering};
636
637 use libc::{
638 pthread_getspecific, pthread_key_create, pthread_key_delete, pthread_key_t,
639 pthread_setspecific,
640 };
641
642 const _POSIX_THREAD_DESTRUCTOR_ITERATIONS: usize = 4;
644
645 static DESTRUCTOR_KEY: AtomicUsize = AtomicUsize::new(usize::MAX);
646
647 #[thread_local]
648 static ITERATION_COUNT: Cell<usize> = Cell::new(0);
649
650 #[thread_local]
651 static REGISTER: Cell<Option<&'static Node>> = Cell::new(None);
652
653 extern "C" fn execute_destroy(_: *mut c_void) {
654 let mut opt_head = REGISTER.take();
655 while let Some(r) = opt_head {
656 r.execute();
657 opt_head = r.take_next().or_else(|| REGISTER.take());
658 }
659 }
660 #[destructor(0)]
663 extern "C" fn force_main_thread_destructor() {
664 execute_destroy(ptr::null_mut());
665 }
666
667 fn get_key() -> Option<pthread_key_t> {
673 let mut key = DESTRUCTOR_KEY.load(Ordering::Acquire);
675 let mut lk = 0;
676 while key == usize::MAX {
677 if unsafe {
681 pthread_key_create(&mut lk as *mut pthread_key_t, Some(execute_destroy)) != 0
682 } {
683 key = DESTRUCTOR_KEY.load(Ordering::Acquire);
684 if key != usize::MAX {
685 break;
686 } else {
687 return None;
688 }
689 }
690 if lk as usize == usize::MAX {
691 unsafe { pthread_key_delete(lk) };
692 } else {
693 key = match DESTRUCTOR_KEY.compare_exchange(
694 usize::MAX,
695 lk as usize,
696 Ordering::AcqRel,
697 Ordering::Acquire, ) {
699 Ok(k) => k,
700 Err(k) => {
701 unsafe { pthread_key_delete(lk) };
702 k
703 }
704 };
705 }
706 }
707 Some(key as pthread_key_t)
708 }
709 fn register_on_thread_exit<
710 T: Sequential<Sequentializer = ThreadExitSequentializer<Tol>>,
711 Tol: 'static + GeneratorTolerance,
712 >(
713 st: &'static T,
714 key: pthread_key_t,
715 ) -> bool
716 where
717 T::Data: 'static + Finaly,
718 {
719 let specific = unsafe { pthread_getspecific(key) };
720
721 if specific.is_null() {
722 if ITERATION_COUNT.get() < _POSIX_THREAD_DESTRUCTOR_ITERATIONS {
723 if unsafe { pthread_setspecific(key, NonNull::dangling().as_ptr()) } != 0 {
724 return false;
725 }
726
727 ITERATION_COUNT.set(ITERATION_COUNT.get() + 1);
728 } else {
729 return false;
730 }
731 }
732
733 Sequential::sequentializer(st).0.next.set(REGISTER.take());
734
735 REGISTER.set(Some(st as &Node));
736 true
737 }
738
739 #[cfg_attr(docsrs, doc(cfg(feature = "thread_local")))]
740 pub(crate) fn finalize_at_thread_exit<
743 T: Sequential<Sequentializer = ThreadExitSequentializer<Tol>>,
744 Tol: 'static + GeneratorTolerance,
745 >(
746 st: &'static T,
747 ) -> bool
748 where
749 T::Data: 'static + Finaly,
750 {
751 match get_key() {
752 Some(key) => register_on_thread_exit(st, key),
753 None => false,
754 }
755 }
756 }
757 #[cfg(any(pthread_thread_at_exit, feature = "test_pthread_support"))]
758 use pthread::finalize_at_thread_exit;
759}