static_init/lib.rs
1// Copyright 2021 Olivier Kannengieser
2//
3// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8//! Safe non const initialized statics and safe mutable statics with unbeatable performance.
9//!
10//! Also provides code execution at program start-up/exit.
11//!
12//! # Feature
13//!
14//! - [x] non const initialized statics.
15//! - [x] statics dropped at program exit.
16//! - [x] safe mutable lazy statics (locked).
17//! - [x] every feature with `no_std` support.
18//! - [x] unbeatable performance, can be order of magnitude faster that any other solution.
19//! - [x] registration of code execution at program exit without allocation (as opposed to libc::at_exit).
20//! - [x] ergonomic syntax.
21//! - [x] sound and safe.
22//! - [x] on nigtly, `thread_locals` and safe mutable `thread_locals`, guaranteed to be
23//! dropped at thread exit with the lowest possible overhead compared to
24//! what is provided by system library thread support or the standard library!
25//!
26//! # Fastest Lazy Statics
27//!
28//! This crate provides *lazy statics* on all plateforms.
29//!
30//! On unixes and windows *lesser lazy statics* are *lazy* during program startup phase
31//! (before `main` is called). Once main is called, those statics are all guaranteed to be
32//! initialized and any access to them almost no incur any performance cost
33//!
34//! ```
35//! use static_init::{dynamic};
36//!
37//! #[dynamic]
38//! static L1: Vec<i32> = vec![1,2,3,4,5,6];
39//!
40//! #[dynamic(drop)]
41//! static mut L2: Vec<i32> = {let mut v = L1.clone(); v.push(43); v};
42//! ```
43//!
44//! Those static initialization and access can be 10x faster than
45//! what is provided by the standard library or other crates.
46//!
47//! # Safe Mutable Statics
48//!
49//! Just add the `mut` keyword to have mutable locked statics.
50//!
51//! ```
52//! use static_init::{dynamic};
53//!
54//! #[dynamic]
55//! static mut L1: Vec<i32> = vec![1,2,3,4,5,6];
56//!
57//! #[dynamic(drop)]
58//! static mut L2: Vec<i32> = {
59//! //get a unique lock:
60//! let mut lock = L1.write();
61//! lock.push(42);
62//! lock.clone()
63//! };
64//! ```
65//!
66//! Those statics use an *apdaptative phase locker* that gives them surprising performance.
67//!
68//! # Classical Lazy statics
69//!
70//! By default, initialization of statics declared with the `dynamic` is forced before main
71//! start on plateform that support it. If *lazyness* if a required feature, the attribute argument
72//! `lazy` can be used.
73//!
74//! ```rust
75//! use static_init::{dynamic};
76//!
77//! #[dynamic(lazy)]
78//! static L1: Vec<i32> = vec![1,2,3,4,5,6];
79//!
80//! #[dynamic(lazy,drop)]
81//! static mut L3: Vec<i32> =L1.clone();
82//! ```
83//!
84//! Even if the static is not mut, dropped statics are always locked. There is also a `finalize` attribute
85//! argument that can be used to run a "drop" equivalent at program exit but leaves the static unchanged.
86//!
87//! Those lazy also provide superior performances compared to other solutions.
88//!
89//! # `no_std` support
90//!
91//! On linux or Reddox (TBC) this library is `no_std`. The library use directly the `futex` system call
92//! to place thread in a wait queue when needed.
93//!
94//! On other plateform `no_std` support can be gain by using the `spin_loop` feature. NB that lock strategies
95//! based on spin loop are not system-fair and cause entire system slow-down.
96//!
97//! # Performant
98//!
99//! ## Under the hood
100//!
101//! The statics and mutable statics declared with `dynamic` attribute use what we
102//! call an *adaptative phase locker*. This is a lock that is in between a `Once`
103//! and a `RwLock`. It is carefully implemented as a variation over the `RwLock`
104//! algorithms of `parking_lot` crate with other tradeoff and different
105//! capabilities.
106//!
107//! It is qualified *adaptative* because the decision to take a read lock,
108//! a write lock or not to take a lock is performed while the lock attempt is
109//! performed and a thread may attempt to get a write lock but decides to be waked
110//! as the owner of a read lock if it is about to be placed in a wait queue.
111//!
112//! Statics and thread locals that need to register themselve for destruction at
113//! program or thread exit are implemented as members of an intrusive list. This
114//! implementation avoid heap memory allocation caused by system library support
115//! (`libc::at_exit`, `glibc::__cxa_at_thread_exit`, pthread... registers use heap
116//! memory allocation), and it avoid to fall on system library implementation
117//! limits that may cause `thread_locals` declared with `std::thread_locals` not to
118//! be dropped.
119//!
120//! Last but not least of the optimization, on windows and unixes (but not Mac yet)
121//! `dynamic` statics initialization is forced before main start. This fact unable
122//! a double check with a single boolean for all statics that is much faster other
123//! double check solution.
124//!
125//! ## Benchmark results
126//!
127//! (see the README file or run benchmark with `cargo bench --feature bench_nightly`)
128//!
129//! # Thread local support
130//!
131//! On nightly `thread_local` support can be enable with the feature
132//! `thread_local`. The attribute `dynamic` can be used with thread locals as with
133//! regular statics. In this case, the mutable `thread_local` will behave similarly
134//! to a RefCell with the same syntax as mutable lazy statics.
135//!
136//! ```rust
137//! # #![cfg_attr(feature = "thread_local", feature(thread_local))]
138//! # use static_init::{Finaly,dynamic};
139//! # #[cfg(feature = "thread_local")]
140//! # mod m{
141//! # use static_init::{dynamic};
142//!
143//! #[dynamic(drop)] //guaranteed to be drop: no leak contrarily to std::thread_local
144//! #[thread_local]
145//! static V: Vec<i32> = vec![1,1,2,3,5];
146//!
147//! #[dynamic]
148//! #[thread_local]
149//! static mut W: Vec<i32> = V.clone();
150//! # fn main() {
151//! assert_ne!(W.read().len(), 0);
152//! assert_ne!(W.try_read().unwrap().len(), 0);
153//! # }
154//! # }
155//! ```
156//!
157//! # Unsafe Low level
158//!
159//! ## Unchecked statics initiliazed at program start up
160//!
161//! The library also provides unchecked statics, whose initialization is run before main start. Those statics
162//! does not imply any memory overhead neither execution time overhead. This is the responsability of the coder
163//! to be sure not to access those static before they are initialized.
164//!
165//! ```rust
166//! use static_init::dynamic;
167//!
168//! #[dynamic(10)]
169//! static A: Vec<i32> = vec![1,2,3];
170//!
171//! #[dynamic(0,drop)]
172//! static mut B: Vec<i32> = unsafe {A.clone()};
173//! ```
174//!
175//! Even if A is not declared mutable, the attribute macro convert it into a mutable static to ensure that every
176//! access to it is unsafe.
177//!
178//! The number indicates the priority, the larger the number, the sooner the static will be initialized.
179//!
180//! Those statics can also be droped at program exit with the `drop` attribute argument.
181//!
182//! ## Program constructor destructor
183//!
184//! It is possible to register fonction for execution before main start/ after main returns.
185//!
186//!
187//! ```rust
188//! use static_init::{constructor, destructor};
189//!
190//! #[constructor(10)]
191//! extern "C" fn run_first() {}
192//!
193//! #[constructor(0)]
194//! extern "C" fn then_run() {}
195//!
196//! #[destructor(0)]
197//! extern "C" fn pre_finish() {}
198//!
199//! #[destructor(10)]
200//! extern "C" fn finaly() {}
201//! ```
202//!
203//! # Debug support
204//!
205//! The feature `debug_order` can be activated to detect trouble with initialization order of raw
206//! statics or dead locks due to lazy initialization depending on itself.
207
208// TODO:
209// - bencher les thread locals
210// - revoir la doc
211// - voir si specializer le phase locker pour les cas non mut / mut lazy
212// - renomer new_static => from_generator
213//
214
215// Notes on rust rt
216//
217// On unixes-linux:
218// -args are initialized with .init_array(99)
219// -but also just before main to help miri
220// On other unixes
221// - args/env is set just before main start
222// => it will look like there are no arg and no env. => safe.
223//
224// On unixes
225// - sys::init() :
226// - initialize standard streams
227// - sigpip reset
228//
229// - guard actualy does noting just return expect stack size
230// - otherwise map memory and prohibit access with mprotect
231// => so this is not secure and no point in minding about that
232// - then sys::stack_overflow install a signal handler to handle
233// signal => once again not secure no point in minding about that
234// - then set thread_info => so use of thread::current will panic
235// in constructor or destructor
236//
237// At exit args/env may be cleaned, also stack_guard
238// stdio will not be buffered
239//
240// windows init maybe called at .CRT$XCU
241//
242//
243//
244// On windows there are no sys::init(), it does nothing
245// no guard,
246// args always accessbile
247// the same as unix with thread_info
248//
249#![cfg_attr(
250 all(
251 not(any(feature = "parking_lot_core", debug_mode)),
252 any(target_os = "linux", target_os = "android")
253 ),
254 no_std
255)]
256#![cfg_attr(all(elf, feature = "thread_local"), feature(linkage))]
257#![cfg_attr(
258 feature = "thread_local",
259 feature(thread_local),
260 feature(cfg_target_thread_local)
261)]
262#![cfg_attr(docsrs, feature(doc_cfg))]
263
264/// # Details and implementation documentation.
265///
266/// ## Mac
267/// - [MACH_O specification](https://www.cnblogs.com/sunkang/archive/2011/05/24/2055635.html)
268/// - GCC source code gcc/config/darwin.c indicates that priorities are not supported.
269///
270/// Initialization functions pointers are placed in section "__DATA,__mod_init_func" and
271/// "__DATA,__mod_term_func"
272///
273/// std::env is not initialized in any constructor.
274///
275/// ## ELF plateforms:
276/// - `info ld`
277/// - linker script: `ld --verbose`
278/// - [ELF specification](https://docs.oracle.com/cd/E23824_01/html/819-0690/chapter7-1.html#scrolltoc)
279///
280/// The runtime will run fonctions pointers of section ".init_array" at startup and function
281/// pointers in ".fini_array" at program exit. The linker place in the target object file
282/// sectio .init_array all sections from the source objects whose name is of the form
283/// .init_array.NNNNN in lexicographical order then the .init_array sections of those same source
284/// objects. It does equivalently with .fini_array and .fini_array.NNNN sections.
285///
286/// Usage can be seen in gcc source gcc/config/pru.c
287///
288/// Resources of libstdc++ are initialized with priority 65535-100 (see gcc source libstdc++-v3/c++17/default_resource.h)
289/// The rust standard library function that capture the environment and executable arguments is
290/// executed at priority 65535-99 on gnu platform variants. On other elf plateform they are not accessbile in any constructors. Nevertheless
291/// one can read into /proc/self directory to retrieve the command line.
292/// Some callbacks constructors and destructors with priority 65535 are
293/// registered by rust/rtlibrary.
294/// Static C++ objects are usually initialized with no priority (TBC). lib-c resources are
295/// initialized by the C-runtime before any function in the init_array (whatever the priority) are executed.
296///
297/// ## Windows
298///
299/// std::env is initialized before any constructors.
300///
301/// - [this blog post](https://www.cnblogs.com/sunkang/archive/2011/05/24/2055635.html)
302///
303/// At start up, any functions pointer between sections ".CRT$XIA" and ".CRT$XIZ"
304/// and then any functions between ".CRT$XCA" and ".CRT$XCZ". It happens that the C library
305/// initialization functions pointer are placed in ".CRT$XIU" and C++ statics functions initialization
306/// pointers are placed in ".CRT$XCU". At program finish the pointers between sections
307/// ".CRT$XPA" and ".CRT$XPZ" are run first then those between ".CRT$XTA" and ".CRT$XTZ".
308///
309/// Some reverse engineering was necessary to find out a way to implement
310/// constructor/destructor priority.
311///
312/// Contrarily to what is reported in this blog post, msvc linker
313/// only performs a lexicographicall ordering of section whose name
314/// is of the form "\<prefix\>$\<suffix\>" and have the same \<prefix\>.
315/// For example "RUST$01" and "RUST$02" will be ordered but those two
316/// sections will not be ordered with "RHUM" section.
317///
318/// Moreover, it seems that section name of the form \<prefix\>$\<suffix\> are
319/// not limited to 8 characters.
320///
321/// So static initialization function pointers are placed in section ".CRT$XCU" and
322/// those with a priority `p` in `format!(".CRT$XCTZ{:05}",65535-p)`. Destructors without priority
323/// are placed in ".CRT$XPU" and those with a priority in `format!(".CRT$XPTZ{:05}",65535-p)`.
324///
325///
326mod details {}
327
328use core::cell::Cell;
329
330/// A trait for objects that are intinded to transition between phasis.
331///
332/// A type that implement [`Sequential`] ensured that its `data` will traverse a sequence of
333/// [phases](Phase). The phase does not participates to the value of the type. The phase describes
334/// the *lifetime* of the object: initialized, droped,...
335///
336/// # Safety
337///
338/// The trait is unsafe because the implementor should ensure that the reference returned by
339/// [`sequentializer`](Self::sequentializer) and the reference returned by [`data`](Self::data) refer to two subobject of a same object.
340///
341unsafe trait Sequential {
342 type Data;
343 type Sequentializer;
344 fn sequentializer(this: &Self) -> &Self::Sequentializer;
345 fn data(this: &Self) -> &Self::Data;
346 fn sequentializer_data_mut(this: &mut Self) -> (&mut Self::Sequentializer, &mut Self::Data);
347}
348
349/// Trait for objects that know in which [phase](Phase) they are.
350pub trait Phased {
351 /// return the current phase
352 fn phase(this: &Self) -> Phase;
353}
354
355/// A type that implement Sequentializer aims at [phase](Phase) sequencement.
356///
357/// The method [`Sequential::sequentializer`] should return an object that implement
358/// this trait.
359///
360/// # Safety
361///
362/// The trait is unsafe because the lock should ensure the following lock semantic:
363/// - if the implementor also implement Sync, the read/write lock semantic should be synchronized
364/// and if no lock is taken, the call to lock should synchronize with the end of the phase
365/// transition that put the target object in its current phase.
366/// - if the implementor is not Sync then the lock should panic if any attempt is made
367/// to take another lock while a write lock is alive or to take a write lock while there
368/// is already a read_lock.(the lock should behave as a RefCell).
369unsafe trait Sequentializer<'a, T: Sequential + 'a>: Sized + Phased {
370 type ReadGuard;
371 type WriteGuard;
372 /// Lock the phases of an object in order to ensure atomic phase transition.
373 ///
374 /// The nature of the lock depend on the phase in which is the object, and is determined
375 /// by the `lock_nature` argument.
376 fn lock(
377 target: &'a T,
378 lock_nature: impl Fn(Phase) -> LockNature,
379 hint: Phase,
380 ) -> LockResult<Self::ReadGuard, Self::WriteGuard>;
381 /// Try to lock the phases of an object in order to ensure atomic phase transition.
382 ///
383 /// The nature of the lock depend on the phase in which is the object, and is determined
384 /// by the `lock_nature` argument. If it is impossible to lock because of another lock
385 /// the result is None.
386 fn try_lock(
387 target: &'a T,
388 lock_nature: impl Fn(Phase) -> LockNature,
389 hint: Phase,
390 ) -> Option<LockResult<Self::ReadGuard, Self::WriteGuard>>;
391
392 /// Lock the phases of an object in order to ensure atomic phase transition.
393 fn lock_mut(target: &'a mut T) -> Self::WriteGuard;
394}
395
396/// A [`LazySequentializer`] sequentialize the [phases](Phase) of a target object to ensure
397/// atomic initialization and finalization.
398///
399/// # Safety
400///
401/// The trait is unsafe because the implementor must ensure that:
402///
403/// - if the implementor also implement Sync, the read/write lock semantic should be synchronized
404/// and if no lock is taken, the call to lock should synchronize with the end of the phase
405/// transition that put the target object in its current phase.
406/// - if the implementor is not Sync then the lock should panic if any attempt is made
407/// to take another lock while a write lock is alive or to take a write lock while there
408/// is already a read_lock.(the lock should behave as a RefCell).
409unsafe trait LazySequentializer<'a, T: Sequential + 'a>: Sequentializer<'a, T> {
410 const INITIALIZED_HINT: Phase;
411 /// if `shall_init` return true for the target [`Sequential`] object, it initialize
412 /// the data of the target object using `init`
413 ///
414 /// The implementor may also proceed to registration of the finalizing method (drop)
415 /// in order to drop the object on the occurence of singular event (thread exit, or program
416 /// exit). If this registration fails and if `init_on_reg_failure` is `true` then the object
417 /// will be initialized, otherwise it will not.
418 fn init(
419 target: &'a T,
420 shall_init: impl Fn(Phase) -> bool,
421 init: impl FnOnce(&'a <T as Sequential>::Data),
422 ) -> Phase;
423 //fn init_unique(
424 // target: &'a mut T,
425 // shall_init: impl Fn(Phase) -> bool,
426 // init: impl FnOnce(&'a <T as Sequential>::Data),
427 //) -> Phase;
428 /// Similar to [init](Self::init) but returns a lock that prevents the phase of the object
429 /// to change (Read Lock). The returned lock may be shared.
430 fn init_then_read_guard(
431 target: &'a T,
432 shall_init: impl Fn(Phase) -> bool,
433 init: impl FnOnce(&'a <T as Sequential>::Data),
434 ) -> Self::ReadGuard;
435 /// Similar to [init](Self::init) but returns a lock that prevents the phase of the object
436 /// to change accepts through the returned lock guard (Write Lock). The lock is exculisive.
437 fn init_then_write_guard(
438 target: &'a T,
439 shall_init: impl Fn(Phase) -> bool,
440 init: impl FnOnce(&'a <T as Sequential>::Data),
441 ) -> Self::WriteGuard;
442 /// Similar to [init_then_read_guard](Self::init_then_read_guard) but will return None
443 /// if any lock is taken on the lazy or if it is beiing initialized
444 fn try_init_then_read_guard(
445 target: &'a T,
446 shall_init: impl Fn(Phase) -> bool,
447 init: impl FnOnce(&'a <T as Sequential>::Data),
448 ) -> Option<Self::ReadGuard>;
449 /// Similar to [init_then_write_guard](Self::init_then_write_guard) but will return None
450 /// if any lock is taken on the lazy or if it is beiing initialized
451 fn try_init_then_write_guard(
452 target: &'a T,
453 shall_init: impl Fn(Phase) -> bool,
454 init: impl FnOnce(&'a <T as Sequential>::Data),
455 ) -> Option<Self::WriteGuard>;
456}
457
458trait UniqueLazySequentializer<T: Sequential> {
459 /// if `shall_init` return true for the target [`Sequential`] object, it initialize
460 /// the data of the target object using `init`
461 ///
462 /// The implementor may also proceed to registration of the finalizing method (drop)
463 /// in order to drop the object on the occurence of singular event (thread exit, or program
464 /// exit). If this registration fails and if `init_on_reg_failure` is `true` then the object
465 /// will be initialized, otherwise it will not.
466 fn init_unique(
467 target: &mut T,
468 shall_init: impl Fn(Phase) -> bool,
469 init: impl FnOnce(&mut <T as Sequential>::Data),
470 ) -> Phase;
471}
472
473/// A [FinalizableLazySequentializer] sequentialize the [phase](Phase) of an object to
474/// ensure atomic initialization and finalization.
475///
476/// A sequentializer that implement this trait is not able to register the finalization
477/// for latter call on program exit or thread exit.
478///
479/// # Safety
480///
481/// The trait is unsafe because the implementor must ensure that:
482///
483/// - either the implementor is Sync and the initialization is performed atomically
484/// - or the implementor is not Sync and any attempt to perform an initialization while
485/// an initialization is running will cause a panic.
486unsafe trait FinalizableLazySequentializer<'a, T: 'a + Sequential>:
487 Sequentializer<'a, T>
488{
489 /// if `shall_init` return true for the target [`Sequential`] object, it initialize
490 /// the data of the target object using `init`
491 ///
492 /// Before initialization of the object, the fonction `reg` is call with the target
493 /// object as argument. This function should proceed to registration of the
494 /// [finalize_callback](Self::finalize_callback) for latter call at program exit or
495 /// thread exit.
496 fn init(
497 target: &'a T,
498 shall_init: impl Fn(Phase) -> bool,
499 init: impl FnOnce(&'a <T as Sequential>::Data),
500 reg: impl FnOnce(&'a T) -> bool,
501 ) -> Phase;
502 /// Similar to [init](Self::init) but returns a lock that prevents the phase of the object
503 /// to change (Read Lock). The returned lock may be shared.
504 fn init_then_read_guard(
505 target: &'a T,
506 shall_init: impl Fn(Phase) -> bool,
507 init: impl FnOnce(&'a <T as Sequential>::Data),
508 reg: impl FnOnce(&'a T) -> bool,
509 ) -> Self::ReadGuard;
510 /// Similar to [init](Self::init) but returns a lock that prevents the phase of the object
511 /// to change accepts through the returned lock guard (Write Lock). The lock is exculisive.
512 fn init_then_write_guard(
513 target: &'a T,
514 shall_init: impl Fn(Phase) -> bool,
515 init: impl FnOnce(&'a <T as Sequential>::Data),
516 reg: impl FnOnce(&'a T) -> bool,
517 ) -> Self::WriteGuard;
518 /// Similar to [init_then_read_guard](Self::init_then_read_guard) but will return None
519 /// if any lock is taken on the lazy or if it is beiing initialized
520 fn try_init_then_read_guard(
521 target: &'a T,
522 shall_init: impl Fn(Phase) -> bool,
523 init: impl FnOnce(&'a <T as Sequential>::Data),
524 reg: impl FnOnce(&'a T) -> bool,
525 ) -> Option<Self::ReadGuard>;
526 /// Similar to [init_then_write_guard](Self::init_then_write_guard) but will return None
527 /// if any lock is taken on the lazy or if it is beiing initialized
528 fn try_init_then_write_guard(
529 target: &'a T,
530 shall_init: impl Fn(Phase) -> bool,
531 init: impl FnOnce(&'a <T as Sequential>::Data),
532 reg: impl FnOnce(&'a T) -> bool,
533 ) -> Option<Self::WriteGuard>;
534 /// A callback that is intened to be stored by the `reg` argument of `init` method.
535 fn finalize_callback(s: &'a T, f: impl FnOnce(&'a T::Data));
536}
537
538pub trait GeneratorTolerance {
539 const INIT_FAILURE: bool;
540 const FINAL_REGISTRATION_FAILURE: bool;
541}
542
543/// Generates a value of type `T`
544pub trait Generator<T>: GeneratorTolerance {
545 fn generate(&self) -> T;
546}
547
548impl<U, T: Fn() -> U> Generator<U> for T {
549 fn generate(&self) -> U {
550 self()
551 }
552}
553
554impl<U, T: Fn() -> U> GeneratorTolerance for T {
555 const INIT_FAILURE: bool = true;
556 const FINAL_REGISTRATION_FAILURE: bool = false;
557}
558
559impl<U, T: FnOnce() -> U> Generator<U> for Cell<Option<T>> {
560 fn generate(&self) -> U {
561 match self.take() {
562 Some(v) => v(),
563 None => panic!("Cannot call this generator twice"),
564 }
565 }
566}
567
568impl<U, T: FnOnce() -> U> GeneratorTolerance for Cell<Option<T>> {
569 const INIT_FAILURE: bool = false;
570 const FINAL_REGISTRATION_FAILURE: bool = false;
571}
572
573/// Trait that must be implemented by #[dynamic(finalize)] statics.
574pub trait Finaly {
575 /// This method is called when program or thread exit and the lazy
576 /// was initialized
577 fn finaly(&self);
578}
579
580/// Trait that must be implemented by #[dynamic(prime)] mutable statics.
581pub trait Uninit {
582 /// This method is called when program or thread exit and the lazy
583 /// was initialized
584 ///
585 /// It should leave the target objet in a valid state as it could
586 /// be accessed throud `primed_<read|write>` method familly.
587 fn uninit(&mut self);
588}
589
590#[cfg_attr(docsrs, doc(cfg(debug_mode)))]
591#[cfg(debug_mode)]
592#[doc(hidden)]
593#[derive(Debug)]
594/// Used to passe errors
595pub struct CyclicPanic;
596
597/// phases and bits to manipulate them;
598pub mod phase {
599
600 use core::fmt::{self, Display, Formatter};
601
602 use bitflags::bitflags;
603 #[cfg(not(feature = "spin_loop"))]
604 pub(crate) const WRITE_WAITER_BIT: u32 = 0b1000_0000_0000_0000_0000_0000_0000_0000;
605 #[cfg(not(feature = "spin_loop"))]
606 pub(crate) const READ_WAITER_BIT: u32 = 0b0100_0000_0000_0000_0000_0000_0000_0000;
607 pub(crate) const LOCKED_BIT: u32 = 0b0010_0000_0000_0000_0000_0000_0000_0000;
608 pub(crate) const READER_BITS: u32 = 0b0000_1111_1111_1111_1111_1111_0000_0000;
609 pub(crate) const READER_OVERF: u32 = 0b0001_0000_0000_0000_0000_0000_0000_0000;
610 pub(crate) const READER_UNITY: u32 = 0b0000_0000_0000_0000_0000_0001_0000_0000;
611 #[cfg(not(feature = "spin_loop"))]
612 pub(crate) const MAX_WAKED_READERS: usize = (READER_OVERF / READER_UNITY) as usize;
613 // Although some flags exclude others, Phase is represented by
614 // a bitflag to allow xor bit tricks that eases atomic phase
615 // changes in the implementation of SyncPhaseLocker.
616 bitflags! {
617 /// The lifetime phase of an object, this indicate weither the object was initialized
618 /// finalized (droped),...
619 ///
620 /// The registration phase is a phase that precede the initialization phase and is meant
621 /// to register a callback that will proceed to the finalization (drop) of the object at
622 /// program exit or thread exit. Depending on the plateform this registration may fail.
623 pub struct Phase: u32 {
624 const INITIALIZED = 0b0000_0000_0000_0000_0000_0000_0000_0001;
625 const INITIALIZATION_PANICKED = 0b0000_0000_0000_0000_0000_0000_0000_0010;
626 const INITIALIZATION_SKIPED = 0b0000_0000_0000_0000_0000_0000_0000_0100;
627
628
629 const REGISTERED = 0b0000_0000_0000_0000_0000_0000_0000_1000;
630 const REGISTRATION_PANICKED = 0b0000_0000_0000_0000_0000_0000_0001_0000;
631 const REGISTRATION_REFUSED = 0b0000_0000_0000_0000_0000_0000_0010_0000;
632
633 const FINALIZED = 0b0000_0000_0000_0000_0000_0000_0100_0000;
634 const FINALIZATION_PANICKED = 0b0000_0000_0000_0000_0000_0000_1000_0000;
635
636 const INITIALIZED_AND_REGISTERED = Self::INITIALIZED.bits | Self::REGISTERED.bits;
637 }
638 }
639
640 impl Display for Phase {
641 fn fmt(&self, ft: &mut Formatter<'_>) -> fmt::Result {
642 if self.is_empty() {
643 write!(ft, "Phase (not initialized)")?;
644 } else {
645 write!(ft, "Phase (")?;
646 let mut is_first = true;
647 let mut write = |s| {
648 if is_first {
649 is_first = false;
650 ft.write_str(s)
651 } else {
652 write!(ft, " | {}", s)
653 }
654 };
655 if self.intersects(Phase::INITIALIZED) {
656 write("Initialized")?;
657 }
658 if self.intersects(Phase::INITIALIZATION_PANICKED) {
659 write("Initialization panicked")?;
660 }
661 if self.intersects(Phase::INITIALIZATION_SKIPED) {
662 write("Initialization skiped")?;
663 }
664 if self.intersects(Phase::REGISTERED) {
665 write("Registered")?;
666 }
667 if self.intersects(Phase::REGISTRATION_PANICKED) {
668 write("Registration panicked")?;
669 }
670 if self.intersects(Phase::REGISTRATION_REFUSED) {
671 write("Registration refused")?;
672 }
673 if self.intersects(Phase::FINALIZED) {
674 write("Finalized")?;
675 }
676 if self.intersects(Phase::FINALIZATION_PANICKED) {
677 write("Finalization panicked")?;
678 }
679 write!(ft, ")")?
680 }
681 Ok(())
682 }
683 }
684}
685#[doc(inline)]
686pub use phase::Phase;
687
688/// Attribute for functions run at program initialization (before main).
689///
690/// ```
691/// # use static_init::constructor;
692/// #[constructor]
693/// extern "C" fn initer () {
694/// // run before main start
695/// }
696/// ```
697///
698/// The execution order of constructors is unspecified. Nevertheless on ELF plateform (linux, any unixes but mac) and
699/// windows plateform a priority can be specified using the syntax `constructor(<num>)` where
700/// `<num>` is a number included in the range [0 ; 2<sup>16</sup>-1].
701///
702/// Constructors with a priority of 65535 are run first (in unspecified order), then constructors
703/// with priority 65534 are run ... then constructors
704/// with priority number 0
705///
706/// An abscence of priority is equivalent to a priority of 0.
707///
708/// ```
709/// # use static_init::constructor;
710/// #[constructor(0)]
711/// extern "C" fn first () {
712/// // run before main start
713/// }
714///
715/// #[constructor(1)]
716/// extern "C" fn then () {
717/// // run before main start
718/// }
719/// ```
720///
721///
722/// # Safety
723///
724/// Any access to *raw statics* with an equal or lower
725/// initialization priority will cause undefined behavior. (NB: usual static data and *lazy
726/// statics* are always safe to access.
727///
728/// # About rust standard library runtime
729///
730/// During program constructions some functionnality of the standard library will be missing on
731/// unixes:
732///
733/// - program argument as returned by `std::env::args` and environment variables as returned by
734/// `std::env::vars` will be emty on unixes other than linux-gnu. On linux/gnu they will be
735/// empty above priority
736/// 65436.
737///
738/// - call to `std::thread::current` will panick.
739///
740/// - standard streams may not be initialized.
741///
742/// - Some signal handler installed by the standard library may not be installed
743///
744/// On windows all the standard library should appear initialized.
745///
746/// # Constructor signature
747///
748/// Constructor function should have type `extern "C" fn() -> ()`.
749///
750/// On plateform where the program is linked
751/// with the gnu variant of libc (which covers all gnu variant platforms) constructor functions
752/// can take (or not) `argc: i32, argv: **const u8, env: **const u8` as arguments.
753/// `argc` is the size of the argv
754/// sequence, `argv` and `env` both refer to null terminated contiguous sequence of pointer
755/// to c-string (c-strings are null terminated sequence of u8).
756///
757/// Also after the null terminating `*const * const u8` of the environment variable list is found
758/// the auxilary vector that are information provided by the kernel. It is possible to retrieve
759/// from that vector information about the process and location of syscalls implemented in the
760/// vdso.
761/// ```
762/// # use static_init::constructor;
763/// # #[cfg(all(linux, target_env = "gnu"))]
764/// # mod m {
765/// #[constructor]
766/// extern "C" fn get_args_env(argc: i32, mut argv: *const *const u8, env: *const *const u8) {}
767/// # }
768pub use static_init_macro::constructor;
769
770/// Attribute for functions run at program termination (after main)
771///
772/// ```
773/// # use static_init::destructor;
774/// #[destructor]
775/// extern "C" fn droper () {
776/// // run after main return
777/// }
778/// ```
779///
780/// The execution order of destructors is unspecified. Nevertheless on ELF plateform (linux,any unixes but mac) and
781/// windows plateform a priority can be specified using the syntax `destructor(<num>)` where
782/// `<num>` is a number included in the range [0 ; 2<sup>16</sup>-1].
783///
784/// Destructors with priority 0 are run first (in unspecified order),
785/// then destructors with priority number 1,... finaly destructors with priority 65535 are run.
786///
787/// An abscence of priority is equivalent to a priority of 0.
788///
789/// ```
790/// # use static_init::destructor;
791/// #[destructor(1)]
792/// extern "C" fn first () {
793/// // run after main return
794/// }
795///
796/// #[destructor(0)]
797/// extern "C" fn then () {
798/// // run after main return
799/// }
800/// ```
801/// # About rust runtime
802///
803/// After main exit the standard streams are not buffered.
804///
805/// # Destructor signature
806///
807/// Destructor function should have type `unsafe extern "C" fn() -> ()`.
808pub use static_init_macro::destructor;
809
810/// Declare statics that can be initialized with non const fonctions and safe mutable statics
811///
812/// Statics on which this attribute is applied will be be initialized at run time (optionaly see
813/// bellow), before main start. This allow statics initialization with non const expressions.
814///
815/// There are two main categories of statics:
816///
817/// - *lazy statics* which are statics that are always safe to use. They may be initialized on
818/// first acces or before main is called;
819///
820/// - *locked lazy statics* which are the mutable version of lazy statics.
821///
822/// - *raw statics*, which are initialized at program start-up and absolutely unchecked. Any
823/// access to them requires `unsafe` block;
824///
825/// # Lazy statics
826///
827/// Those statics are initialized on first access. An optimization implemented by *lesser lazy statics*
828/// initialize the static before main is called on all tier1 plateform but mach.
829///
830/// The declared object is encapsulated in a type that implement `Deref`.
831///
832/// Other access functionnality and state information are accessible through the `LazyAccess`
833/// trait.
834///
835/// Those lazy can be used with regular statics and thread locals.
836///
837/// ```
838/// # #![cfg_attr(feature = "thread_local",feature(thread_local))]
839/// # use static_init::dynamic;
840///
841/// #[dynamic]
842/// static A :Vec<i32> = vec![1,2];
843///
844/// # #[cfg(feature = "thread_local")]
845/// # mod m {
846/// # use static_init::dynamic;
847/// #[dynamic]
848/// #[thread_local]
849/// static TL :Vec<i32> = vec![1,2];
850/// # }
851///
852/// ```
853///
854/// ## Lesser Lazy Statics
855///
856/// They are declared with the `#[dynamic]` attribute (or equivalently `#[dynamic(lesser_lazy)]`.
857/// They are either initialized on first access or before main is called. They provide
858/// unsurpassable access performance: their access time is comparable to const initialized statics
859/// but they support non const initialization:
860///
861/// ```
862/// # use static_init::dynamic;
863/// #[dynamic]
864/// static V :Vec<i32> = vec![1,2];
865///
866/// assert_eq!(V.len(), 2);
867/// ```
868///
869/// ## Realy lazy Statics
870///
871/// When initialization on first access is a requirement, the static shall be attributed with
872/// `#[dynamic(lazy)]`
873///
874/// ```
875/// # use static_init::dynamic;
876/// #[dynamic(lazy)]
877/// static V :Vec<i32> = vec![1,2];
878///
879/// assert_eq!(*V, vec![1,2]);
880/// ```
881///
882/// ## Finalized statics
883///
884/// The attribute argument `finalize` can be used if the declared type of
885/// the static implement `Finaly` trait. The finalize method is called at
886/// program exit or at thread exit for thread locals. (NB: mutable lazy also
887/// support drop, see below)
888///
889/// ```
890/// # #![cfg_attr(feature = "thread_local", feature(thread_local))]
891/// # use static_init::{Finaly,dynamic};
892///
893/// # fn main(){}
894///
895/// struct A(i32);
896///
897/// impl Finaly for A {
898/// fn finaly(&self){/* some clean up code */ }
899/// }
900///
901/// #[dynamic(finalize)] //finalize execute at program exit
902/// static X :A = A(33);
903///
904/// # #[cfg(feature="thread_local")]
905/// # mod m{
906/// # use static_init::{dynamic};
907/// # use super::A;
908/// #[dynamic(lazy,finalize)] //finalize executed at thread exit
909/// #[thread_local]
910/// static Y :A = A(33);
911/// # }
912/// ```
913///
914/// ## Tolerances
915///
916/// ### Initialization fault tolerance
917///
918/// By default if the initialization of a lazy panic, initialization will be attempted
919/// once again on the next access attempt. If this is not desired the lazy should be declared
920/// with attribute argument `try_init_once`, in which case, the lazy will be poisonned if
921/// initialization panics.
922///
923/// ```
924/// # use static_init::{dynamic};
925/// #[dynamic(try_init_once)]
926/// static X :Vec<i32> = vec![1,2];
927///
928/// #[dynamic(lazy,try_init_once)] //attribute argument can be combined
929/// static Y :Vec<i32> = vec![1,2];
930/// ```
931///
932/// ### Registration for finalization tolerance
933///
934/// By default lazy that intended to be finalized (because they use the `finalize` or `drop`
935/// attribute argument) refuse to initialize if registration of the finalization or drop at
936/// program exit or thread exit fails.
937///
938/// If this is not desired, the `tolerate_leak` attribute argument can be used.
939///
940/// ```
941/// # use static_init::{Finaly,dynamic};
942/// struct A(i32);
943///
944/// impl Finaly for A {
945/// fn finaly(&self){/* some clean up code */ }
946/// }
947///
948/// #[dynamic(finalize,tolerate_leak)]
949/// static X :A = A(21);
950/// //the initialization may succeed even if it is impossible to register
951/// //the call to finaly at program exit
952/// ```
953///
954/// # Locked lazy statics
955///
956/// Those statics are mutable statics, initialized on the first acces and protected behind
957/// a kind of read/write lock specialy designed for them.
958///
959/// The are declared as *lazy statics* but with the `mut` keyword. The macro will actualy remove
960/// the `mut` keyword and use a r/w locked wrapper type:
961///
962/// ```
963/// # use static_init::{Finaly,dynamic};
964///
965/// #[dynamic]
966/// static mut V: Vec<i32> = vec![1,2];
967///
968/// V.write().push(3);
969///
970/// assert_eq!(*V.read(), vec![1,2,3]);
971/// ```
972///
973/// Those statics provides different methods to access the target object. See the documentation of
974/// [LockedLazy] for exemple. All *locked lazy* types provide the same methods.
975///
976/// Locked lazy statics support all attribute arguments supported by *lazy statics*: `finalize`,
977/// `try_init_once`, `tolerate_leak`. Moreover they support two other arguments:
978///
979/// - `drop` in which case the static will be dropped at program exit:
980/// - `prime` which is a static that support access before it is actualy initialized
981/// and after it is droped;
982///
983/// ## Dropped locked lazy statics
984///
985/// Locked lazy statics can be droped at program exit or thread exit when declared with
986/// the `drop` attribute argument
987///
988/// ```
989/// # #![cfg_attr(feature = "thread_local", feature(thread_local))]
990/// # use static_init::{Finaly,dynamic};
991///
992/// # fn main(){}
993///
994/// # #[cfg(feature="thread_local")]
995/// # mod m{
996/// # use static_init::{dynamic};
997///
998/// #[dynamic(drop)]
999/// #[thread_local]
1000/// static mut V: Vec<i32> = vec![1,2];
1001/// # }
1002///
1003/// #[dynamic(lazy,drop,tolerate_leak)]
1004/// static mut V2: Vec<i32> = vec![1,2];
1005/// ```
1006///
1007/// ## Primed locked lazy statics
1008///
1009/// Those statics model the case where an object should have a
1010/// standard behavior and a fallback behavior after ressources
1011/// are release or not yet acquired.
1012///
1013/// Those statics are initialized in two steps:
1014///
1015/// - a const initialization that happens at compile time
1016///
1017/// - a dynamic intialization that happens the first time they are accessed if
1018/// if is declared with `lazy` attribute argument or just before.
1019///
1020/// More over they are conceptualy uninitialized if the type of the statics
1021/// implement the `Uninit` trait and is declared with the `drop` attribute argument.
1022///
1023/// They must be initialized with a match expression as exemplified bellow:
1024///
1025/// ```
1026/// use static_init::{dynamic, Uninit};
1027///
1028/// #[dynamic(prime)]
1029/// static mut O: Option<Vec<i32>> = match INIT {
1030/// PRIME => None,
1031/// DYN => Some(vec![1,2]),
1032/// };
1033///
1034/// #[dynamic(lazy,prime)]
1035/// static mut OLAZY: Option<Vec<i32>> = match INIT {
1036/// PRIME => None,
1037/// DYN => Some(vec![1,2]),
1038/// };
1039///
1040///
1041/// struct A(Option<Vec<i32>>);
1042///
1043/// impl Uninit for A {
1044/// fn uninit(&mut self) {
1045/// self.0.take();
1046/// }
1047/// }
1048///
1049/// #[dynamic(prime,finalize)]//finalize/drop actualy means uninit for primed lazy
1050/// static mut P: A = match INIT {
1051/// PRIME => A(None),
1052/// DYN => A(Some(vec![1,2])),
1053/// };
1054///
1055/// match P.primed_read() {
1056/// Ok(read_lock) => (),/*a read lock that refers to the initialized statics */
1057/// Err(read_lock) => (),/* post finalization access, uninit has already been called*/
1058/// }
1059///
1060/// match P.primed_write() {
1061/// Ok(write_lock) => (),/*a write lock that refers to the initialized statics */
1062/// Err(read_lock) => (),/* post finalization access, uninit has already been called*/
1063/// }
1064/// ```
1065///
1066/// # Raw statics
1067///
1068/// Those statics will be initialized at program startup, without ordering, accept between those
1069/// that have different priorities on plateform that support priorities. Those statics are
1070/// supported on unixes and windows with priorities and mac without priorities.
1071///
1072/// ## Safety
1073///
1074/// During initialization, any access to other
1075/// "dynamic" statics initialized with a lower priority will cause undefined behavior. Similarly,
1076/// during drop any access to a "dynamic" static dropped with a lower priority will cause undefined
1077/// behavior. For this reason those statics are always turn into mutable statics to ensure that all
1078/// access attempt is unsafe.
1079///
1080/// Those statics are interesting only to get the optimalest performance at the price of unsafety.
1081///
1082/// ```
1083/// # use static_init::dynamic;
1084/// #[dynamic(0)]
1085/// static V :Vec<i32> = vec![1,2];
1086///
1087/// assert!(unsafe{*V == vec![1,2]})
1088/// ```
1089///
1090/// ## Execution Order
1091///
1092/// The execution order of raw static initializations is unspecified. Nevertheless on ELF plateform (linux,any unixes but mac) and
1093/// windows plateform a priority can be specified using the syntax `dynamic(<num>)` where
1094/// `<num>` is a number included in the range [0 ; 2<sup>16</sup>-1].
1095///
1096/// Statics with priority number 65535 are initialized first (in unspecified order), then statics
1097/// with priority number 65534 are initialized ... then statics
1098/// with priority number 0.
1099///
1100/// ```
1101/// # use static_init::dynamic;
1102/// //V1 must be initialized first
1103/// //because V2 uses the value of V1.
1104///
1105/// #[dynamic(20)]
1106/// static mut V1 :Vec<i32> = vec![1,2];
1107///
1108/// #[dynamic(10)]
1109/// static V2 :Vec<i32> = unsafe{V1.push(3); V1.clone()};
1110/// ```
1111///
1112/// ## Drop
1113///
1114/// Those statics can use the `drop` attribute argument. In this case
1115/// the static will be droped at program exit
1116///
1117/// ```
1118/// # use static_init::dynamic;
1119/// #[dynamic(0, drop)]
1120/// static mut V1 :Vec<i32> = vec![1,2];
1121/// ```
1122///
1123/// The drop priority can be specified with the `drop=<priority>` syntax. If no priority
1124/// is given, the drop priority will equal the one of the initialization priority.
1125///
1126/// ```
1127/// # use static_init::dynamic;
1128///
1129/// #[dynamic(10, drop)] //equivalent to #[dynamic(10,drop=10)]
1130/// //or longer #[dynamic(init=10,drop=10)]
1131/// static mut V1 :Vec<i32> = vec![1,2];
1132///
1133/// #[dynamic(42, drop=33)]
1134/// static mut V2 :Vec<i32> = vec![1,2];
1135/// ```
1136///
1137/// The drop priorities are sequenced in the reverse order of initialization priority. The smaller
1138/// is the priority the sooner is droped the static.
1139///
1140/// Finaly the `drop_only=<priority>` is equivalent to `#[dynamic(0,drop=<priority>)]` except that the
1141/// static will be const initialized.
1142///
1143/// ```
1144/// # use static_init::dynamic;
1145/// struct A;
1146/// impl Drop for A {
1147/// fn drop(&mut self) {}
1148/// }
1149///
1150/// #[dynamic(drop_only=33)]
1151/// static V2: A = A;
1152/// ```
1153pub use static_init_macro::dynamic;
1154
1155/// Provides PhaseLockers, that are phase tagged *adaptative* read-write lock types: during the lock loop, the nature of the lock that
1156/// is attempted to be taken variates depending on the phase.
1157///
1158/// The major difference with a RwLock is that decision to read lock, to write lock or not to lock
1159/// is taken within the lock loop: on each attempt to take the lock,
1160/// the PhaseLocker may change its locking strategy or abandon any further attempt to take the lock.
1161mod phase_locker;
1162use phase_locker::{LockNature, LockResult};
1163
1164/// Provides two lazy sequentializers, one that is Sync, and the other that is not Sync, that are
1165/// able to sequentialize the target object initialization but cannot register its finalization
1166/// callback.
1167mod lazy_sequentializer;
1168
1169#[cfg(any(elf, mach_o, coff))]
1170/// Provides two lazy sequentializers, one that will finalize the target object at program exit and
1171/// the other at thread exit.
1172mod exit_sequentializer;
1173
1174/// Provides policy types for implementation of various lazily initialized types.
1175mod generic_lazy;
1176
1177#[doc(inline)]
1178pub use generic_lazy::AccessError;
1179
1180/// Provides various implementation of lazily initialized types
1181pub mod lazy;
1182#[doc(inline)]
1183pub use lazy::{Lazy, LazyAccess, LockedLazy};
1184#[doc(inline)]
1185pub use lazy::{UnSyncLazy, UnSyncLockedLazy};
1186
1187#[cfg(any(elf, mach_o, coff))]
1188/// Provides types for statics that are meant to run code before main start or after it exit.
1189pub mod raw_static;
1190
1191#[derive(Debug)]
1192#[doc(hidden)]
1193pub enum InitMode {
1194 Const,
1195 Lazy,
1196 LesserLazy,
1197 ProgramConstructor(u16),
1198}
1199
1200#[derive(Debug)]
1201#[doc(hidden)]
1202pub enum FinalyMode {
1203 None,
1204 Drop,
1205 Finalize,
1206 ProgramDestructor(u16),
1207}
1208
1209#[derive(Debug)]
1210#[doc(hidden)]
1211pub struct StaticInfo {
1212 pub variable_name: &'static str,
1213 pub file_name: &'static str,
1214 pub line: u32,
1215 pub column: u32,
1216 pub init_mode: InitMode,
1217 pub drop_mode: FinalyMode,
1218}
1219
1220#[cfg(all(feature = "lock_statistics", not(feature = "spin_loop")))]
1221pub use phase_locker::LockStatistics;