static_init/
exit_sequentializer.rs

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    // if a panic is launched during a finalization
29    // static that have not yet been finalized will not
30    // be finalized
31    #[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    /// A sequentializer that store finalize_callback  
37    /// for execution at program exit
38    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                // SAFETY:
63                // the reference created mut point to an object:
64                //   - this is full-filled by the requirement that the ExitSequentializer object
65                //     must be static.
66                //   - there should not have any mutable reference to the object: this is
67                //   a requirement of the ExitSequentializer object new method
68                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        /// Store a reference of the static for execution of the
80        /// finalize call back at program exit
81        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    /// This object is only used to for const initialization
108    const MUTEX_INIT: Mutex<Option<&'static Node>> = Mutex::new(None);
109
110    impl<Tol> ExitSequentializer<Tol> {
111        #[inline(always)]
112        /// Create a new ExitSequentializer
113        ///
114        /// Useless if the target object is not 'static
115        pub const fn new(l: SyncPhaseLocker) -> Self {
116            //Self(GLOBAL_INIT)
117            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    // SAFETY: it is safe because it does implement synchronized locks
144    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    // SAFETY: it is safe because it does implement synchronized locks
175    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    /// A sequentializer that store finalize_callback  
299    /// for execution at thread exit
300    struct ThreadExitSequentializerBase<Tol> {
301        sub: SubSequentializer<Tol>,
302        next: Cell<Option<&'static Node>>,
303    }
304
305    // if a panic is launched during a finalization
306    // static that have not yet been finalized will not
307    // be finalized
308    #[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    /// A sequentializer that store finalize_callback  
315    /// for execution at thread exit
316    pub(crate) struct ThreadExitSequentializer<Tol>(ThreadExitSequentializerBase<Tol>);
317
318    #[allow(clippy::declare_interior_mutable_const)]
319    /// This object is only used to be copied
320    const CELL_INIT: Cell<Option<&'static Node>> = Cell::new(None);
321
322    impl<Tol> ThreadExitSequentializer<Tol> {
323        #[inline(always)]
324        /// Useless if the target object is not a static thread_local
325        pub const fn new(l: UnSyncPhaseLocker) -> Self {
326            //Self(GLOBAL_INIT)
327            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    // SAFETY: it is safe because it does implement locking panic
354    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    // SAFETY: it is safe because it does implement circular initialization panic
385    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        //On thread exit
486        //non nul pointers between .CRT$XLA and .CRT$XLZ will be
487        //run... => So we could implement thread_local drop without
488        //registration...
489        #[link_section = ".CRT$XLAZ"] //TODO: voir si cela est bien fait après la librairie standard
490        #[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                    // SAFETY ptr must refer to a thread_local static
498                    // this is required by ThreadExitSequentializer::new
499                    r.execute();
500                    o_ptr = r.take_next();
501                    o_ptr.or_else(|| REGISTER.take());
502                }
503                DONE.set(true)
504            }
505
506            // Copy pasted from: std/src/sys/windows/thread_local_key.rs
507            //
508            // See comments above for what this is doing. Note that we don't need this
509            // trickery on GNU windows, just on MSVC.
510            //
511            // TODO: better implement it as in libstdc++ implementation of __cxa_thread_atexit?
512            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        /// Store a reference of the thread local static for execution of the
532        /// finalize call back at thread exit
533        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        /// Register a function along with a pointer.
569        ///
570        /// When the thread exit, functions register with this
571        /// function will be called in reverse order of their addition
572        /// and will take as argument the `data`.
573        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()); //
579                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        /// Store a reference of the thread local static for execution of the
603        /// finalize call back at thread exit
604        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        //minimum number of time a destructor key may be registered while destructors are run
643        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        //pthread key destructor are not run in the main thread
661        //so we must force this
662        #[destructor(0)]
663        extern "C" fn force_main_thread_destructor() {
664            execute_destroy(ptr::null_mut());
665        }
666
667        /// Here panics are prefered so that we are sure
668        /// that if it returns false, no memory allocation
669        /// has been done, which avoid recursions.
670        ///
671        /// To do => an init()
672        fn get_key() -> Option<pthread_key_t> {
673            //TODO a revoir
674            let mut key = DESTRUCTOR_KEY.load(Ordering::Acquire);
675            let mut lk = 0;
676            while key == usize::MAX {
677                //The minimum number of key is 128, we require only one contrarily to
678                //what happen in standard library (one per thread local on some targets)
679                //on glibc the limit is 1024. So this could definitively fail.
680                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, //Just in case, to be sure to sync with lib pthread state.
698                    ) {
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        /// Store a reference of the thread local static for execution of the
741        /// finalize call back at thread exit
742        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}