use park::{BoxPark, BoxUnpark};
use task::Task;
use worker::state::{State, PUSHED_MASK};
use std::cell::UnsafeCell;
use std::fmt;
use std::sync::Arc;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::atomic::Ordering::{AcqRel, Relaxed};
use crossbeam_utils::CachePadded;
use deque;
pub(crate) struct WorkerEntry {
pub state: CachePadded<AtomicUsize>,
next_sleeper: UnsafeCell<usize>,
worker: deque::Worker<Arc<Task>>,
stealer: deque::Stealer<Arc<Task>>,
pub park: UnsafeCell<BoxPark>,
pub unpark: BoxUnpark,
}
impl WorkerEntry {
pub fn new(park: BoxPark, unpark: BoxUnpark) -> Self {
let (w, s) = deque::fifo();
WorkerEntry {
state: CachePadded::new(AtomicUsize::new(State::default().into())),
next_sleeper: UnsafeCell::new(0),
worker: w,
stealer: s,
park: UnsafeCell::new(park),
unpark,
}
}
pub fn fetch_unset_pushed(&self, ordering: Ordering) -> State {
self.state.fetch_and(!PUSHED_MASK, ordering).into()
}
#[inline]
pub fn submit_internal(&self, task: Arc<Task>) {
self.push_internal(task);
}
#[inline]
pub fn notify(&self, mut state: State) -> bool {
use worker::Lifecycle::*;
loop {
let mut next = state;
next.notify();
let actual = self.state.compare_and_swap(
state.into(), next.into(),
AcqRel).into();
if state == actual {
break;
}
state = actual;
}
match state.lifecycle() {
Sleeping => {
self.wakeup();
true
}
Shutdown => false,
Running | Notified | Signaled => {
true
}
}
}
pub fn signal_stop(&self, mut state: State) {
use worker::Lifecycle::*;
loop {
let mut next = state;
match state.lifecycle() {
Shutdown => {
return;
}
Running | Sleeping => {}
Notified | Signaled => {
return;
}
}
next.set_lifecycle(Signaled);
let actual = self.state.compare_and_swap(
state.into(), next.into(), AcqRel).into();
if actual == state {
break;
}
state = actual;
}
self.wakeup();
}
#[inline]
pub fn pop_task(&self) -> deque::Pop<Arc<Task>> {
self.worker.pop()
}
pub fn steal_tasks(&self, dest: &Self) -> deque::Steal<Arc<Task>> {
self.stealer.steal_many(&dest.worker)
}
pub fn drain_tasks(&self) {
use deque::Pop::*;
loop {
match self.worker.pop() {
Data(_) => {}
Empty => break,
Retry => {}
}
}
}
#[inline]
pub fn push_internal(&self, task: Arc<Task>) {
self.worker.push(task);
}
#[inline]
pub fn wakeup(&self) {
self.unpark.unpark();
}
#[inline]
pub fn next_sleeper(&self) -> usize {
unsafe { *self.next_sleeper.get() }
}
#[inline]
pub fn set_next_sleeper(&self, val: usize) {
unsafe { *self.next_sleeper.get() = val; }
}
}
impl fmt::Debug for WorkerEntry {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
fmt.debug_struct("WorkerEntry")
.field("state", &self.state.load(Relaxed))
.field("next_sleeper", &"UnsafeCell<usize>")
.field("worker", &self.worker)
.field("stealer", &self.stealer)
.field("park", &"UnsafeCell<BoxPark>")
.field("unpark", &"BoxUnpark")
.finish()
}
}