use super::*;
impl PreparedThread {
pub fn thread_handle(&self) -> ThreadHandle {
self.handle
.as_ref()
.expect("prepared thread was already consumed")
.clone()
}
pub fn publish(self) -> Result<ThreadHandle, TaskError> {
Ok(self.stage()?.activate())
}
pub fn stage(mut self) -> Result<StagedThread, TaskError> {
let handle = self
.handle
.take()
.expect("prepared thread was already consumed");
publish_prepared_thread(self.system, handle).map(|handle| StagedThread {
handle: Some(handle),
start: Arc::clone(&self.start),
})
}
pub(in crate::thread) fn new(
system: &'static TaskSystem,
handle: ThreadHandle,
start: Arc<RuntimeThreadStart>,
) -> Self {
Self {
system,
handle: Some(handle),
start,
}
}
}
impl StagedThread {
pub fn thread_handle(&self) -> ThreadHandle {
self.handle
.as_ref()
.expect("staged thread was already consumed")
.clone()
}
pub fn activate(mut self) -> ThreadHandle {
let handle = self
.handle
.take()
.expect("staged thread was already consumed");
self.start.activate();
handle
}
}
impl Drop for StagedThread {
fn drop(&mut self) {
self.start.abort();
}
}
impl Drop for PreparedThread {
fn drop(&mut self) {
if let Some(handle) = self.handle.take() {
cleanup_failed_thread(self.system, handle);
}
}
}
impl RuntimeThreadStart {
pub(in crate::thread) const fn new() -> Self {
Self {
state: AtomicU8::new(THREAD_START_PENDING),
wait: WaitQueue::new(),
}
}
fn activate(&self) {
self.state
.compare_exchange(
THREAD_START_PENDING,
THREAD_START_ACTIVE,
Ordering::AcqRel,
Ordering::Acquire,
)
.unwrap_or_else(|state| panic!("invalid staged-thread activation state: {state}"));
self.wait.notify_all();
}
fn abort(&self) {
if self
.state
.compare_exchange(
THREAD_START_PENDING,
THREAD_START_ABORTED,
Ordering::AcqRel,
Ordering::Acquire,
)
.is_ok()
{
self.wait.notify_all();
}
}
pub(in crate::thread) fn wait_for_activation(&self) -> bool {
match self.state.load(Ordering::Acquire) {
THREAD_START_ACTIVE => return true,
THREAD_START_ABORTED => return false,
THREAD_START_PENDING => {}
state => panic!("invalid runtime thread-start state: {state}"),
}
self.wait
.wait_until(|| self.state.load(Ordering::Acquire) != THREAD_START_PENDING);
match self.state.load(Ordering::Acquire) {
THREAD_START_ACTIVE => true,
THREAD_START_ABORTED => false,
state => panic!("invalid completed thread-start state: {state}"),
}
}
}
fn publish_prepared_thread(
system: &'static TaskSystem,
handle: ThreadHandle,
) -> Result<ThreadHandle, TaskError> {
let result = with_current_cpu_local_mut_owner(|cpu| system.start_thread(cpu, handle.id()));
if let Err(error) = result {
cleanup_failed_thread(system, handle);
return Err(error);
}
Ok(handle)
}
fn cleanup_failed_thread(system: &TaskSystem, handle: ThreadHandle) {
let thread = handle.id();
let _ = system.mark_exited(thread);
drop(handle);
let _ = system.reap_thread(thread);
}