Skip to content

Commit 2e8eb5f

Browse files
committed
Move thread parking to a seperate function
1 parent fbc242f commit 2e8eb5f

File tree

1 file changed

+42
-38
lines changed

1 file changed

+42
-38
lines changed

src/libstd/sync/once.rs

Lines changed: 42 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -401,51 +401,55 @@ impl Once {
401401
// not RUNNING.
402402
_ => {
403403
assert!(state_and_queue & STATE_MASK == RUNNING);
404-
// Create the node for our current thread that we are going to try to slot
405-
// in at the head of the linked list.
406-
let mut node = Waiter {
407-
thread: thread::current(),
408-
signaled: AtomicBool::new(false),
409-
next: ptr::null(),
410-
};
411-
let me = &node as *const Waiter as usize;
412-
assert!(me & STATE_MASK == 0); // We assume pointers have 2 free bits that
413-
// we can use for state.
414-
415-
// Try to slide in the node at the head of the linked list.
416-
// Run in a loop where we make sure the status is still RUNNING, and that
417-
// another thread did not just replace the head of the linked list.
418-
let mut old_head_and_status = state_and_queue;
419-
loop {
420-
if old_head_and_status & STATE_MASK != RUNNING {
421-
return; // No need anymore to enqueue ourselves.
422-
}
423-
424-
node.next = (old_head_and_status & !STATE_MASK) as *const Waiter;
425-
let old = self.state_and_queue.compare_and_swap(old_head_and_status,
426-
me | RUNNING,
427-
Ordering::Release);
428-
if old == old_head_and_status {
429-
break; // Success!
430-
}
431-
old_head_and_status = old;
432-
}
433-
434-
// We have enqueued ourselves, now lets wait.
435-
// It is important not to return before being signaled, otherwise we would
436-
// drop our `Waiter` node and leave a hole in the linked list (and a
437-
// dangling reference). Guard against spurious wakeups by reparking
438-
// ourselves until we are signaled.
439-
while !node.signaled.load(Ordering::SeqCst) {
440-
thread::park();
441-
}
404+
wait(&self.state_and_queue, state_and_queue);
442405
state_and_queue = self.state_and_queue.load(Ordering::SeqCst);
443406
}
444407
}
445408
}
446409
}
447410
}
448411

412+
fn wait(state_and_queue: &AtomicUsize, current_state: usize) {
413+
// Create the node for our current thread that we are going to try to slot
414+
// in at the head of the linked list.
415+
let mut node = Waiter {
416+
thread: thread::current(),
417+
signaled: AtomicBool::new(false),
418+
next: ptr::null(),
419+
};
420+
let me = &node as *const Waiter as usize;
421+
assert!(me & STATE_MASK == 0); // We assume pointers have 2 free bits that
422+
// we can use for state.
423+
424+
// Try to slide in the node at the head of the linked list.
425+
// Run in a loop where we make sure the status is still RUNNING, and that
426+
// another thread did not just replace the head of the linked list.
427+
let mut old_head_and_status = current_state;
428+
loop {
429+
if old_head_and_status & STATE_MASK != RUNNING {
430+
return; // No need anymore to enqueue ourselves.
431+
}
432+
433+
node.next = (old_head_and_status & !STATE_MASK) as *const Waiter;
434+
let old = state_and_queue.compare_and_swap(old_head_and_status,
435+
me | RUNNING,
436+
Ordering::Release);
437+
if old == old_head_and_status {
438+
break; // Success!
439+
}
440+
old_head_and_status = old;
441+
}
442+
443+
// We have enqueued ourselves, now lets wait.
444+
// It is important not to return before being signaled, otherwise we would
445+
// drop our `Waiter` node and leave a hole in the linked list (and a
446+
// dangling reference). Guard against spurious wakeups by reparking
447+
// ourselves until we are signaled.
448+
while !node.signaled.load(Ordering::SeqCst) {
449+
thread::park();
450+
}
451+
}
452+
449453
#[stable(feature = "std_debug", since = "1.16.0")]
450454
impl fmt::Debug for Once {
451455
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {

0 commit comments

Comments
 (0)