/rust/registry/src/index.crates.io-6f17d22bba15001f/spin-0.9.8/src/relax.rs
Line | Count | Source (jump to first uncovered line) |
1 | | //! Strategies that determine the behaviour of locks when encountering contention. |
2 | | |
3 | | /// A trait implemented by spinning relax strategies. |
4 | | pub trait RelaxStrategy { |
5 | | /// Perform the relaxing operation during a period of contention. |
6 | | fn relax(); |
7 | | } |
8 | | |
9 | | /// A strategy that rapidly spins while informing the CPU that it should power down non-essential components via |
10 | | /// [`core::hint::spin_loop`]. |
11 | | /// |
12 | | /// Note that spinning is a 'dumb' strategy and most schedulers cannot correctly differentiate it from useful work, |
13 | | /// thereby misallocating even more CPU time to the spinning process. This is known as |
14 | | /// ['priority inversion'](https://matklad.github.io/2020/01/02/spinlocks-considered-harmful.html). |
15 | | /// |
16 | | /// If you see signs that priority inversion is occurring, consider switching to [`Yield`] or, even better, not using a |
17 | | /// spinlock at all and opting for a proper scheduler-aware lock. Remember also that different targets, operating |
18 | | /// systems, schedulers, and even the same scheduler with different workloads will exhibit different behaviour. Just |
19 | | /// because priority inversion isn't occurring in your tests does not mean that it will not occur. Use a scheduler- |
20 | | /// aware lock if at all possible. |
21 | | pub struct Spin; |
22 | | |
23 | | impl RelaxStrategy for Spin { |
24 | | #[inline(always)] |
25 | 0 | fn relax() { |
26 | 0 | // Use the deprecated spin_loop_hint() to ensure that we don't get |
27 | 0 | // a higher MSRV than we need to. |
28 | 0 | #[allow(deprecated)] |
29 | 0 | core::sync::atomic::spin_loop_hint(); |
30 | 0 | } |
31 | | } |
32 | | |
33 | | /// A strategy that yields the current time slice to the scheduler in favour of other threads or processes. |
34 | | /// |
35 | | /// This is generally used as a strategy for minimising power consumption and priority inversion on targets that have a |
36 | | /// standard library available. Note that such targets have scheduler-integrated concurrency primitives available, and |
37 | | /// you should generally use these instead, except in rare circumstances. |
38 | | #[cfg(feature = "std")] |
39 | | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] |
40 | | pub struct Yield; |
41 | | |
42 | | #[cfg(feature = "std")] |
43 | | #[cfg_attr(docsrs, doc(cfg(feature = "std")))] |
44 | | impl RelaxStrategy for Yield { |
45 | | #[inline(always)] |
46 | | fn relax() { |
47 | | std::thread::yield_now(); |
48 | | } |
49 | | } |
50 | | |
51 | | /// A strategy that rapidly spins, without telling the CPU to do any powering down. |
52 | | /// |
53 | | /// You almost certainly do not want to use this. Use [`Spin`] instead. It exists for completeness and for targets |
54 | | /// that, for some reason, miscompile or do not support spin hint intrinsics despite attempting to generate code for |
55 | | /// them (i.e: this is a workaround for possible compiler bugs). |
56 | | pub struct Loop; |
57 | | |
58 | | impl RelaxStrategy for Loop { |
59 | | #[inline(always)] |
60 | 0 | fn relax() {} |
61 | | } |