README.md
1# critical-section
2[](https://crates.io/crates/critical-section)
3[](https://crates.io/crates/critical-section)
4[](https://docs.rs/critical-section)
5
6This project is developed and maintained by the [HAL team][team].
7
8A critical section that works everywhere!
9
10When writing software for embedded systems, it's common to use a "critical section"
11as a basic primitive to control concurrency. A critical section is essentially a
12mutex global to the whole process, that can be acquired by only one thread at a time.
13This can be used to protect data behind mutexes, to [emulate atomics](https://crates.io/crates/portable-atomic) in
14targets that don't support them, etc.
15
16There's a wide range of possible implementations depending on the execution environment:
17- For bare-metal single core, disabling interrupts in the current (only) core.
18- For bare-metal multicore, disabling interrupts in the current core and acquiring a hardware spinlock to prevent other cores from entering a critical section concurrently.
19- For bare-metal using a RTOS, using library functions for acquiring a critical section, often named "scheduler lock" or "kernel lock".
20- For bare-metal running in non-privileged mode, calling some system call is usually needed.
21- For `std` targets, acquiring a global `std::sync::Mutex`.
22
23Libraries often need to use critical sections, but there's no universal API for this in `core`. This leads
24library authors to hard-code them for their target, or at best add some `cfg`s to support a few targets.
25This doesn't scale since there are many targets out there, and in the general case it's impossible to know
26which critical section implementation is needed from the Rust target alone. For example, the `thumbv7em-none-eabi` target
27could be cases 1-4 from the above list.
28
29This crate solves the problem by providing this missing universal API.
30
31- It provides functions `acquire`, `release` and `with` that libraries can directly use.
32- It provides a way for any crate to supply an implementation. This allows "target support" crates such as architecture crates (`cortex-m`, `riscv`), RTOS bindings, or HALs for multicore chips to supply the correct implementation so that all the crates in the dependency tree automatically use it.
33
34## Usage in `no-std` binaries.
35
36First, add a dependency on a crate providing a critical section implementation. Enable the `critical-section-*` Cargo feature if required by the crate.
37
38Implementations are typically provided by either architecture-support crates, HAL crates, and OS/RTOS bindings, including:
39
40* The [`cortex-m`] crate provides an implementation for all single-core Cortex-M microcontrollers via its `critical-section-single-core` feature
41* The [`riscv`] crate provides an implementation for all single-hart RISC-V microcontrollers via its `critical-section-single-hart` feature
42* The [`msp430`] crate provides an implementation for all MSP430 microcontrollers via its `critical-section-single-core` feature
43* The [`rp2040-hal`] crate provides a multi-core-safe critical section for the RP2040 microcontroller via its `critical-section-impl` feature
44* The [`avr-device`] crate provides an implementation for all AVR microcontrollers via its `critical-section-impl` feature
45* The [`esp-hal-common`] crate provides an implementation for ESP32 microcontrollers which is used by the ESP HALs
46* The [`embassy-rp`] crate provides a multi-core-safe critical section for the RP2040 microcontroller via its `critical-section-impl` feature
47* The [`nrf-softdevice`] crate provides a critical section that's compatible with the nRF soft-device firmware via its `critical-section-impl` feature
48
49[`cortex-m`]: https://crates.io/crates/cortex-m
50[`riscv`]: https://crates.io/crates/riscv
51[`msp430`]: https://crates.io/crates/msp430
52[`rp2040-hal`]: https://crates.io/crates/rp2040-hal
53[`avr-device`]: https://crates.io/crates/avr-device
54[`esp-hal-common`]: https://crates.io/crates/esp-hal-common
55[`embassy-rp`]: https://docs.embassy.dev/embassy-rp
56[`nrf-softdevice`]: https://docs.embassy.dev/nrf-softdevice
57
58For example, for single-core Cortex-M targets, you can use:
59
60```toml
61[dependencies]
62cortex-m = { version = "0.7.6", features = ["critical-section-single-core"]}
63```
64
65Then you can use `critical_section::with()`.
66
67```rust
68use core::cell::Cell;
69use critical_section::Mutex;
70
71static MY_VALUE: Mutex<Cell<u32>> = Mutex::new(Cell::new(0));
72
73critical_section::with(|cs| {
74 // This code runs within a critical section.
75
76 // `cs` is a token that you can use to "prove" that to some API,
77 // for example to a `Mutex`:
78 MY_VALUE.borrow(cs).set(42);
79});
80
81# #[cfg(not(feature = "std"))] // needed for `cargo test --features std`
82# mod no_std {
83# struct MyCriticalSection;
84# critical_section::set_impl!(MyCriticalSection);
85# unsafe impl critical_section::Impl for MyCriticalSection {
86# unsafe fn acquire() -> () {}
87# unsafe fn release(token: ()) {}
88# }
89# }
90```
91
92## Usage in `std` binaries.
93
94Add the `critical-section` dependency to `Cargo.toml` enabling the `std` feature. This makes the `critical-section` crate itself
95provide an implementation based on `std::sync::Mutex`, so you don't have to add any other dependency.
96
97```toml
98[dependencies]
99critical-section = { version = "1.1", features = ["std"]}
100```
101
102## Usage in libraries
103
104If you're writing a library intended to be portable across many targets, simply add a dependency on `critical-section`
105and use `critical_section::free` and/or `Mutex` as usual.
106
107**Do not** add any dependency supplying a critical section implementation. Do not enable any `critical-section-*` Cargo feature.
108This has to be done by the end user, enabling the correct implementation for their target.
109
110**Do not** enable any Cargo feature in `critical-section`.
111
112## Usage in `std` tests for `no-std` libraries.
113
114If you want to run `std`-using tests in otherwise `no-std` libraries, enable the `std` feature in `dev-dependencies` only.
115This way the main target will use the `no-std` implementation chosen by the end-user's binary, and only the test targets
116will use the `std` implementation.
117
118```toml
119[dependencies]
120critical-section = "1.1"
121
122[dev-dependencies]
123critical-section = { version = "1.1", features = ["std"]}
124```
125
126## Providing an implementation
127
128Crates adding support for a particular architecture, chip or operating system should provide a critical section implementation.
129It is **strongly recommended** to gate the implementation behind a feature, so the user can still use another implementation
130if needed (having two implementations in the same binary will cause linking to fail).
131
132Add the dependency, and a `critical-section-*` feature to your `Cargo.toml`:
133
134```toml
135[features]
136# Enable critical section implementation that does "foo"
137critical-section-foo = ["critical-section/restore-state-bool"]
138
139[dependencies]
140critical-section = { version = "1.0", optional = true }
141```
142
143Then, provide the critical implementation like this:
144
145```rust
146# #[cfg(not(feature = "std"))] // needed for `cargo test --features std`
147# mod no_std {
148// This is a type alias for the enabled `restore-state-*` feature.
149// For example, it is `bool` if you enable `restore-state-bool`.
150use critical_section::RawRestoreState;
151
152struct MyCriticalSection;
153critical_section::set_impl!(MyCriticalSection);
154
155unsafe impl critical_section::Impl for MyCriticalSection {
156 unsafe fn acquire() -> RawRestoreState {
157 // TODO
158 }
159
160 unsafe fn release(token: RawRestoreState) {
161 // TODO
162 }
163}
164# }
165```
166
167## Troubleshooting
168
169### Undefined reference errors
170
171If you get an error like these:
172
173```not_rust
174undefined reference to `_critical_section_1_0_acquire'
175undefined reference to `_critical_section_1_0_release'
176```
177
178it is because you (or a library) are using `critical_section::with` without providing a critical section implementation.
179Make sure you're depending on a crate providing the implementation, and have enabled the `critical-section-*` feature in it if required. See the `Usage` section above.
180
181The error can also be caused by having the dependency but never `use`ing it. This can be fixed by adding a dummy `use`:
182
183```rust,ignore
184use the_cs_impl_crate as _;
185```
186
187### Duplicate symbol errors
188
189If you get errors like these:
190
191```not_rust
192error: symbol `_critical_section_1_0_acquire` is already defined
193```
194
195it is because you have two crates trying to provide a critical section implementation. You can only
196have one implementation in a program.
197
198You can use `cargo tree --format '{p} {f}'` to view all dependencies and their enabled features. Make sure
199that in the whole dependency tree, exactly one implementation is provided.
200
201Check for multiple versions of the same crate as well. For example, check the `critical-section-single-core`
202feature is not enabled for both `cortex-m` 0.7 and 0.8.
203
204## Why not generics?
205
206An alternative solution would be to use a `CriticalSection` trait, and make all
207code that needs acquiring the critical section generic over it. This has a few problems:
208
209- It would require passing it as a generic param to a very big amount of code, which
210would be quite unergonomic.
211- It's common to put `Mutex`es in `static` variables, and `static`s can't
212be generic.
213- It would allow mixing different critical section implementations in the same program,
214which would be unsound.
215
216## Minimum Supported Rust Version (MSRV)
217
218This crate is guaranteed to compile on the following Rust versions:
219
220- If the `std` feature is not enabled: stable Rust 1.54 and up.
221- If the `std` feature is enabled: stable Rust 1.63 and up.
222
223It might compile with older versions but that may change in any new patch release.
224
225See [here](docs/msrv.md) for details on how the MSRV may be upgraded.
226
227## License
228
229This work is licensed under either of
230
231- Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or
232 <http://www.apache.org/licenses/LICENSE-2.0>)
233- MIT license ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
234
235at your option.
236
237## Contribution
238
239Unless you explicitly state otherwise, any contribution intentionally submitted
240for inclusion in the work by you, as defined in the Apache-2.0 license, shall be
241dual licensed as above, without any additional terms or conditions.
242
243## Code of Conduct
244
245Contribution to this crate is organized under the terms of the [Rust Code of
246Conduct][CoC], the maintainer of this crate, the [HAL team][team], promises
247to intervene to uphold that code of conduct.
248
249[CoC]: CODE_OF_CONDUCT.md
250[team]: https://github.com/rust-embedded/wg#the-hal-team
251