about summary refs log tree commit diff
path: root/src/libstd/sync
diff options
context:
space:
mode:
authorPaul Dicker <pitdicker@gmail.com>2019-10-23 10:01:22 +0200
committerPaul Dicker <pitdicker@gmail.com>2019-10-24 17:28:08 +0200
commit2e8eb5f33d55b507da687593bbb7042416d73058 (patch)
tree651e7748a76eae883c7aa4716b408f20b5b9133b /src/libstd/sync
parentfbc242f1ef172f6fa5b7bc837b5c3a78a4c8f850 (diff)
downloadrust-2e8eb5f33d55b507da687593bbb7042416d73058.tar.gz
rust-2e8eb5f33d55b507da687593bbb7042416d73058.zip
Move thread parking to a seperate function
Diffstat (limited to 'src/libstd/sync')
-rw-r--r--src/libstd/sync/once.rs80
1 files changed, 42 insertions, 38 deletions
diff --git a/src/libstd/sync/once.rs b/src/libstd/sync/once.rs
index 01cb7582d38..2c09fb3318b 100644
--- a/src/libstd/sync/once.rs
+++ b/src/libstd/sync/once.rs
@@ -401,44 +401,7 @@ impl Once {
                 // not RUNNING.
                 _ => {
                     assert!(state_and_queue & STATE_MASK == RUNNING);
-                    // Create the node for our current thread that we are going to try to slot
-                    // in at the head of the linked list.
-                    let mut node = Waiter {
-                        thread: thread::current(),
-                        signaled: AtomicBool::new(false),
-                        next: ptr::null(),
-                    };
-                    let me = &node as *const Waiter as usize;
-                    assert!(me & STATE_MASK == 0); // We assume pointers have 2 free bits that
-                                                   // we can use for state.
-
-                    // Try to slide in the node at the head of the linked list.
-                    // Run in a loop where we make sure the status is still RUNNING, and that
-                    // another thread did not just replace the head of the linked list.
-                    let mut old_head_and_status = state_and_queue;
-                    loop {
-                        if old_head_and_status & STATE_MASK != RUNNING {
-                            return; // No need anymore to enqueue ourselves.
-                        }
-
-                        node.next = (old_head_and_status & !STATE_MASK) as *const Waiter;
-                        let old = self.state_and_queue.compare_and_swap(old_head_and_status,
-                                                                        me | RUNNING,
-                                                                        Ordering::Release);
-                        if old == old_head_and_status {
-                            break; // Success!
-                        }
-                        old_head_and_status = old;
-                    }
-
-                    // We have enqueued ourselves, now lets wait.
-                    // It is important not to return before being signaled, otherwise we would
-                    // drop our `Waiter` node and leave a hole in the linked list (and a
-                    // dangling reference). Guard against spurious wakeups by reparking
-                    // ourselves until we are signaled.
-                    while !node.signaled.load(Ordering::SeqCst) {
-                        thread::park();
-                    }
+                    wait(&self.state_and_queue, state_and_queue);
                     state_and_queue = self.state_and_queue.load(Ordering::SeqCst);
                 }
             }
@@ -446,6 +409,47 @@ impl Once {
     }
 }
 
+fn wait(state_and_queue: &AtomicUsize, current_state: usize) {
+    // Create the node for our current thread that we are going to try to slot
+    // in at the head of the linked list.
+    let mut node = Waiter {
+        thread: thread::current(),
+        signaled: AtomicBool::new(false),
+        next: ptr::null(),
+    };
+    let me = &node as *const Waiter as usize;
+    assert!(me & STATE_MASK == 0); // We assume pointers have 2 free bits that
+                                   // we can use for state.
+
+    // Try to slide in the node at the head of the linked list.
+    // Run in a loop where we make sure the status is still RUNNING, and that
+    // another thread did not just replace the head of the linked list.
+    let mut old_head_and_status = current_state;
+    loop {
+        if old_head_and_status & STATE_MASK != RUNNING {
+            return; // No need anymore to enqueue ourselves.
+        }
+
+        node.next = (old_head_and_status & !STATE_MASK) as *const Waiter;
+        let old = state_and_queue.compare_and_swap(old_head_and_status,
+                                                   me | RUNNING,
+                                                   Ordering::Release);
+        if old == old_head_and_status {
+            break; // Success!
+        }
+        old_head_and_status = old;
+    }
+
+    // We have enqueued ourselves, now lets wait.
+    // It is important not to return before being signaled, otherwise we would
+    // drop our `Waiter` node and leave a hole in the linked list (and a
+    // dangling reference). Guard against spurious wakeups by reparking
+    // ourselves until we are signaled.
+    while !node.signaled.load(Ordering::SeqCst) {
+        thread::park();
+    }
+}
+
 #[stable(feature = "std_debug", since = "1.16.0")]
 impl fmt::Debug for Once {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {