• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.
relax()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)]
relax()25     fn relax() {
26         core::hint::spin_loop();
27     }
28 }
29 
30 /// A strategy that yields the current time slice to the scheduler in favour of other threads or processes.
31 ///
32 /// This is generally used as a strategy for minimising power consumption and priority inversion on targets that have a
33 /// standard library available. Note that such targets have scheduler-integrated concurrency primitives available, and
34 /// you should generally use these instead, except in rare circumstances.
35 #[cfg(feature = "std")]
36 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
37 pub struct Yield;
38 
39 #[cfg(feature = "std")]
40 #[cfg_attr(docsrs, doc(cfg(feature = "std")))]
41 impl RelaxStrategy for Yield {
42     #[inline(always)]
relax()43     fn relax() {
44         std::thread::yield_now();
45     }
46 }
47 
48 /// A strategy that rapidly spins, without telling the CPU to do any powering down.
49 ///
50 /// You almost certainly do not want to use this. Use [`Spin`] instead. It exists for completeness and for targets
51 /// that, for some reason, miscompile or do not support spin hint intrinsics despite attempting to generate code for
52 /// them (i.e: this is a workaround for possible compiler bugs).
53 pub struct Loop;
54 
55 impl RelaxStrategy for Loop {
56     #[inline(always)]
relax()57     fn relax() {}
58 }
59