]> git.lizzy.rs Git - rust.git/blob - library/std/src/thread/available_concurrency.rs
Add std::thread::available_concurrency
[rust.git] / library / std / src / thread / available_concurrency.rs
1 use crate::io;
2 use crate::num::NonZeroUsize;
3
4 /// Returns the number of hardware threads available to the program.
5 ///
6 /// This value should be considered only a hint.
7 ///
8 /// # Platform-specific behavior
9 ///
10 /// If interpreted as the number of actual hardware threads, it may undercount on
11 /// Windows systems with more than 64 hardware threads. If interpreted as the
12 /// available concurrency for that process, it may overcount on Windows systems
13 /// when limited by a process wide affinity mask or job object limitations, and
14 /// it may overcount on Linux systems when limited by a process wide affinity
15 /// mask or affected by cgroups limits.
16 ///
17 /// # Errors
18 ///
19 /// This function will return an error in the following situations, but is not
20 /// limited to just these cases:
21 ///
22 /// - If the number of hardware threads is not known for the target platform.
23 /// - The process lacks permissions to view the number of hardware threads
24 ///   available.
25 ///
26 /// # Examples
27 ///
28 /// ```
29 /// # #![allow(dead_code)]
30 /// #![feature(available_concurrency)]
31 /// use std::thread;
32 ///
33 /// let count = thread::available_concurrency().map(|n| n.get()).unwrap_or(1);
34 /// ```
35 #[unstable(feature = "available_concurrency", issue = "74479")]
36 pub fn available_concurrency() -> io::Result<NonZeroUsize> {
37     available_concurrency_internal()
38 }
39
40 cfg_if::cfg_if! {
41     if #[cfg(windows)] {
42         #[allow(nonstandard_style)]
43         fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
44             #[repr(C)]
45             struct SYSTEM_INFO {
46                 wProcessorArchitecture: u16,
47                 wReserved: u16,
48                 dwPageSize: u32,
49                 lpMinimumApplicationAddress: *mut u8,
50                 lpMaximumApplicationAddress: *mut u8,
51                 dwActiveProcessorMask: *mut u8,
52                 dwNumberOfProcessors: u32,
53                 dwProcessorType: u32,
54                 dwAllocationGranularity: u32,
55                 wProcessorLevel: u16,
56                 wProcessorRevision: u16,
57             }
58             extern "system" {
59                 fn GetSystemInfo(info: *mut SYSTEM_INFO) -> i32;
60             }
61             let res = unsafe {
62                 let mut sysinfo = crate::mem::zeroed();
63                 GetSystemInfo(&mut sysinfo);
64                 sysinfo.dwNumberOfProcessors as usize
65             };
66             match res {
67                 0 => Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
68                 cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus) }),
69             }
70         }
71     } else if #[cfg(any(
72         target_os = "android",
73         target_os = "cloudabi",
74         target_os = "emscripten",
75         target_os = "fuchsia",
76         target_os = "ios",
77         target_os = "linux",
78         target_os = "macos",
79         target_os = "solaris",
80         target_os = "illumos",
81     ))] {
82         fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
83             match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN) } {
84                 -1 => Err(io::Error::last_os_error()),
85                 0 => Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform")),
86                 cpus => Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) }),
87             }
88         }
89     } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly", target_os = "netbsd"))] {
90         fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
91             use crate::ptr;
92
93             let mut cpus: libc::c_uint = 0;
94             let mut cpus_size = crate::mem::size_of_val(&cpus);
95
96             unsafe {
97                 cpus = libc::sysconf(libc::_SC_NPROCESSORS_ONLN) as libc::c_uint;
98             }
99
100             // Fallback approach in case of errors or no hardware threads.
101             if cpus < 1 {
102                 let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
103                 let res = unsafe {
104                     libc::sysctl(
105                         mib.as_mut_ptr(),
106                         2,
107                         &mut cpus as *mut _ as *mut _,
108                         &mut cpus_size as *mut _ as *mut _,
109                         ptr::null_mut(),
110                         0,
111                     )
112                 };
113
114                 // Handle errors if any.
115                 if res == -1 {
116                     return Err(io::Error::last_os_error());
117                 } else if cpus == 0 {
118                     return Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
119                 }
120             }
121             Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
122         }
123     } else if #[cfg(target_os = "openbsd")] {
124         fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
125             use crate::ptr;
126
127             let mut cpus: libc::c_uint = 0;
128             let mut cpus_size = crate::mem::size_of_val(&cpus);
129             let mut mib = [libc::CTL_HW, libc::HW_NCPU, 0, 0];
130
131             let res = unsafe {
132                 libc::sysctl(
133                     mib.as_mut_ptr(),
134                     2,
135                     &mut cpus as *mut _ as *mut _,
136                     &mut cpus_size as *mut _ as *mut _,
137                     ptr::null_mut(),
138                     0,
139                 )
140             };
141
142             // Handle errors if any.
143             if res == -1 {
144                 return Err(io::Error::last_os_error());
145             } else if cpus == 0 {
146                 return Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"));
147             }
148
149             Ok(unsafe { NonZeroUsize::new_unchecked(cpus as usize) })
150         }
151     } else {
152         // FIXME: implement on vxWorks, Redox, HermitCore, Haiku, l4re
153         fn available_concurrency_internal() -> io::Result<NonZeroUsize> {
154             Err(io::Error::new(io::ErrorKind::NotFound, "The number of hardware threads is not known for the target platform"))
155         }
156     }
157 }