Coverage Report

Created: 2025-02-21 07:11

/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
}