diff options
| author | Aleksey Kladov <aleksey.kladov@gmail.com> | 2018-08-06 16:31:04 +0300 |
|---|---|---|
| committer | Aleksey Kladov <aleksey.kladov@gmail.com> | 2018-08-09 20:50:43 +0300 |
| commit | e1bd0e7b4e9009ada545580b2698a11631f1f597 (patch) | |
| tree | 70bc9475b5d60ac8235a329515cd00c900b3e000 /src/libstd/sync | |
| parent | 6aba6f9184e0e738664c219c58feadb70f967f33 (diff) | |
| download | rust-e1bd0e7b4e9009ada545580b2698a11631f1f597.tar.gz rust-e1bd0e7b4e9009ada545580b2698a11631f1f597.zip | |
Reduce code duplication in Once
Diffstat (limited to 'src/libstd/sync')
| -rw-r--r-- | src/libstd/sync/once.rs | 32 |
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 { |
