use crate::flash::ids::ThreadKey;
pub use crate::{
backend::thread::{
Duration, JoinHandle, Thread, ThreadId, assert_main_thread, assert_not_main_thread,
available_parallelism, current, current_thread_id, is_main_thread, is_worker_thread, park,
},
common::thread_id::active_named_thread_count,
};
pub(crate) enum GateBackend {
Engine,
Native,
}
impl Default for GateBackend {
fn default() -> Self {
if crate::flash::flash_ambient() {
Self::Engine
} else {
Self::Native
}
}
}
impl GateBackend {
#[inline]
pub(crate) fn park_timeout(&self, duration: Duration) {
match self {
Self::Engine => {
let key = ThreadKey::of(current().id());
crate::flash::system::park_timed_unparkable(
duration,
key,
crate::flash::system::ParkRole::Backstop,
);
}
Self::Native => crate::backend::thread::park_timeout(duration),
}
}
#[inline]
pub(crate) fn unpark(&self, thread_id: u64, thread: Option<&Thread>) {
match self {
Self::Engine => {
let key = ThreadKey::from(thread_id);
crate::flash::system::unpark(key);
}
Self::Native => {
if let Some(thread) = thread {
crate::backend::thread::unpark(thread);
}
}
}
}
}
#[inline]
pub(crate) fn gate_instant(backend: &GateBackend) -> crate::flash::Instant {
match backend {
GateBackend::Engine => crate::flash::Instant::now_virtual(),
GateBackend::Native => crate::flash::Instant::now_real(),
}
}
fn propagated<F, T>(f: F) -> impl FnOnce() -> T + Send + 'static
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
let ambient = crate::flash::ambient_snapshot();
let active = crate::flash::flash_enabled();
let slot = ambient.then(crate::flash::system::credit::DedicatedSlot::reserve);
move || {
let _ambient = crate::flash::set_ambient_for_spawn(ambient);
let _flash = crate::flash::enter_dynamic(active);
let _participant = slot.map(|slot| slot.claim_thread());
f()
}
}
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
crate::backend::thread::spawn(propagated(f))
}
#[inline]
pub fn yield_now() {
if crate::flash::flash_enabled() {
crate::flash::system::yield_until_advance();
} else {
crate::backend::thread::yield_now();
}
}
fn counted<F, T>(f: F) -> impl FnOnce() -> T + Send + 'static
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
let ambient = crate::flash::ambient_snapshot();
let slot = crate::flash::system::credit::DedicatedSlot::reserve_named();
move || {
let _ambient = crate::flash::set_ambient_for_spawn(ambient);
let _flash = crate::flash::enter_dynamic(true);
crate::flash::system::credit::reset_credit();
let _participant = slot.claim_dedicated();
f()
}
}
pub fn spawn_named<F, T, N: Into<String>>(name: N, f: F) -> JoinHandle<T>
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
crate::backend::thread::spawn_named_uncounted(name, counted(f))
}
#[inline]
#[track_caller]
pub fn sleep(duration: Duration) {
if crate::flash::flash_enabled() {
crate::flash::system::sleep_timed(duration);
} else {
crate::backend::thread::sleep(duration);
}
}
#[inline]
#[track_caller]
pub fn paced_backoff(duration: Duration) {
if crate::flash::flash_enabled() {
crate::flash::system::yield_until_advance();
} else {
crate::backend::thread::sleep(duration);
}
}
#[inline]
#[track_caller]
pub fn park_timeout(duration: Duration) {
if crate::flash::flash_enabled() {
crate::flash::system::park_timed_unparkable(
duration,
ThreadKey::of(current().id()),
crate::flash::system::ParkRole::Deadline,
);
} else {
crate::backend::thread::park_timeout(duration);
}
}
#[inline]
pub(crate) fn park_timeout_virtual(duration: Duration) {
crate::flash::system::park_timed_unparkable(
duration,
ThreadKey::of(current().id()),
crate::flash::system::ParkRole::Deadline,
);
}
#[inline]
pub fn unpark(t: &Thread) {
if crate::flash::flash_enabled() {
crate::flash::system::unpark(ThreadKey::of(t.id()));
}
crate::backend::thread::unpark(t);
}