about summary refs log tree commit diff
path: root/src/libstd/sync
diff options
context:
space:
mode:
authorAleksey Kladov <aleksey.kladov@gmail.com>2018-08-06 16:31:04 +0300
committerAleksey Kladov <aleksey.kladov@gmail.com>2018-08-09 20:50:43 +0300
commite1bd0e7b4e9009ada545580b2698a11631f1f597 (patch)
tree70bc9475b5d60ac8235a329515cd00c900b3e000 /src/libstd/sync
parent6aba6f9184e0e738664c219c58feadb70f967f33 (diff)
downloadrust-e1bd0e7b4e9009ada545580b2698a11631f1f597.tar.gz
rust-e1bd0e7b4e9009ada545580b2698a11631f1f597.zip
Reduce code duplication in Once
Diffstat (limited to 'src/libstd/sync')
-rw-r--r--src/libstd/sync/once.rs32
1 files changed, 18 insertions, 14 deletions
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 3ca6a135345..c788ff3ca63 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -219,13 +219,9 @@ impl Once {
     /// [poison]: struct.Mutex.html#poisoning
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn call_once<F>(&self, f: F) where F: FnOnce() {
-        // Fast path, just see if we've completed initialization.
-        // An `Acquire` load is enough because that makes all the initialization
-        // operations visible to us. The cold path uses SeqCst consistently
-        // because the performance difference really does not matter there,
-        // and SeqCst minimizes the chances of something going wrong.
-        if self.state.load(Ordering::Acquire) == COMPLETE {
-            return
+        // Fast path check
+        if self.is_completed() {
+            return;
         }
 
         let mut f = Some(f);
@@ -280,13 +276,9 @@ impl Once {
     /// ```
     #[unstable(feature = "once_poison", issue = "33577")]
     pub fn call_once_force<F>(&self, f: F) where F: FnOnce(&OnceState) {
-        // same as above, just with a different parameter to `call_inner`.
-        // An `Acquire` load is enough because that makes all the initialization
-        // operations visible to us. The cold path uses SeqCst consistently
-        // because the performance difference really does not matter there,
-        // and SeqCst minimizes the chances of something going wrong.
-        if self.state.load(Ordering::Acquire) == COMPLETE {
-            return
+        // Fast path check
+        if self.is_completed() {
+            return;
         }
 
         let mut f = Some(f);
@@ -302,6 +294,10 @@ impl Once {
     ///   * `call_once` was called, but has not yet completed,
     ///   * the `Once` instance is poisoned
     ///
+    /// It is also possible that immediately after `is_completed`
+    /// returns false, some other thread finishes executing
+    /// `call_once`.
+    ///
     /// # Examples
     ///
     /// ```
@@ -333,6 +329,10 @@ impl Once {
     /// ```
     #[unstable(feature = "once_is_completed", issue = "42")]
     pub fn is_completed(&self) -> bool {
+        // An `Acquire` load is enough because that makes all the initialization
+        // operations visible to us, and, this being a fast path, weaker
+        // ordering helps with performance. This `Acquire` synchronizes with
+        // `SeqCst` operations on the slow path.
         self.state.load(Ordering::Acquire) == COMPLETE
     }
 
@@ -351,6 +351,10 @@ impl Once {
     fn call_inner(&self,
                   ignore_poisoning: bool,
                   init: &mut dyn FnMut(bool)) {
+
+        // This cold path uses SeqCst consistently because the
+        // performance difference really does not matter there, and
+        // SeqCst minimizes the chances of something going wrong.
         let mut state = self.state.load(Ordering::SeqCst);
 
         'outer: loop {