1 // Take a look at the license at the top of the repository in the LICENSE file.
3 #![doc = include_str!("../README.md")]
4 #![allow(unknown_lints)]
6 #![deny(rustdoc::broken_intra_doc_links)]
7 #![allow(clippy::upper_case_acronyms)]
8 #![allow(clippy::non_send_fields_in_send_ty)]
9 #![allow(renamed_and_removed_lints)]
10 #![allow(unknown_lints)]
16 if #[cfg(feature = "unknown-ci")] {
17 // This is used in CI to check that the build for unknown targets is compiling fine.
22 pub(crate) const MIN_USERS
: usize = 0;
23 } else if #[cfg(any(target_os = "macos", target_os = "ios"))] {
26 extern crate core_foundation_sys
;
29 pub(crate) const MIN_USERS
: usize = 1;
30 } else if #[cfg(windows)] {
37 pub(crate) const MIN_USERS
: usize = 1;
38 } else if #[cfg(any(target_os = "linux", target_os = "android"))] {
44 pub(crate) const MIN_USERS
: usize = 1;
45 } else if #[cfg(target_os = "freebsd")] {
51 pub(crate) const MIN_USERS
: usize = 1;
57 pub(crate) const MIN_USERS
: usize = 0;
62 get_current_pid
, CpuRefreshKind
, DiskType
, DiskUsage
, Gid
, LoadAvg
, NetworksIter
, Pid
, PidExt
,
63 ProcessRefreshKind
, ProcessStatus
, RefreshKind
, Signal
, Uid
, User
,
65 pub use sys
::{Component, Cpu, Disk, NetworkData, Networks, Process, System}
;
67 ComponentExt
, CpuExt
, DiskExt
, NetworkExt
, NetworksExt
, ProcessExt
, SystemExt
, UserExt
,
70 #[cfg(feature = "c-interface")]
71 pub use c_interface
::*;
73 #[cfg(feature = "c-interface")]
81 /// This function is only used on linux targets, on the other platforms it does nothing and returns
84 /// On linux, to improve performance, we keep a `/proc` file open for each process we index with
85 /// a maximum number of files open equivalent to half of the system limit.
87 /// The problem is that some users might need all the available file descriptors so we need to
88 /// allow them to change this limit.
90 /// Note that if you set a limit bigger than the system limit, the system limit will be set.
92 /// Returns `true` if the new value has been set.
95 /// use sysinfo::{System, SystemExt, set_open_files_limit};
97 /// // We call the function before any call to the processes update.
98 /// if !set_open_files_limit(10) {
99 /// // It'll always return false on non-linux targets.
100 /// eprintln!("failed to update the open files limit...");
102 /// let s = System::new_all();
104 pub fn set_open_files_limit(mut _new_limit
: isize) -> bool
{
106 if #[cfg(all(not(feature = "unknown-ci"), any(target_os = "linux", target_os = "android")))]
111 let max
= sys
::system
::get_max_nb_fds();
112 if _new_limit
> max
{
116 if let Ok(ref mut x
) = sys
::system
::REMAINING_FILES
.lock() {
117 // If files are already open, to be sure that the number won't be bigger when those
118 // files are closed, we subtract the current number of opened files to the new
120 let diff
= max
.saturating_sub(**x
);
121 **x
= _new_limit
.saturating_sub(diff
);
133 // FIXME: Can be removed once negative trait bounds are supported.
136 /// Check that `Process` doesn't implement `Clone`.
138 /// First we check that the "basic" code works:
141 /// use sysinfo::{Process, System, SystemExt};
143 /// let mut s = System::new_all();
144 /// let p: &Process = s.processes().values().next().unwrap();
147 /// And now we check if it fails when we try to clone it:
150 /// use sysinfo::{Process, System, SystemExt};
152 /// let mut s = System::new_all();
153 /// let p: &Process = s.processes().values().next().unwrap();
154 /// let p = (*p).clone();
158 /// Check that `System` doesn't implement `Clone`.
160 /// First we check that the "basic" code works:
163 /// use sysinfo::{Process, System, SystemExt};
165 /// let s = System::new();
168 /// And now we check if it fails when we try to clone it:
171 /// use sysinfo::{Process, System, SystemExt};
173 /// let s = System::new();
174 /// let s = s.clone();
183 #[cfg(feature = "unknown-ci")]
185 fn check_unknown_ci_feature() {
186 assert
!(!System
::IS_SUPPORTED
);
190 fn check_process_memory_usage() {
191 let mut s
= System
::new();
194 if System
::IS_SUPPORTED
{
195 // No process should have 0 as memory usage.
196 #[cfg(not(feature = "apple-sandbox"))]
197 assert
!(!s
.processes().iter().all(|(_
, proc_
)| proc_
.memory() == 0));
199 // There should be no process, but if there is one, its memory usage should be 0.
200 assert
!(s
.processes().iter().all(|(_
, proc_
)| proc_
.memory() == 0));
205 fn check_memory_usage() {
206 let mut s
= System
::new();
208 assert_eq
!(s
.total_memory(), 0);
209 assert_eq
!(s
.free_memory(), 0);
210 assert_eq
!(s
.available_memory(), 0);
211 assert_eq
!(s
.used_memory(), 0);
212 assert_eq
!(s
.total_swap(), 0);
213 assert_eq
!(s
.free_swap(), 0);
214 assert_eq
!(s
.used_swap(), 0);
217 if System
::IS_SUPPORTED
{
218 assert
!(s
.total_memory() > 0);
219 assert
!(s
.used_memory() > 0);
220 if s
.total_swap() > 0 {
221 // I think it's pretty safe to assume that there is still some swap left...
222 assert
!(s
.free_swap() > 0);
225 assert_eq
!(s
.total_memory(), 0);
226 assert_eq
!(s
.used_memory(), 0);
227 assert_eq
!(s
.total_swap(), 0);
228 assert_eq
!(s
.free_swap(), 0);
232 #[cfg(target_os = "linux")]
234 fn check_processes_cpu_usage() {
235 if !System
::IS_SUPPORTED
{
238 let mut s
= System
::new();
240 s
.refresh_processes();
241 // All CPU usage will start at zero until the second refresh
245 .all(|(_
, proc_
)| proc_
.cpu_usage() == 0.0));
247 // Wait a bit to update CPU usage values
248 std
::thread
::sleep(std
::time
::Duration
::from_millis(100));
249 s
.refresh_processes();
253 .all(|(_
, proc_
)| proc_
.cpu_usage() >= 0.0
254 && proc_
.cpu_usage() <= (s
.cpus().len() as f32) * 100.0));
258 .any(|(_
, proc_
)| proc_
.cpu_usage() > 0.0));
262 fn check_cpu_usage() {
263 if !System
::IS_SUPPORTED
{
266 let mut s
= System
::new();
269 // Wait a bit to update CPU usage values
270 std
::thread
::sleep(std
::time
::Duration
::from_millis(100));
271 if s
.cpus().iter().any(|c
| c
.cpu_usage() > 0.0) {
276 panic
!("CPU usage is always zero...");
281 let mut s
= System
::new();
282 assert
!(s
.users().is_empty());
283 s
.refresh_users_list();
284 assert
!(s
.users().len() >= MIN_USERS
);
286 let mut s
= System
::new();
287 assert
!(s
.users().is_empty());
289 assert
!(s
.users().is_empty());
291 let s
= System
::new_all();
292 assert
!(s
.users().len() >= MIN_USERS
);
297 let mut s
= System
::new();
298 assert
!(s
.users().is_empty());
299 s
.refresh_users_list();
300 let users
= s
.users();
301 assert
!(users
.len() >= MIN_USERS
);
303 if System
::IS_SUPPORTED
{
304 #[cfg(not(target_os = "windows"))]
308 .find(|u
| u
.name() == "root")
309 .expect("no root user");
310 assert_eq
!(**user
.id(), 0);
311 assert_eq
!(*user
.group_id(), 0);
312 if let Some(user
) = users
.iter().find(|u
| *u
.group_id() > 0) {
313 assert
!(**user
.id() > 0);
314 assert
!(*user
.group_id() > 0);
316 assert
!(users
.iter().filter(|u
| **u
.id() > 0).count() > 0);
319 // And now check that our `get_user_by_id` method works.
320 s
.refresh_processes();
324 .filter_map(|(_
, p
)| p
.user_id())
325 .any(|uid
| s
.get_user_by_id(uid
).is_some()));
330 fn check_system_info() {
331 // We don't want to test on unsupported systems.
332 if System
::IS_SUPPORTED
{
333 let s
= System
::new();
334 assert
!(!s
.name().expect("Failed to get system name").is_empty());
338 .expect("Failed to get kernel version")
341 assert
!(!s
.os_version().expect("Failed to get os version").is_empty());
345 .expect("Failed to get long OS version")
351 fn check_host_name() {
352 // We don't want to test on unsupported systems.
353 if System
::IS_SUPPORTED
{
354 let s
= System
::new();
355 assert
!(s
.host_name().is_some());
360 fn check_refresh_process_return_value() {
361 // We don't want to test on unsupported systems.
362 if System
::IS_SUPPORTED
{
363 let _pid
= get_current_pid().expect("Failed to get current PID");
365 #[cfg(not(feature = "apple-sandbox"))]
367 let mut s
= System
::new();
368 // First check what happens in case the process isn't already in our process list.
369 assert
!(s
.refresh_process(_pid
));
370 // Then check that it still returns true if the process is already in our process list.
371 assert
!(s
.refresh_process(_pid
));
377 fn ensure_is_supported_is_set_correctly() {
379 assert
!(System
::IS_SUPPORTED
);
381 assert
!(!System
::IS_SUPPORTED
);
386 fn check_cpus_number() {
387 let mut s
= System
::new();
389 // This information isn't retrieved by default.
390 assert
!(s
.cpus().is_empty());
391 if System
::IS_SUPPORTED
{
392 // The physical cores count is recomputed every time the function is called, so the
393 // information must be relevant even with nothing initialized.
394 let physical_cores_count
= s
395 .physical_core_count()
396 .expect("failed to get number of physical cores");
399 // The cpus shouldn't be empty anymore.
400 assert
!(!s
.cpus().is_empty());
402 // In case we are running inside a VM, it's possible to not have a physical core, only
403 // logical ones, which is why we don't test `physical_cores_count > 0`.
404 let physical_cores_count2
= s
405 .physical_core_count()
406 .expect("failed to get number of physical cores");
407 assert
!(physical_cores_count2
<= s
.cpus().len());
408 assert_eq
!(physical_cores_count
, physical_cores_count2
);
410 assert_eq
!(s
.physical_core_count(), None
);
412 assert
!(s
.physical_core_count().unwrap_or(0) <= s
.cpus().len());
416 fn check_nb_supported_signals() {
417 if System
::IS_SUPPORTED
{
419 !System
::SUPPORTED_SIGNALS
.is_empty(),
420 "SUPPORTED_SIGNALS shoudn't be empty on supported systems!"
424 System
::SUPPORTED_SIGNALS
.is_empty(),
425 "SUPPORTED_SIGNALS should be empty on not support systems!"
430 // Ensure that the CPUs frequency isn't retrieved until we ask for it.
432 #[cfg(not(target_os = "freebsd"))] // In a VM, it'll fail.
433 fn check_cpu_frequency() {
434 if !System
::IS_SUPPORTED
{
437 let mut s
= System
::new();
438 s
.refresh_processes();
439 for proc_
in s
.cpus() {
440 assert_eq
!(proc_
.frequency(), 0);
443 for proc_
in s
.cpus() {
444 assert_ne
!(proc_
.frequency(), 0);