{"id":16373157,"url":"https://github.com/bbqsrc/static_init","last_synced_at":"2026-03-20T11:30:15.016Z","repository":{"id":237444808,"uuid":"639367081","full_name":"bbqsrc/static_init","owner":"bbqsrc","description":"Fork of https://gitlab.com/okannen/static_init","archived":false,"fork":false,"pushed_at":"2023-05-11T10:25:49.000Z","size":518,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2024-12-31T21:11:58.254Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/bbqsrc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2023-05-11T10:25:04.000Z","updated_at":"2023-05-11T11:04:05.000Z","dependencies_parsed_at":"2024-05-01T23:55:21.527Z","dependency_job_id":"dac3b339-724c-4609-b0b2-e13e0e534550","html_url":"https://github.com/bbqsrc/static_init","commit_stats":null,"previous_names":["bbqsrc/static_init"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbqsrc%2Fstatic_init","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbqsrc%2Fstatic_init/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbqsrc%2Fstatic_init/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/bbqsrc%2Fstatic_init/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/bbqsrc","download_url":"https://codeload.github.com/bbqsrc/static_init/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":239933259,"owners_count":19720753,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-11T03:13:31.117Z","updated_at":"2026-03-20T11:30:14.967Z","avatar_url":"https://github.com/bbqsrc.png","language":"Rust","readme":"[![LICENSE](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE-MIT)\n[![LICENSE](https://img.shields.io/badge/license-apache-blue.svg)](LICENSE-APACHE)\n[![Documentation](https://docs.rs/static_init/badge.svg)](https://docs.rs/static_init)\n[![Crates.io Version](https://img.shields.io/crates/v/static_init.svg)](https://crates.io/crates/static_init)\n\nSafe non const initialized statics and safe mutable statics with unbeatable performance.\n\nAlso provides code execution at program start-up/exit.\n\nWhy using non const initialized statics and safe mutable statics? Because all execution depends on state that is\nmaintained during all program execution. Because it is very difficult than it looks-like\nto have an ergonomic, safe and with excellent performance solution for maintaining such state. \n\n# Feature\n\n- [x] non const initialized statics.\n- [x] statics dropped at program exit.\n- [x] safe mutable lazy statics (locked).\n- [x] every feature with `no_std` support.\n- [x] unbeatable performance, can be order of magnitude faster that any other solution.\n- [x] registration of code execution at program exit without allocation (as opposed to libc::at_exit).\n- [x] ergonomic syntax.\n- [x] sound and safe.\n- [x] on nigtly, `thread_locals` and safe mutable `thread_locals`, guaranteed to be\n    dropped at thread exit with the lowest possible overhead compared to\n    what is provided by system library thread support or the standard library!\n\n# Fastest Lazy Statics\n\nThis crate provides *lazy statics* on all platforms.\n\nOn unixes and windows *lesser lazy statics* are *lazy* during program startup phase\n(before `main` is called). Once main is called, those statics are all guaranteed to be\ninitialized and any access to them almost no incur any performance cost\n\n```\nuse static_init::{dynamic};\n\n#[dynamic] \nstatic L1: Vec\u003ci32\u003e = vec![1,2,3,4,5,6];\n\n#[dynamic(drop)] \nstatic mut L2: Vec\u003ci32\u003e = {let mut v = L1.clone(); v.push(43); v};\n```\n\nThose static initialization and access can be 10x faster than\nwhat is provided by the standard library or other crates.\n\n# Safe Mutable Statics\n\nJust add the `mut` keyword to have mutable locked statics.\n\n```\nuse static_init::{dynamic};\n\n#[dynamic] \nstatic mut L1: Vec\u003ci32\u003e = vec![1,2,3,4,5,6];\n\n//Mutable statics are safe to access\n#[dynamic] \nstatic mut L2: Vec\u003ci32\u003e = {\n   //get a unique lock:\n   let mut lock = L1.write(); \n   lock.push(42); \n   lock.clone()\n   };\n```\n\nThose statics use an *apdaptative phase locker* that gives them surprising performance.\n\n# Classical Lazy statics \n\nBy default, initialization of statics declared with the `dynamic` is forced before main\nstart on platform that support it. If *lazyness* if a required feature, the attribute argument\n`lazy` can be used.\n\n```rust\nuse static_init::{dynamic};\n\n#[dynamic(lazy)] \nstatic L1: Vec\u003ci32\u003e = vec![1,2,3,4,5,6];\n\n#[dynamic(lazy,drop)] \nstatic mut L3: Vec\u003ci32\u003e =L1.clone(); \n```\n\nEven if the static is not mut, dropped statics are always locked. There is also a `finalize` attribute\nargument that can be used to run a \"drop\" equivalent at program exit but leaves the static unchanged. \n\nThose lazy also provide superior performances compared to other solutions.\n\n# Other features for lazy statics\n\nIn the documentation of macro `dynamic` you will find how to:\n\n- declare static that are poisoned if first initialization panics. (By default initialization is retried)\n\n- declare finalized or droped statics.\n\n- declare droped or finalized statics that tolerate to be leaked.\n\n- declare lazy statics that are also const initialized and provide a const fallback when their resource is released\n  at program/thread exit\n\n# `no_std` support\n\nOn linux or Reddox (TBC) this library is `no_std`. The library use directly the `futex` system call\nto place thread in a wait queue when needed.\n\nOn other platform `no_std` support can be gain by using the `spin_loop` feature. NB that lock strategies\nbased on spin loop are not system-fair and cause entire system slow-down.\n\n# Performant\n\n## Under the hood\n\nThe statics and mutable statics declared with `dynamic` attribute use what we\ncall an  *adaptative phase locker*. This is a lock that is in between a `Once`\nand a `RwLock`. It is carefully implemented as a variation over the `RwLock`\nalgorithms of `parking_lot` crate with other tradeoff and different\ncapabilities. \n\nIt is qualified *adaptative* because the decision to take a read lock,\na write lock or not to take a lock is performed while the lock attempt is\nperformed and a thread may attempt to get a write lock but decides to be waked\nas the owner of a read lock if it is about to be placed in a wait queue.\n\nStatics and thread locals that need to register themselve for destruction at\nprogram or thread exit are implemented as members of an intrusive list. This\nimplementation avoid heap memory allocation caused by system library support\n(`libc::at_exit`, `glibc::__cxa_at_thread_exit`, pthread... registers use heap\nmemory allocation), and it avoid to fall on system library implementation\nlimits that may cause `thread_locals` declared with `std::thread_locals` not to\nbe dropped. \n\nLast but not least of the optimization, on windows and unixes (but not Mac yet)\n`dynamic` statics initialization is forced before main start. This fact unable\na double check with a single boolean for all statics that is much faster other\ndouble check solution. \n\n## Benchmark results\n\n### Lazy static access\n\nThis graph showes the access time to lazy statics once they are initialized. The measurment includes statics from crates `double_checked_cell` and `lazy_static`.  In the legend \"LesserLazy\" are the lazy declared using `#[dynamic]` attribute and \"Lazy\" those declared with the\nattribute `#[dynamic(lazy)]`. On the horizontal axis is reported the number of thread that almost simultaneous attempt to access the lazy and the vertical axis the access time summed over all thread. \n\nAccess time to lazy from this crates can be up to *10x faster* than other solutions.\n\n![](docs/access.svg)\n\n### Lazy static initialization\n\n#### Extremely short initization performance\n\nThis graph showes the access time to lazy statics when the lazy is not yet\ninitialized. The measurment includes statics from crates `double_checked_cell`\nand `lazy_static`.  In the legend \"LesserLazy\" are the lazy declared using\n`#[dynamic]` attribute and \"Lazy\" those declared with the attribute\n`#[dynamic(lazy)]`. On the horizontal axis is reported the number of thread\nthat almost simultaneous attempt to access and initialize the lazy and the\nvertical axis the access time + initialization time overhead summed over all\nthread. The initialization in itself count for pico seconds. \"LesserLazy\" (`#[dynamic]) are\nnot ploted here because they are initialized before main start but whatsoever,\nthey use the exact same lock as that of \"Lazy\" (`#[dynamic(lazy)]`) statics.\n\nInitialization duration is *3x time faster* when using statics from this crates.\n\n![](docs/init_nano.svg)\n\n#### Large initization performance\n\nIn this case all thread attempt to initialize a static whose initialization takes\napproximately 20µs. Static from this crates scale much better on high contention. On high contention\nis this crates provides a *10x speed-up*.\n\n![](docs/init_20us.svg)\n\n### Mutable Locked lazy access\n\nMutable lazy from this crates are compared to an implementation using parking-lot crate `RwLock`. The implementation\ncan be found in the source file `benches/multi_threaded/main.rs`.\n\nOn the graph below the legend \"Locked Lazy\" are for mutable statics declared with `#[dynamic(lazy)]` attribute, \"LesserLocked Lazy\" those declared with `#[dynamic]`, \"LesserLocked LazyDrop\" those declared with `#[dynamic(drop)]` and \"Locked Lazy PkLot\" the one implemented using parking-lot crate `RwLock`.\n\nMutable locked statics from this crates are close to *2x time faster* than the solution using parking-lot RwLock if the initialization is attempted throught an attempt to get a read lock (on the first graph). When initilization is attempted through an attempt to get a write lock all solutions are globaly equivalent.\n\n![](docs/access_locked_read.svg)\n![](docs/access_locked_write.svg)\n\n### Mutable locked lazy static initialization\n\n#### Extremely short initization performance\n\nHere we compare access time when the lazy is not yet initialized. On high\ncontention, when a high number of thread attempt to get a read lock while the\nlazy is not yet initialized, lazy declared with #[dynamic(lazy)] perform close\nto *100x time* `RwLock`. This is the concequence of the adaptative lock. On the\nother hand, on low contention, when only 1 or 2 thread are simultaneously\nattempting to initialize the static, this adaptative ness cause an increased\ninitialization time. Nevertheless this is a one shot performance shift of a few\nnano seconds.\n\n![](docs/init_locked_nano.svg)\n\n#### Large initialization time \n\nHere we compare access time + initialization time when the lazy is not yet initialized and when the initialization time is\nof the order of 20µs. When all threads attempt to initialize the statics while trying to get a write lock, the statics from \nthis crate hase similar performance as a static using parking_lot `RwLock`. But if such initialization is performed through attempt\nto get a read lock, statics from this crate are *200x time faster* than `RwLock`. This is also a concequence of the adaptative lock algorithm.\n\n![](docs/init_locked_20us.svg)\n\n# Thread local support\n\nOn nightly `thread_local` support can be enable with the feature\n`thread_local`. The attribute `dynamic` can be used with thread locals as with\nregular statics. In this case, the mutable `thread_local` will behave similarly\nto a RefCell with the same syntax as mutable lazy statics.\n\n```rust\n# #![cfg_attr(feature = \"thread_local\", feature(thread_local))]\n# use static_init::{Finaly,dynamic};\n# #[cfg(feature = \"thread_local\")]\n# mod m{\n# use static_init::{dynamic};\n\n#[dynamic(drop)] //guaranteed to be drop: no leak contrarily to std::thread_local\n#[thread_local]\nstatic V: Vec\u003ci32\u003e = vec![1,1,2,3,5];\n\n#[dynamic]\n#[thread_local]\nstatic mut W: Vec\u003ci32\u003e = V.clone();\n# fn main() { \nassert_ne!(W.read().len(), 0);\nassert_ne!(W.try_read().unwrap().len(), 0);\n# }\n# }\n```\n\n# Unsafe Low level \n\n## Unchecked statics initiliazed at program start up\n\nThe library also provides unchecked statics, whose initialization is run before main start. Those statics\ndoes not imply any memory overhead neither execution time overhead. This is the responsability of the coder\nto be sure not to access those static before they are initialized.\n\n```rust\nuse static_init::dynamic;\n\n#[dynamic(10)]\nstatic A: Vec\u003ci32\u003e = vec![1,2,3];\n\n#[dynamic(0,drop)]\nstatic mut B: Vec\u003ci32\u003e = unsafe {A.clone()};\n```\n\nEven if A is not declared mutable, the attribute macro convert it into a mutable static to ensure that every\naccess to it is unsafe.\n\nThe number indicates the priority, the larger the number, the sooner the static will be initialized.\n\nThose statics can also be droped at program exit with the `drop` attribute argument.\n\n## Program constructor destructor \n\nIt is possible to register fonction for execution before main start/ after main returns.\n\n```rust\nuse static_init::{constructor, destructor};\n\n#[constructor(10)]\nextern \"C\" fn run_first() {}\n\n#[constructor(0)]\nextern \"C\" fn then_run() {}\n\n#[destructor(0)]\nextern \"C\" fn pre_finish() {}\n\n#[destructor(10)]\nextern \"C\" fn finaly() {}\n```\n\n# Debug support\n\nThe feature `debug_order` can be activated to detect trouble with initialization order of raw\nstatics or dead locks due to lazy initialization depending on itself.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbqsrc%2Fstatic_init","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbbqsrc%2Fstatic_init","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbbqsrc%2Fstatic_init/lists"}