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=)] except that the static will be const initialized.

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;