#[cfg(target_os = "linux")]
pub(crate) fn count() -> std::io::Result<usize> {
let status = std::fs::read_to_string("/proc/self/status")?;
let line = status
.lines()
.find(|line| line.starts_with("Threads:"))
.ok_or_else(|| std::io::Error::new(std::io::ErrorKind::InvalidData, "no Threads: line"))?;
line.split_whitespace()
.nth(1)
.and_then(|n| n.parse().ok())
.ok_or_else(|| {
std::io::Error::new(std::io::ErrorKind::InvalidData, "malformed Threads: line")
})
}
#[cfg(all(
not(target_os = "linux"),
any(
target_os = "macos",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)
))]
pub(crate) use crate::unsafe_ops::thread_count as count;
#[cfg(all(
test,
any(
target_os = "linux",
target_os = "macos",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd"
)
))]
mod tests {
use super::count;
use crate::test_support::{is_subprocess, run_in_subprocess};
#[test]
fn current_thread_count_tracks_live_threads() {
run_in_subprocess(
"thread_count::tests::current_thread_count_tracks_live_threads_subprocess",
);
}
#[test]
#[ignore]
fn current_thread_count_tracks_live_threads_subprocess() {
if !is_subprocess() {
return;
}
use std::sync::mpsc;
use std::sync::{Arc, Barrier};
let base = count().expect("thread count should be readable");
assert!(
base >= 1,
"expected at least the calling thread, got {base}"
);
const N: usize = 3;
let release = Arc::new(Barrier::new(N + 1));
let (started_tx, started_rx) = mpsc::channel();
let mut handles = Vec::new();
for _ in 0..N {
let release = Arc::clone(&release);
let started_tx = started_tx.clone();
handles.push(std::thread::spawn(move || {
started_tx.send(()).unwrap();
release.wait();
}));
}
for _ in 0..N {
started_rx.recv().unwrap(); }
let with_threads = count().expect("thread count should be readable");
assert!(
with_threads >= base + N,
"expected >= {} threads with {N} spawned, got {with_threads}",
base + N
);
release.wait();
for h in handles {
h.join().unwrap();
}
}
}