1use tokio::sync::OnceCell;
2use tracing::warn;
3
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub struct RuntimeFeatures {
6 pub io_uring: bool,
7 pub num_cpus: usize,
8}
9
10static RUNTIME_FEATURES: OnceCell<RuntimeFeatures> = OnceCell::const_new();
11
12pub async fn detect_runtime_features() -> RuntimeFeatures {
13 *RUNTIME_FEATURES
14 .get_or_init(|| async {
15 let io_uring = match tokio::task::spawn_blocking(detect_io_uring).await {
16 Ok(value) => value,
17 Err(error) => {
18 warn!("runtime feature probe failed: {error}");
19 false
20 }
21 };
22 RuntimeFeatures {
23 io_uring,
24 num_cpus: std::thread::available_parallelism()
27 .map_or(1, std::num::NonZeroUsize::get),
28 }
29 })
30 .await
31}
32
33fn detect_io_uring() -> bool {
34 #[cfg(target_os = "linux")]
35 {
36 if let Ok(release) = std::fs::read_to_string("/proc/sys/kernel/osrelease")
37 && let Some(major) = release.split('.').next()
38 && let Ok(major) = major.parse::<u32>()
39 && major < 5
40 {
41 return false;
42 }
43 io_uring::IoUring::new(1).is_ok()
44 }
45
46 #[cfg(not(target_os = "linux"))]
47 {
48 false
49 }
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55
56 #[tokio::test]
57 async fn io_uring_report_matches_target_gate() {
58 let features = detect_runtime_features().await;
59 assert!(!features.io_uring || cfg!(target_os = "linux"));
60 }
61}