Attribute Macro static_init::dynamic
source · #[dynamic]
Expand description
Statics initialized with non const functions.
Statics on which this attribute is applied will be be initialized at run time (optionaly see bellow), before main start. This allow statics initialization with non const expressions.
There are two variants of dynamic statics:
Dynamic lazy statics
These dynamics are supported on all plateforms and requires std support. Lazy dynamics are enabled by the default feature “lazy”.
Lazy statics are declared with the [dynamic(lazy)]
or simply [dynamic]
attribute. On unixes and windows plateforms these
statics are optimized versions of [std::lazy::SyncLazy]. After program initialization phase,
those statics are guaranteed to be initialized and access to them will be as fast as any access
to a regular static. On other plateforms, those statics are equivalent to [std::lazy::SyncLazy].
struct A(i32);
impl A {
//new is not const
fn new(v:i32) -> A {
A(v)
}
}
#[dynamic] //equivalently #[dynamic(lazy)]
static V :A = A::new(42);
Optionnaly, if the default feature “atexit” is enabled, lazy dynamic statics declared with
[dynamic(lazy,drop)]
will be dropped at program exit. Dropped lazy dynamic statics ared
dropped in the reverse order of their initialization. This feature is implemented thanks to
libc::atexit
. See also drop_reverse
attribute argument.
struct A(i32);
impl A {
//new is not const
fn new(v:i32) -> A {
A(v)
}
}
impl Drop for A {
fn drop(&mut A){
println!("{}",A.0)
}
}
// V2 is initialized before V1,
// so V1 will be dropped before V2
// The program will print:
// 33
// 42
#[dynamic(lazy,drop)]
static V1 :A = A::new(unsafe{V2.0} - 9);
#[dynamic(drop)] //implies lazy
static V2 :A = A::new(42);
Even if V1 is const, access to it must be unsafe because its state may be dropped.
Internaly the procedural macro change V1 to a mutable statics and wrap it in a type
that does not implement DerefMut
.
Thread locals
lazy statics can be declared for thread local. This feature does not require std support.
They also can be dropped with if the thread_local_drop
feature is enabled.
This last feature does require std support.
#[thread_local]
#[dynamic(lazy,drop)]
static V1 :A = A::new(unsafe{V2.0} - 9);
#[thread_local]
#[dynamic(drop)] //implies lazy
static V2 :A = A::new(42);
Dynamic statics
Those statics will be initialized at program startup, without ordering, accept between those that have different priorities on plateform that support priorities. Those statics are supported on unixes and windows with priorities and mac without priorities.
Safety
Initialization expressions must be unsafe blocks. During initialization, any access to other “dynamic” statics initialized with a lower priority will cause undefined behavior. Similarly, during drop any access to a “dynamic” static dropped with a lower priority will cause undefined behavior.
struct A(i32);
impl A {
//new is not const
fn new(v:i32) -> A {
A(v)
}
}
#[dynamic(0)]
static V :A = A::new(42);
Execution Order
The execution order of “dynamic” static initializations is unspecified. Nevertheless on ELF plateform (linux,any unixes but mac) and
windows plateform a priority can be specified using the syntax dynamic(<num>)
where
<num>
is a number included in the range [0 ; 216-1].
Statics with priority number 65535 are initialized first (in unspecified order), then statics with priority number 65534 are initialized … then statics with priority number 0.
struct A(i32);
impl A {
//new is not const
fn new(v:i32) -> A {
A(v)
}
}
//V1 must be initialized first
//because V2 uses the value of V1.
#[dynamic(10)]
static mut V1 :A = A::new(33);
#[dynamic(20)]
static V2 :A = unsafe{A::new(V1.0 + 9)};
Full syntax and dropped statics
Finaly the full syntax is for the attribute is:
"dynamic" [ "(" <dyn_opts> ")" ]
dyn_opts:
<dyn_opt>
<dyn_opt>, <dyn_opts>
dyn_opt:
"init" [ "=" <priority> ]
"drop" [ "=" <priority> ]
"lazy"
"drop_only "=" <priority>
The macro attribute dynamic
is equivalent to dynamic(lazy)
and dynamic(<num>)
to dynamic(init=<num>)
. If a priority
is given it will be dropped by program destructor. The priority has the
same semantic as for the destructor attribute: statics with priority 0 are dropped first,
… and finaly statics with priority 65535 are the last dropped.
The drop_only=<priority>
is equivalent to #[dynamic(0,drop=
If no priority is given to the drop argument, the drop function will be registered using libc::atexit
. All
dynamic statics registered this way will be dropped in the reverse order of their
initialization and before any dynamic statics marked for drop using the drop
attribute
argument.
struct A(i32);
impl A {
//new is not const
fn new(v:i32) -> A {
A(v)
}
//new is not const
const fn const_new(v:i32) -> A {
A(v)
}
}
impl Drop for A {
fn drop(&mut self) {}
}
//const initialized droped after main exit
#[dynamic(init=0, drop=0)]
static mut V1 :A = A::new_const(33);
//initialized before V1 and droped after V1
#[dynamic(20,drop=10)]
static V2 :A = A::new(10);
// not droped, V3, V4 and V5 all have initialization priority 0
#[dynamic(init=0)]
static V3 :A = A::new(10);
// not droped
#[dynamic(init)]
static V4 :A = A::new(10);
// not droped
#[dynamic(0)]
static V5 :A = A::new(10);
// not droped
#[dynamic(10)]
static V6 :A = A::new(10);
Actual type of “dynamic” statics
A thread_local lazy static that is not mutable and that will be dropped is wrapped in a mutable thread_local static
of type static_init::ThreadLocalConstLazy
. Otherwise the mutability is unchanged and the
static is wrapped in a static_init::ThreadLocalLazy
.
A lazy static that is not mutable and that will be dropped is wrapped in a mutable static
of type static_init::ConstLazy
. Otherwise the mutability is unchanged and the
static is wrapped in a static_init::Lazy
.
A mutable dynamic static declared to have type T
are wrapped in static_init::Static<T>
.
A mutable “dynamic” static declared to have type T
are wrapped in a mutable static of type static_init::ConstStatic<T>
// V has type static_init::ConstStatic<i32>
#[dynamic]
static V :i32 = 0;
// W has type static_init::Static<i32>
#[dynamic]
static W :i32 = 0;