use std::sync::atomic::Ordering;
pub use std::time::Duration;
pub use crate::common::thread_id::active_named_thread_count;
use crate::common::thread_id::{ACTIVE_NAMED_THREADS, thread_id_hash};
pub type Thread = std::thread::Thread;
pub type ThreadId = std::thread::ThreadId;
fn counted<F, T>(f: F) -> impl FnOnce() -> T + Send + 'static
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
ACTIVE_NAMED_THREADS.fetch_add(1, Ordering::Release);
move || {
let result = f();
ACTIVE_NAMED_THREADS.fetch_sub(1, Ordering::Release);
result
}
}
#[derive(Default)]
pub(crate) enum GateBackend {
#[default]
System,
}
impl GateBackend {
#[inline]
pub(crate) fn park_timeout(&self, duration: Duration) {
match self {
Self::System => park_timeout(duration),
}
}
#[inline]
pub(crate) fn unpark(&self, _thread_id: u64, thread: Option<&Thread>) {
match self {
Self::System => {
if let Some(thread) = thread {
unpark(thread);
}
}
}
}
}
#[inline]
pub(crate) fn gate_instant(backend: &GateBackend) -> crate::time::Instant {
match backend {
GateBackend::System => crate::time::Instant::now(),
}
}
#[inline]
pub fn yield_now() {
std::thread::yield_now();
}
#[inline]
#[must_use]
pub fn is_worker_thread() -> bool {
false
}
#[inline]
#[must_use]
pub fn is_main_thread() -> bool {
true
}
#[inline]
pub fn assert_main_thread(_label: &str) {}
#[inline]
pub fn assert_not_main_thread(_label: &str) {}
pub type JoinHandle<T> = std::thread::JoinHandle<T>;
#[inline]
#[must_use]
pub fn current() -> Thread {
std::thread::current()
}
pub fn spawn<F, T>(f: F) -> JoinHandle<T>
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
std::thread::spawn(f)
}
pub(crate) fn spawn_named_uncounted<F, T, N: Into<String>>(name: N, f: F) -> JoinHandle<T>
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
std::thread::Builder::new()
.name(name.into())
.spawn(f)
.expect(
"BUG: spawn_named must succeed; thread::Builder only fails on OS resource exhaustion",
)
}
pub fn spawn_named<F, T, N: Into<String>>(name: N, f: F) -> JoinHandle<T>
where
F: FnOnce() -> T + Send + 'static,
T: Send + 'static,
{
spawn_named_uncounted(name, counted(f))
}
#[inline]
#[track_caller]
pub fn sleep(duration: Duration) {
crate::no_block::forbid("thread::sleep");
std::thread::sleep(duration);
}
#[inline]
#[track_caller]
pub fn paced_backoff(duration: Duration) {
sleep(duration);
}
#[inline]
#[track_caller]
pub fn park() {
crate::no_block::forbid("thread::park");
std::thread::park();
}
#[inline]
#[track_caller]
pub fn park_timeout(duration: Duration) {
crate::no_block::forbid("thread::park_timeout");
std::thread::park_timeout(duration);
}
#[inline]
pub fn unpark(t: &Thread) {
t.unpark();
}
#[inline]
#[must_use]
pub fn current_thread_id() -> u64 {
thread_id_hash(current().id())
}
#[inline]
#[must_use]
pub fn available_parallelism() -> Option<std::num::NonZeroUsize> {
std::thread::available_parallelism().ok()
}