summaryrefslogtreecommitdiffstats
path: root/vendor/parking_lot_core-0.8.6/src/spinwait.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/parking_lot_core-0.8.6/src/spinwait.rs')
-rw-r--r--vendor/parking_lot_core-0.8.6/src/spinwait.rs74
1 files changed, 74 insertions, 0 deletions
diff --git a/vendor/parking_lot_core-0.8.6/src/spinwait.rs b/vendor/parking_lot_core-0.8.6/src/spinwait.rs
new file mode 100644
index 000000000..ad0327a3a
--- /dev/null
+++ b/vendor/parking_lot_core-0.8.6/src/spinwait.rs
@@ -0,0 +1,74 @@
+// Copyright 2016 Amanieu d'Antras
+//
+// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
+// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
+// http://opensource.org/licenses/MIT>, at your option. This file may not be
+// copied, modified, or distributed except according to those terms.
+
+use crate::thread_parker;
+use std::sync::atomic::spin_loop_hint;
+
+// Wastes some CPU time for the given number of iterations,
+// using a hint to indicate to the CPU that we are spinning.
+#[inline]
+fn cpu_relax(iterations: u32) {
+ for _ in 0..iterations {
+ spin_loop_hint()
+ }
+}
+
+/// A counter used to perform exponential backoff in spin loops.
+#[derive(Default)]
+pub struct SpinWait {
+ counter: u32,
+}
+
+impl SpinWait {
+ /// Creates a new `SpinWait`.
+ #[inline]
+ pub fn new() -> Self {
+ Self::default()
+ }
+
+ /// Resets a `SpinWait` to its initial state.
+ #[inline]
+ pub fn reset(&mut self) {
+ self.counter = 0;
+ }
+
+ /// Spins until the sleep threshold has been reached.
+ ///
+ /// This function returns whether the sleep threshold has been reached, at
+ /// which point further spinning has diminishing returns and the thread
+ /// should be parked instead.
+ ///
+ /// The spin strategy will initially use a CPU-bound loop but will fall back
+ /// to yielding the CPU to the OS after a few iterations.
+ #[inline]
+ pub fn spin(&mut self) -> bool {
+ if self.counter >= 10 {
+ return false;
+ }
+ self.counter += 1;
+ if self.counter <= 3 {
+ cpu_relax(1 << self.counter);
+ } else {
+ thread_parker::thread_yield();
+ }
+ true
+ }
+
+ /// Spins without yielding the thread to the OS.
+ ///
+ /// Instead, the backoff is simply capped at a maximum value. This can be
+ /// used to improve throughput in `compare_exchange` loops that have high
+ /// contention.
+ #[inline]
+ pub fn spin_no_yield(&mut self) {
+ self.counter += 1;
+ if self.counter > 10 {
+ self.counter = 10;
+ }
+ cpu_relax(1 << self.counter);
+ }
+}