sysinfo/common/system.rs
1// Take a look at the license at the top of the repository in the LICENSE file.
2
3use std::collections::{HashMap, HashSet};
4use std::ffi::{OsStr, OsString};
5use std::fmt;
6use std::path::Path;
7use std::process::ExitStatus;
8use std::str::FromStr;
9
10use crate::common::impl_get_set::impl_get_set;
11use crate::common::DiskUsage;
12use crate::{CpuInner, Gid, ProcessInner, SystemInner, Uid};
13
14/// Structs containing system's information such as processes, memory and CPU.
15///
16/// ⚠️ On newer Android versions, there are restrictions on which system information
17/// a non-system application has access to. So CPU information might not be available.
18///
19/// ```
20/// use sysinfo::System;
21///
22/// if sysinfo::IS_SUPPORTED_SYSTEM {
23/// println!("System: {:?}", System::new_all());
24/// } else {
25/// println!("This OS isn't supported (yet?).");
26/// }
27/// ```
28pub struct System {
29 pub(crate) inner: SystemInner,
30}
31
32impl Default for System {
33 fn default() -> System {
34 System::new()
35 }
36}
37
38impl System {
39 /// Creates a new [`System`] instance with nothing loaded.
40 ///
41 /// Use one of the refresh methods (like [`refresh_all`]) to update its internal information.
42 ///
43 /// [`System`]: crate::System
44 /// [`refresh_all`]: #method.refresh_all
45 ///
46 /// ```no_run
47 /// use sysinfo::System;
48 ///
49 /// let s = System::new();
50 /// ```
51 pub fn new() -> Self {
52 Self::new_with_specifics(RefreshKind::nothing())
53 }
54
55 /// Creates a new [`System`] instance with everything loaded.
56 ///
57 /// It is an equivalent of [`System::new_with_specifics`]`(`[`RefreshKind::everything`]`())`.
58 ///
59 /// [`System`]: crate::System
60 ///
61 /// ```no_run
62 /// use sysinfo::System;
63 ///
64 /// let s = System::new_all();
65 /// ```
66 pub fn new_all() -> Self {
67 Self::new_with_specifics(RefreshKind::everything())
68 }
69
70 /// Creates a new [`System`] instance and refresh the data corresponding to the
71 /// given [`RefreshKind`].
72 ///
73 /// [`System`]: crate::System
74 ///
75 /// ```
76 /// use sysinfo::{ProcessRefreshKind, RefreshKind, System};
77 ///
78 /// // We want to only refresh processes.
79 /// let mut system = System::new_with_specifics(
80 /// RefreshKind::nothing().with_processes(ProcessRefreshKind::everything()),
81 /// );
82 ///
83 /// # if sysinfo::IS_SUPPORTED_SYSTEM && !cfg!(feature = "apple-sandbox") {
84 /// assert!(!system.processes().is_empty());
85 /// # }
86 /// ```
87 pub fn new_with_specifics(refreshes: RefreshKind) -> Self {
88 let mut s = Self {
89 inner: SystemInner::new(),
90 };
91 s.refresh_specifics(refreshes);
92 s
93 }
94
95 /// Refreshes according to the given [`RefreshKind`]. It calls the corresponding
96 /// "refresh_" methods.
97 ///
98 /// It will remove dead processes if [`RefreshKind::processes`] returns `Some`.
99 /// If you want to keep dead processes, use [`System::refresh_processes_specifics`]
100 /// directly.
101 ///
102 /// ```
103 /// use sysinfo::{ProcessRefreshKind, RefreshKind, System};
104 ///
105 /// let mut s = System::new_all();
106 ///
107 /// // Let's just update processes:
108 /// s.refresh_specifics(
109 /// RefreshKind::nothing().with_processes(ProcessRefreshKind::everything()),
110 /// );
111 /// ```
112 pub fn refresh_specifics(&mut self, refreshes: RefreshKind) {
113 if let Some(kind) = refreshes.memory() {
114 self.refresh_memory_specifics(kind);
115 }
116 if let Some(kind) = refreshes.cpu() {
117 self.refresh_cpu_specifics(kind);
118 }
119 if let Some(kind) = refreshes.processes() {
120 self.refresh_processes_specifics(ProcessesToUpdate::All, true, kind);
121 }
122 }
123
124 /// Refreshes all system and processes information.
125 ///
126 /// It is the same as calling `system.refresh_specifics(RefreshKind::everything())`.
127 ///
128 /// Don't forget to take a look at [`ProcessRefreshKind::everything`] method to see what it
129 /// will update for processes more in details.
130 ///
131 /// It will remove dead processes. If you want to keep dead processes, use
132 /// [`System::refresh_processes_specifics`] directly.
133 ///
134 /// ```no_run
135 /// use sysinfo::System;
136 ///
137 /// let mut s = System::new();
138 /// s.refresh_all();
139 /// ```
140 pub fn refresh_all(&mut self) {
141 self.refresh_specifics(RefreshKind::everything());
142 }
143
144 /// Refreshes RAM and SWAP usage.
145 ///
146 /// It is the same as calling `system.refresh_memory_specifics(MemoryRefreshKind::everything())`.
147 ///
148 /// If you don't want to refresh both, take a look at [`System::refresh_memory_specifics`].
149 ///
150 /// ```no_run
151 /// use sysinfo::System;
152 ///
153 /// let mut s = System::new();
154 /// s.refresh_memory();
155 /// ```
156 pub fn refresh_memory(&mut self) {
157 self.refresh_memory_specifics(MemoryRefreshKind::everything())
158 }
159
160 /// Refreshes system memory specific information.
161 ///
162 /// ```no_run
163 /// use sysinfo::{MemoryRefreshKind, System};
164 ///
165 /// let mut s = System::new();
166 /// s.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
167 /// ```
168 pub fn refresh_memory_specifics(&mut self, refresh_kind: MemoryRefreshKind) {
169 self.inner.refresh_memory_specifics(refresh_kind)
170 }
171
172 /// Refreshes CPUs usage.
173 ///
174 /// ⚠️ Please note that the result will very likely be inaccurate at the first call.
175 /// You need to call this method at least twice (with a bit of time between each call, like
176 /// 200 ms, take a look at [`MINIMUM_CPU_UPDATE_INTERVAL`] for more information)
177 /// to get accurate value as it uses previous results to compute the next value.
178 ///
179 /// Calling this method is the same as calling
180 /// `system.refresh_cpu_specifics(CpuRefreshKind::nothing().with_cpu_usage())`.
181 ///
182 /// ```no_run
183 /// use sysinfo::System;
184 ///
185 /// let mut s = System::new_all();
186 /// // Wait a bit because CPU usage is based on diff.
187 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
188 /// // Refresh CPUs again.
189 /// s.refresh_cpu_usage();
190 /// ```
191 ///
192 /// [`MINIMUM_CPU_UPDATE_INTERVAL`]: crate::MINIMUM_CPU_UPDATE_INTERVAL
193 pub fn refresh_cpu_usage(&mut self) {
194 self.refresh_cpu_specifics(CpuRefreshKind::nothing().with_cpu_usage())
195 }
196
197 /// Refreshes CPUs frequency information.
198 ///
199 /// Calling this method is the same as calling
200 /// `system.refresh_cpu_specifics(CpuRefreshKind::nothing().with_frequency())`.
201 ///
202 /// ```no_run
203 /// use sysinfo::System;
204 ///
205 /// let mut s = System::new_all();
206 /// s.refresh_cpu_frequency();
207 /// ```
208 pub fn refresh_cpu_frequency(&mut self) {
209 self.refresh_cpu_specifics(CpuRefreshKind::nothing().with_frequency())
210 }
211
212 /// Refreshes the list of CPU.
213 ///
214 /// Normally, this should almost never be needed as it's pretty rare for a computer
215 /// to add a CPU while running, but it's possible on some computers which shutdown
216 /// CPU if the load is low enough.
217 ///
218 /// The `refresh_kind` argument tells what information you want to be retrieved
219 /// for each CPU.
220 ///
221 /// ```no_run
222 /// use sysinfo::{CpuRefreshKind, System};
223 ///
224 /// let mut s = System::new_all();
225 /// // We already have the list of CPU filled, but we want to recompute it
226 /// // in case new CPUs were added.
227 /// s.refresh_cpu_list(CpuRefreshKind::everything());
228 /// ```
229 pub fn refresh_cpu_list(&mut self, refresh_kind: CpuRefreshKind) {
230 self.inner.refresh_cpu_list(refresh_kind);
231 }
232
233 /// Refreshes all information related to CPUs information.
234 ///
235 /// If you only want the CPU usage, use [`System::refresh_cpu_usage`] instead.
236 ///
237 /// ⚠️ Please note that the result will be inaccurate at the first call.
238 /// You need to call this method at least twice (with a bit of time between each call, like
239 /// 200 ms, take a look at [`MINIMUM_CPU_UPDATE_INTERVAL`] for more information)
240 /// to get accurate value as it uses previous results to compute the next value.
241 ///
242 /// Calling this method is the same as calling
243 /// `system.refresh_cpu_specifics(CpuRefreshKind::everything())`.
244 ///
245 /// ```no_run
246 /// use sysinfo::System;
247 ///
248 /// let mut s = System::new_all();
249 /// s.refresh_cpu_all();
250 /// ```
251 ///
252 /// [`MINIMUM_CPU_UPDATE_INTERVAL`]: crate::MINIMUM_CPU_UPDATE_INTERVAL
253 pub fn refresh_cpu_all(&mut self) {
254 self.refresh_cpu_specifics(CpuRefreshKind::everything())
255 }
256
257 /// Refreshes CPUs specific information.
258 ///
259 /// ```no_run
260 /// use sysinfo::{System, CpuRefreshKind};
261 ///
262 /// let mut s = System::new_all();
263 /// s.refresh_cpu_specifics(CpuRefreshKind::everything());
264 /// ```
265 pub fn refresh_cpu_specifics(&mut self, refresh_kind: CpuRefreshKind) {
266 self.inner.refresh_cpu_specifics(refresh_kind)
267 }
268
269 /// Gets all processes and updates their information, along with all the tasks each process has.
270 ///
271 /// It does the same as:
272 ///
273 /// ```no_run
274 /// # use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind};
275 /// # let mut system = System::new();
276 /// system.refresh_processes_specifics(
277 /// ProcessesToUpdate::All,
278 /// true,
279 /// ProcessRefreshKind::nothing()
280 /// .with_memory()
281 /// .with_cpu()
282 /// .with_disk_usage()
283 /// .with_exe(UpdateKind::OnlyIfNotSet)
284 /// );
285 /// ```
286 ///
287 /// ⚠️ `remove_dead_processes` works as follows: if an updated process is dead, then it is
288 /// removed. So if you refresh pids 1, 2 and 3. If 2 and 7 are dead, only 2 will be removed
289 /// since 7 is not part of the update.
290 ///
291 /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour
292 /// by using [`set_open_files_limit`][crate::set_open_files_limit].
293 ///
294 /// ⚠️ On Linux, if you dont need the tasks of each process, you can use
295 /// `refresh_processes_specifics` with `ProcessRefreshKind::everything().without_tasks()`.
296 /// Refreshesing all processes and their tasks can be quite expensive. For more information
297 /// see [`ProcessRefreshKind`].
298 ///
299 /// Example:
300 ///
301 /// ```no_run
302 /// use sysinfo::{ProcessesToUpdate, System};
303 ///
304 /// let mut s = System::new_all();
305 /// s.refresh_processes(ProcessesToUpdate::All, true);
306 /// ```
307 pub fn refresh_processes(
308 &mut self,
309 processes_to_update: ProcessesToUpdate<'_>,
310 remove_dead_processes: bool,
311 ) -> usize {
312 self.refresh_processes_specifics(
313 processes_to_update,
314 remove_dead_processes,
315 ProcessRefreshKind::nothing()
316 .with_memory()
317 .with_cpu()
318 .with_disk_usage()
319 .with_exe(UpdateKind::OnlyIfNotSet)
320 .with_tasks(),
321 )
322 }
323
324 /// Gets all processes and updates the specified information.
325 ///
326 /// Returns the number of updated processes.
327 ///
328 /// ⚠️ `remove_dead_processes` works as follows: if an updated process is dead, then it is
329 /// removed. So if you refresh pids 1, 2 and 3. If 2 and 7 are dead, only 2 will be removed
330 /// since 7 is not part of the update.
331 ///
332 /// ⚠️ On Linux, `sysinfo` keeps the `stat` files open by default. You can change this behaviour
333 /// by using [`set_open_files_limit`][crate::set_open_files_limit].
334 ///
335 /// ```no_run
336 /// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System};
337 ///
338 /// let mut s = System::new_all();
339 /// s.refresh_processes_specifics(
340 /// ProcessesToUpdate::All,
341 /// true,
342 /// ProcessRefreshKind::everything(),
343 /// );
344 /// ```
345 pub fn refresh_processes_specifics(
346 &mut self,
347 processes_to_update: ProcessesToUpdate<'_>,
348 remove_dead_processes: bool,
349 refresh_kind: ProcessRefreshKind,
350 ) -> usize {
351 fn update_and_remove(pid: &Pid, processes: &mut HashMap<Pid, Process>) {
352 let updated = if let Some(proc) = processes.get_mut(pid) {
353 proc.inner.switch_updated()
354 } else {
355 return;
356 };
357 if !updated {
358 processes.remove(pid);
359 }
360 }
361 fn update(pid: &Pid, processes: &mut HashMap<Pid, Process>) {
362 if let Some(proc) = processes.get_mut(pid) {
363 if !proc.inner.switch_updated() {
364 proc.inner.set_nonexistent();
365 }
366 }
367 }
368
369 let nb_updated = self
370 .inner
371 .refresh_processes_specifics(processes_to_update, refresh_kind);
372 let processes = self.inner.processes_mut();
373 match processes_to_update {
374 ProcessesToUpdate::All => {
375 if remove_dead_processes {
376 processes.retain(|_, v| v.inner.switch_updated());
377 } else {
378 for proc in processes.values_mut() {
379 proc.inner.switch_updated();
380 }
381 }
382 }
383 ProcessesToUpdate::Some(pids) => {
384 let call = if remove_dead_processes {
385 update_and_remove
386 } else {
387 update
388 };
389 for pid in pids {
390 call(pid, processes);
391 }
392 }
393 }
394 nb_updated
395 }
396
397 /// Returns the process list.
398 ///
399 /// ```no_run
400 /// use sysinfo::System;
401 ///
402 /// let s = System::new_all();
403 /// for (pid, process) in s.processes() {
404 /// println!("{} {:?}", pid, process.name());
405 /// }
406 /// ```
407 pub fn processes(&self) -> &HashMap<Pid, Process> {
408 self.inner.processes()
409 }
410
411 /// Returns the process corresponding to the given `pid` or `None` if no such process exists.
412 ///
413 /// ```no_run
414 /// use sysinfo::{Pid, System};
415 ///
416 /// let s = System::new_all();
417 /// if let Some(process) = s.process(Pid::from(1337)) {
418 /// println!("{:?}", process.name());
419 /// }
420 /// ```
421 pub fn process(&self, pid: Pid) -> Option<&Process> {
422 self.inner.process(pid)
423 }
424
425 /// Returns an iterator of process containing the given `name`.
426 ///
427 /// If you want only the processes with exactly the given `name`, take a look at
428 /// [`System::processes_by_exact_name`].
429 ///
430 /// **⚠️ Important ⚠️**
431 ///
432 /// On **Linux**, there are two things to know about processes' name:
433 /// 1. It is limited to 15 characters.
434 /// 2. It is not always the exe name.
435 ///
436 /// ```no_run
437 /// use sysinfo::System;
438 ///
439 /// let s = System::new_all();
440 /// for process in s.processes_by_name("htop".as_ref()) {
441 /// println!("{} {:?}", process.pid(), process.name());
442 /// }
443 /// ```
444 pub fn processes_by_name<'a: 'b, 'b>(
445 &'a self,
446 name: &'b OsStr,
447 ) -> impl Iterator<Item = &'a Process> + 'b {
448 let finder = memchr::memmem::Finder::new(name.as_encoded_bytes());
449 self.processes()
450 .values()
451 .filter(move |val: &&Process| finder.find(val.name().as_encoded_bytes()).is_some())
452 }
453
454 /// Returns an iterator of processes with exactly the given `name`.
455 ///
456 /// If you instead want the processes containing `name`, take a look at
457 /// [`System::processes_by_name`].
458 ///
459 /// **⚠️ Important ⚠️**
460 ///
461 /// On **Linux**, there are two things to know about processes' name:
462 /// 1. It is limited to 15 characters.
463 /// 2. It is not always the exe name.
464 ///
465 /// ```no_run
466 /// use sysinfo::System;
467 ///
468 /// let s = System::new_all();
469 /// for process in s.processes_by_exact_name("htop".as_ref()) {
470 /// println!("{} {:?}", process.pid(), process.name());
471 /// }
472 /// ```
473 pub fn processes_by_exact_name<'a: 'b, 'b>(
474 &'a self,
475 name: &'b OsStr,
476 ) -> impl Iterator<Item = &'a Process> + 'b {
477 self.processes()
478 .values()
479 .filter(move |val: &&Process| val.name() == name)
480 }
481
482 /// Returns "global" CPUs usage (aka the addition of all the CPUs).
483 ///
484 /// To have up-to-date information, you need to call [`System::refresh_cpu_specifics`] or
485 /// [`System::refresh_specifics`] with `cpu` enabled.
486 ///
487 /// ```no_run
488 /// use sysinfo::{CpuRefreshKind, RefreshKind, System};
489 ///
490 /// let mut s = System::new_with_specifics(
491 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
492 /// );
493 /// // Wait a bit because CPU usage is based on diff.
494 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
495 /// // Refresh CPUs again to get actual value.
496 /// s.refresh_cpu_usage();
497 /// println!("{}%", s.global_cpu_usage());
498 /// ```
499 pub fn global_cpu_usage(&self) -> f32 {
500 self.inner.global_cpu_usage()
501 }
502
503 /// Returns the list of the CPUs.
504 ///
505 /// By default, the list of CPUs is empty until you call [`System::refresh_cpu_specifics`] or
506 /// [`System::refresh_specifics`] with `cpu` enabled.
507 ///
508 /// ```no_run
509 /// use sysinfo::{CpuRefreshKind, RefreshKind, System};
510 ///
511 /// let mut s = System::new_with_specifics(
512 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
513 /// );
514 /// // Wait a bit because CPU usage is based on diff.
515 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
516 /// // Refresh CPUs again to get actual value.
517 /// s.refresh_cpu_usage();
518 /// for cpu in s.cpus() {
519 /// println!("{}%", cpu.cpu_usage());
520 /// }
521 /// ```
522 pub fn cpus(&self) -> &[Cpu] {
523 self.inner.cpus()
524 }
525
526 /// Returns the RAM size in bytes.
527 ///
528 /// ```no_run
529 /// use sysinfo::System;
530 ///
531 /// let s = System::new_all();
532 /// println!("{} bytes", s.total_memory());
533 /// ```
534 ///
535 /// On Linux, if you want to see this information with the limit of your cgroup, take a look
536 /// at [`cgroup_limits`](System::cgroup_limits).
537 pub fn total_memory(&self) -> u64 {
538 self.inner.total_memory()
539 }
540
541 /// Returns the amount of free RAM in bytes.
542 ///
543 /// Generally, "free" memory refers to unallocated memory whereas "available" memory refers to
544 /// memory that is available for (re)use.
545 ///
546 /// Side note: Windows doesn't report "free" memory so this method returns the same value
547 /// as [`available_memory`](System::available_memory).
548 ///
549 /// ```no_run
550 /// use sysinfo::System;
551 ///
552 /// let s = System::new_all();
553 /// println!("{} bytes", s.free_memory());
554 /// ```
555 pub fn free_memory(&self) -> u64 {
556 self.inner.free_memory()
557 }
558
559 /// Returns the amount of available RAM in bytes.
560 ///
561 /// Generally, "free" memory refers to unallocated memory whereas "available" memory refers to
562 /// memory that is available for (re)use.
563 ///
564 /// ⚠️ Windows and FreeBSD don't report "available" memory so [`System::free_memory`]
565 /// returns the same value as this method.
566 ///
567 /// ```no_run
568 /// use sysinfo::System;
569 ///
570 /// let s = System::new_all();
571 /// println!("{} bytes", s.available_memory());
572 /// ```
573 pub fn available_memory(&self) -> u64 {
574 self.inner.available_memory()
575 }
576
577 /// Returns the amount of used RAM in bytes.
578 ///
579 /// ```no_run
580 /// use sysinfo::System;
581 ///
582 /// let s = System::new_all();
583 /// println!("{} bytes", s.used_memory());
584 /// ```
585 pub fn used_memory(&self) -> u64 {
586 self.inner.used_memory()
587 }
588
589 /// Returns the SWAP size in bytes.
590 ///
591 /// ```no_run
592 /// use sysinfo::System;
593 ///
594 /// let s = System::new_all();
595 /// println!("{} bytes", s.total_swap());
596 /// ```
597 pub fn total_swap(&self) -> u64 {
598 self.inner.total_swap()
599 }
600
601 /// Returns the amount of free SWAP in bytes.
602 ///
603 /// ```no_run
604 /// use sysinfo::System;
605 ///
606 /// let s = System::new_all();
607 /// println!("{} bytes", s.free_swap());
608 /// ```
609 pub fn free_swap(&self) -> u64 {
610 self.inner.free_swap()
611 }
612
613 /// Returns the amount of used SWAP in bytes.
614 ///
615 /// ```no_run
616 /// use sysinfo::System;
617 ///
618 /// let s = System::new_all();
619 /// println!("{} bytes", s.used_swap());
620 /// ```
621 pub fn used_swap(&self) -> u64 {
622 self.inner.used_swap()
623 }
624
625 /// Retrieves the limits for the current cgroup (if any), otherwise it returns `None`.
626 ///
627 /// This information is computed every time the method is called.
628 ///
629 /// ⚠️ You need to have run [`refresh_memory`](System::refresh_memory) at least once before
630 /// calling this method.
631 ///
632 /// ⚠️ This method is only implemented for Linux. It always returns `None` for all other
633 /// systems.
634 ///
635 /// ```no_run
636 /// use sysinfo::System;
637 ///
638 /// let s = System::new_all();
639 /// println!("limits: {:?}", s.cgroup_limits());
640 /// ```
641 pub fn cgroup_limits(&self) -> Option<CGroupLimits> {
642 self.inner.cgroup_limits()
643 }
644
645 /// Returns system uptime (in seconds).
646 ///
647 /// **Important**: this information is computed every time this function is called.
648 ///
649 /// ```no_run
650 /// use sysinfo::System;
651 ///
652 /// println!("System running since {} seconds", System::uptime());
653 /// ```
654 pub fn uptime() -> u64 {
655 SystemInner::uptime()
656 }
657
658 /// Returns the time (in seconds) when the system booted since UNIX epoch.
659 ///
660 /// **Important**: this information is computed every time this function is called.
661 ///
662 /// ```no_run
663 /// use sysinfo::System;
664 ///
665 /// println!("System booted at {} seconds", System::boot_time());
666 /// ```
667 pub fn boot_time() -> u64 {
668 SystemInner::boot_time()
669 }
670
671 /// Returns the system load average value.
672 ///
673 /// **Important**: this information is computed every time this function is called.
674 ///
675 /// ⚠️ This is currently not working on **Windows**.
676 ///
677 /// ```no_run
678 /// use sysinfo::System;
679 ///
680 /// let load_avg = System::load_average();
681 /// println!(
682 /// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%",
683 /// load_avg.one,
684 /// load_avg.five,
685 /// load_avg.fifteen,
686 /// );
687 /// ```
688 pub fn load_average() -> LoadAvg {
689 SystemInner::load_average()
690 }
691
692 /// Returns the system name.
693 ///
694 /// | example platform | value of `System::name()` |
695 /// |---|---|
696 /// | linux laptop | "Ubuntu" |
697 /// | android phone | "Pixel 9 Pro" |
698 /// | apple laptop | "Darwin" |
699 /// | windows server | "Windows" |
700 ///
701 /// **Important**: this information is computed every time this function is called.
702 ///
703 /// ```no_run
704 /// use sysinfo::System;
705 ///
706 /// println!("OS: {:?}", System::name());
707 /// ```
708 pub fn name() -> Option<String> {
709 SystemInner::name()
710 }
711
712 /// Returns the system's kernel version.
713 ///
714 /// | example platform | value of `System::kernel_version()` |
715 /// |---|---|
716 /// | linux laptop | "6.8.0-48-generic" |
717 /// | android phone | "6.1.84-android14-11" |
718 /// | apple laptop | "24.1.0" |
719 /// | windows server | "20348" |
720 ///
721 /// **Important**: this information is computed every time this function is called.
722 ///
723 /// ```no_run
724 /// use sysinfo::System;
725 ///
726 /// println!("kernel version: {:?}", System::kernel_version());
727 /// ```
728 pub fn kernel_version() -> Option<String> {
729 SystemInner::kernel_version()
730 }
731
732 /// Returns the system version (e.g. for macOS this will return 15.1 rather than the kernel
733 /// version).
734 ///
735 /// | example platform | value of `System::os_version()` |
736 /// |---|---|
737 /// | linux laptop | "24.04" |
738 /// | android phone | "15" |
739 /// | apple laptop | "15.1.1" |
740 /// | windows server | "10 (20348)" |
741 ///
742 /// **Important**: this information is computed every time this function is called.
743 ///
744 /// ```no_run
745 /// use sysinfo::System;
746 ///
747 /// println!("OS version: {:?}", System::os_version());
748 /// ```
749 pub fn os_version() -> Option<String> {
750 SystemInner::os_version()
751 }
752
753 /// Returns the system long os version.
754 ///
755 /// | example platform | value of `System::long_os_version()` |
756 /// |---|---|
757 /// | linux laptop | "Linux (Ubuntu 24.04)" |
758 /// | android phone | "Android 15 on Pixel 9 Pro" |
759 /// | apple laptop | "macOS 15.1.1 Sequoia" |
760 /// | windows server | "Windows Server 2022 Datacenter" |
761 ///
762 /// **Important**: this information is computed every time this function is called.
763 ///
764 /// ```no_run
765 /// use sysinfo::System;
766 ///
767 /// println!("Long OS Version: {:?}", System::long_os_version());
768 /// ```
769 pub fn long_os_version() -> Option<String> {
770 SystemInner::long_os_version()
771 }
772
773 /// Returns the distribution id as defined by os-release,
774 /// or [`std::env::consts::OS`].
775 ///
776 /// See also
777 /// - <https://www.freedesktop.org/software/systemd/man/os-release.html#ID=>
778 /// - <https://doc.rust-lang.org/std/env/consts/constant.OS.html>
779 ///
780 /// | example platform | value of `System::distribution_id()` |
781 /// |---|---|
782 /// | linux laptop | "ubuntu" |
783 /// | android phone | "android" |
784 /// | apple laptop | "macos" |
785 /// | windows server | "windows" |
786 ///
787 /// **Important**: this information is computed every time this function is called.
788 ///
789 /// ```no_run
790 /// use sysinfo::System;
791 ///
792 /// println!("Distribution ID: {:?}", System::distribution_id());
793 /// ```
794 pub fn distribution_id() -> String {
795 SystemInner::distribution_id()
796 }
797
798 /// Returns the distribution ids of operating systems that are closely
799 /// related to the local operating system in regards to packaging and
800 /// programming interfaces, for example listing one or more OS identifiers
801 /// the local OS is a derivative from.
802 ///
803 /// See also
804 /// - <https://www.freedesktop.org/software/systemd/man/latest/os-release.html#ID_LIKE=>
805 ///
806 /// | example platform | value of `System::distribution_id_like()` |
807 /// |---|---|
808 /// | android phone | [] |
809 /// | archlinux laptop | [] |
810 /// | centos server | ["rhel", "fedora"] |
811 /// | ubuntu laptop | ["debian"] |
812 /// | windows laptop | [] |
813 ///
814 /// **Important**: this information is computed every time this function is called.
815 ///
816 /// ```no_run
817 /// use sysinfo::System;
818 ///
819 /// println!("Distribution ID_LIKE: {:?}", System::distribution_id_like());
820 /// ```
821 pub fn distribution_id_like() -> Vec<String> {
822 SystemInner::distribution_id_like()
823 }
824
825 /// Provides kernel version following this string format:
826 ///
827 /// | Platform | Result |
828 /// |-|-|
829 /// | Windows | Windows OS Build 20348.2227 |
830 /// | Linux | Linux 6.12.13-200.fc41.x86_64 |
831 /// | Android | Android 612.13-200 |
832 /// | MacOS | Darwin 21.6.0 |
833 /// | FreeBSD | FreeBSD 199506 |
834 ///
835 /// If any of the information is not available, it will be replaced with "unknown".
836 ///
837 /// **Important**: this information is computed every time this function is called.
838 ///
839 /// ```no_run
840 /// use sysinfo::System;
841 ///
842 /// println!("Kernel long version: {}", System::kernel_long_version());
843 /// ```
844 ///
845 /// [distribution_id]: System::distribution_id
846 /// [kernel_version]: System::kernel_version
847 pub fn kernel_long_version() -> String {
848 let kernel_version = match System::kernel_version() {
849 None => "unknown".to_string(),
850 Some(s) => s,
851 };
852 let kernel_name = SystemInner::kernel_name().unwrap_or("Unknown");
853 if cfg!(windows) {
854 format!("{kernel_name} OS Build {kernel_version}")
855 } else {
856 format!("{kernel_name} {kernel_version}")
857 }
858 }
859
860 /// Returns the system hostname based off DNS.
861 ///
862 /// **Important**: this information is computed every time this function is called.
863 ///
864 /// ```no_run
865 /// use sysinfo::System;
866 ///
867 /// println!("Hostname: {:?}", System::host_name());
868 /// ```
869 pub fn host_name() -> Option<String> {
870 SystemInner::host_name()
871 }
872
873 /// Returns the CPU architecture (eg. x86, amd64, aarch64, ...).
874 ///
875 /// **Important**: this information is computed every time this function is called.
876 ///
877 /// ```no_run
878 /// use sysinfo::System;
879 ///
880 /// println!("CPU Architecture: {:?}", System::cpu_arch());
881 /// ```
882 pub fn cpu_arch() -> String {
883 SystemInner::cpu_arch().unwrap_or_else(|| std::env::consts::ARCH.to_owned())
884 }
885
886 /// Returns the number of physical cores on the CPU or `None` if it couldn't get it.
887 ///
888 /// In case there are multiple CPUs, it will combine the physical core count of all the CPUs.
889 ///
890 /// **Important**: this information is computed every time this function is called.
891 ///
892 /// ```no_run
893 /// use sysinfo::System;
894 ///
895 /// let s = System::new();
896 /// println!("{:?}", System::physical_core_count());
897 /// ```
898 pub fn physical_core_count() -> Option<usize> {
899 SystemInner::physical_core_count()
900 }
901
902 /// Returns the (default) maximum number of open files for a process.
903 ///
904 /// Returns `None` if it failed retrieving the information or if the current system is not
905 /// supported.
906 ///
907 /// **Important**: this information is computed every time this function is called.
908 ///
909 /// ```no_run
910 /// use sysinfo::System;
911 ///
912 /// println!("Max open files: {:?}", System::open_files_limit());
913 /// ```
914 pub fn open_files_limit() -> Option<usize> {
915 SystemInner::open_files_limit()
916 }
917}
918
919/// A struct representing system load average value.
920///
921/// It is returned by [`System::load_average`][crate::System::load_average].
922///
923/// ```no_run
924/// use sysinfo::System;
925///
926/// let load_avg = System::load_average();
927/// println!(
928/// "one minute: {}%, five minutes: {}%, fifteen minutes: {}%",
929/// load_avg.one,
930/// load_avg.five,
931/// load_avg.fifteen,
932/// );
933/// ```
934#[repr(C)]
935#[derive(Default, Debug, Clone)]
936pub struct LoadAvg {
937 /// Average load within one minute.
938 pub one: f64,
939 /// Average load within five minutes.
940 pub five: f64,
941 /// Average load within fifteen minutes.
942 pub fifteen: f64,
943}
944
945/// An enum representing signals on UNIX-like systems.
946///
947/// On non-unix systems, this enum is mostly useless and is only there to keep coherency between
948/// the different OSes.
949///
950/// If you want the list of the supported signals on the current system, use
951/// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
952#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
953#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
954pub enum Signal {
955 /// Hangup detected on controlling terminal or death of controlling process.
956 Hangup,
957 /// Interrupt from keyboard.
958 Interrupt,
959 /// Quit from keyboard.
960 Quit,
961 /// Illegal instruction.
962 Illegal,
963 /// Trace/breakpoint trap.
964 Trap,
965 /// Abort signal from C abort function.
966 Abort,
967 /// IOT trap. A synonym for SIGABRT.
968 IOT,
969 /// Bus error (bad memory access).
970 Bus,
971 /// Floating point exception.
972 FloatingPointException,
973 /// Kill signal.
974 Kill,
975 /// User-defined signal 1.
976 User1,
977 /// Invalid memory reference.
978 Segv,
979 /// User-defined signal 2.
980 User2,
981 /// Broken pipe: write to pipe with no readers.
982 Pipe,
983 /// Timer signal from C alarm function.
984 Alarm,
985 /// Termination signal.
986 Term,
987 /// Child stopped or terminated.
988 Child,
989 /// Continue if stopped.
990 Continue,
991 /// Stop process.
992 Stop,
993 /// Stop typed at terminal.
994 TSTP,
995 /// Terminal input for background process.
996 TTIN,
997 /// Terminal output for background process.
998 TTOU,
999 /// Urgent condition on socket.
1000 Urgent,
1001 /// CPU time limit exceeded.
1002 XCPU,
1003 /// File size limit exceeded.
1004 XFSZ,
1005 /// Virtual alarm clock.
1006 VirtualAlarm,
1007 /// Profiling time expired.
1008 Profiling,
1009 /// Windows resize signal.
1010 Winch,
1011 /// I/O now possible.
1012 IO,
1013 /// Pollable event (Sys V). Synonym for IO
1014 Poll,
1015 /// Power failure (System V).
1016 ///
1017 /// Doesn't exist on apple systems so will be ignored.
1018 Power,
1019 /// Bad argument to routine (SVr4).
1020 Sys,
1021}
1022
1023impl std::fmt::Display for Signal {
1024 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1025 let s = match *self {
1026 Self::Hangup => "Hangup",
1027 Self::Interrupt => "Interrupt",
1028 Self::Quit => "Quit",
1029 Self::Illegal => "Illegal",
1030 Self::Trap => "Trap",
1031 Self::Abort => "Abort",
1032 Self::IOT => "IOT",
1033 Self::Bus => "Bus",
1034 Self::FloatingPointException => "FloatingPointException",
1035 Self::Kill => "Kill",
1036 Self::User1 => "User1",
1037 Self::Segv => "Segv",
1038 Self::User2 => "User2",
1039 Self::Pipe => "Pipe",
1040 Self::Alarm => "Alarm",
1041 Self::Term => "Term",
1042 Self::Child => "Child",
1043 Self::Continue => "Continue",
1044 Self::Stop => "Stop",
1045 Self::TSTP => "TSTP",
1046 Self::TTIN => "TTIN",
1047 Self::TTOU => "TTOU",
1048 Self::Urgent => "Urgent",
1049 Self::XCPU => "XCPU",
1050 Self::XFSZ => "XFSZ",
1051 Self::VirtualAlarm => "VirtualAlarm",
1052 Self::Profiling => "Profiling",
1053 Self::Winch => "Winch",
1054 Self::IO => "IO",
1055 Self::Poll => "Poll",
1056 Self::Power => "Power",
1057 Self::Sys => "Sys",
1058 };
1059 f.write_str(s)
1060 }
1061}
1062
1063/// Contains memory limits for the current process.
1064#[derive(Default, Debug, Clone)]
1065pub struct CGroupLimits {
1066 /// Total memory (in bytes) for the current cgroup.
1067 pub total_memory: u64,
1068 /// Free memory (in bytes) for the current cgroup.
1069 pub free_memory: u64,
1070 /// Free swap (in bytes) for the current cgroup.
1071 pub free_swap: u64,
1072 /// Resident Set Size (RSS) (in bytes) for the current cgroup.
1073 pub rss: u64,
1074}
1075
1076/// Enum describing the different status of a process.
1077#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
1078#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1079pub enum ProcessStatus {
1080 /// ## Linux
1081 ///
1082 /// Idle kernel thread.
1083 ///
1084 /// ## macOs/FreeBSD
1085 ///
1086 /// Process being created by fork.
1087 ///
1088 /// ## Other OS
1089 ///
1090 /// Not available.
1091 Idle,
1092 /// Running.
1093 Run,
1094 /// ## Linux
1095 ///
1096 /// Sleeping in an interruptible waiting.
1097 ///
1098 /// ## macOS/FreeBSD
1099 ///
1100 /// Sleeping on an address.
1101 ///
1102 /// ## Other OS
1103 ///
1104 /// Not available.
1105 Sleep,
1106 /// ## Linux
1107 ///
1108 /// Stopped (on a signal) or (before Linux 2.6.33) trace stopped.
1109 ///
1110 /// ## macOS/FreeBSD
1111 ///
1112 /// Process debugging or suspension.
1113 ///
1114 /// ## Other OS
1115 ///
1116 /// Not available.
1117 Stop,
1118 /// ## Linux/FreeBSD/macOS
1119 ///
1120 /// Zombie process. Terminated but not reaped by its parent.
1121 ///
1122 /// ## Other OS
1123 ///
1124 /// Not available.
1125 Zombie,
1126 /// ## Linux
1127 ///
1128 /// Tracing stop (Linux 2.6.33 onward). Stopped by debugger during the tracing.
1129 ///
1130 /// ## Other OS
1131 ///
1132 /// Not available.
1133 Tracing,
1134 /// ## Linux
1135 ///
1136 /// Dead/uninterruptible sleep (usually IO).
1137 ///
1138 /// ## FreeBSD
1139 ///
1140 /// A process should never end up in this state.
1141 ///
1142 /// ## Other OS
1143 ///
1144 /// Not available.
1145 Dead,
1146 /// ## Linux
1147 ///
1148 /// Wakekill (Linux 2.6.33 to 3.13 only).
1149 ///
1150 /// ## Other OS
1151 ///
1152 /// Not available.
1153 Wakekill,
1154 /// ## Linux
1155 ///
1156 /// Waking (Linux 2.6.33 to 3.13 only).
1157 ///
1158 /// ## Other OS
1159 ///
1160 /// Not available.
1161 Waking,
1162 /// ## Linux
1163 ///
1164 /// Parked (Linux 3.9 to 3.13 only).
1165 ///
1166 /// ## macOS
1167 ///
1168 /// Halted at a clean point.
1169 ///
1170 /// ## Other OS
1171 ///
1172 /// Not available.
1173 Parked,
1174 /// ## FreeBSD
1175 ///
1176 /// Blocked on a lock.
1177 ///
1178 /// ## Other OS
1179 ///
1180 /// Not available.
1181 LockBlocked,
1182 /// ## Linux
1183 ///
1184 /// Waiting in uninterruptible disk sleep.
1185 ///
1186 /// ## Other OS
1187 ///
1188 /// Not available.
1189 UninterruptibleDiskSleep,
1190 /// Unknown.
1191 Unknown(u32),
1192}
1193
1194/// Enum describing the different kind of threads.
1195#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1196#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1197pub enum ThreadKind {
1198 /// Kernel thread.
1199 Kernel,
1200 /// User thread.
1201 Userland,
1202}
1203
1204/// Enum describing possible [`Process::kill_and_wait`] errors.
1205#[derive(Clone, Copy, Debug, PartialEq, Eq)]
1206#[cfg_attr(feature = "serde", derive(serde::Deserialize))]
1207pub enum KillError {
1208 /// This signal doesn't exist on this platform.
1209 SignalDoesNotExist,
1210 /// The signal failed to be sent to the target process.
1211 FailedToSendSignal,
1212}
1213
1214/// Struct containing information of a process.
1215///
1216/// ## iOS
1217///
1218/// This information cannot be retrieved on iOS due to sandboxing.
1219///
1220/// ## Apple app store
1221///
1222/// If you are building a macOS Apple app store, it won't be able
1223/// to retrieve this information.
1224///
1225/// ```no_run
1226/// use sysinfo::{Pid, System};
1227///
1228/// let s = System::new_all();
1229/// if let Some(process) = s.process(Pid::from(1337)) {
1230/// println!("{:?}", process.name());
1231/// }
1232/// ```
1233pub struct Process {
1234 pub(crate) inner: ProcessInner,
1235}
1236
1237impl Process {
1238 /// Sends [`Signal::Kill`] to the process (which is the only signal supported on all supported
1239 /// platforms by this crate).
1240 ///
1241 /// Returns `true` if the signal was sent successfully. If you want to wait for this process
1242 /// to end, you can use [`Process::wait`] or directly [`Process::kill_and_wait`].
1243 ///
1244 /// ⚠️ Even if this function returns `true`, it doesn't necessarily mean that the process will
1245 /// be killed. It just means that the signal was sent successfully.
1246 ///
1247 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1248 /// levels than the current process for example.
1249 ///
1250 /// If you want to use another signal, take a look at [`Process::kill_with`].
1251 ///
1252 /// To get the list of the supported signals on this system, use
1253 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1254 ///
1255 /// ```no_run
1256 /// use sysinfo::{Pid, System};
1257 ///
1258 /// let s = System::new_all();
1259 /// if let Some(process) = s.process(Pid::from(1337)) {
1260 /// process.kill();
1261 /// }
1262 /// ```
1263 pub fn kill(&self) -> bool {
1264 self.kill_with(Signal::Kill).unwrap_or(false)
1265 }
1266
1267 /// Sends the given `signal` to the process. If the signal doesn't exist on this platform,
1268 /// it'll do nothing and will return `None`. Otherwise it'll return `Some(bool)`. The boolean
1269 /// value will depend on whether or not the signal was sent successfully.
1270 ///
1271 /// If you just want to kill the process, use [`Process::kill`] directly. If you want to wait
1272 /// for this process to end, you can use [`Process::wait`] or [`Process::kill_with_and_wait`].
1273 ///
1274 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1275 /// levels than the current process for example.
1276 ///
1277 /// To get the list of the supported signals on this system, use
1278 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1279 ///
1280 /// ```no_run
1281 /// use sysinfo::{Pid, Signal, System};
1282 ///
1283 /// let s = System::new_all();
1284 /// if let Some(process) = s.process(Pid::from(1337)) {
1285 /// if process.kill_with(Signal::Kill).is_none() {
1286 /// println!("This signal isn't supported on this platform");
1287 /// }
1288 /// }
1289 /// ```
1290 pub fn kill_with(&self, signal: Signal) -> Option<bool> {
1291 self.inner.kill_with(signal)
1292 }
1293
1294 /// Sends [`Signal::Kill`] to the process then waits for its termination.
1295 ///
1296 /// Internally, this method is calling [`Process::kill`] then [`Process::wait`].
1297 ///
1298 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1299 /// levels than the current process for example. In this case, this method could enter an
1300 /// infinite loop.
1301 ///
1302 /// ```no_run
1303 /// use sysinfo::{Pid, System};
1304 ///
1305 /// let s = System::new_all();
1306 /// if let Some(process) = s.process(Pid::from(1337)) {
1307 /// if let Err(error) = process.kill_and_wait() {
1308 /// println!("`kill_and_wait` failed: {error:?}");
1309 /// }
1310 /// }
1311 /// ```
1312 pub fn kill_and_wait(&self) -> Result<Option<ExitStatus>, KillError> {
1313 self.kill_with_and_wait(Signal::Kill)
1314 }
1315
1316 /// Sends the given `signal` to the process.then waits for its termination.
1317 ///
1318 /// Internally, this method is calling [`Process::kill_with`] then [`Process::wait`].
1319 ///
1320 /// ⚠️ Please note that some processes might not be "killable", like if they run with higher
1321 /// levels than the current process for example. In this case, this method could enter an
1322 /// infinite loop.
1323 ///
1324 /// To get the list of the supported signals on this system, use
1325 /// [`SUPPORTED_SIGNALS`][crate::SUPPORTED_SIGNALS].
1326 ///
1327 /// ```no_run
1328 /// use sysinfo::{Pid, System};
1329 ///
1330 /// let s = System::new_all();
1331 /// if let Some(process) = s.process(Pid::from(1337)) {
1332 /// if let Err(error) = process.kill_and_wait() {
1333 /// println!("`kill_and_wait` failed: {error:?}");
1334 /// }
1335 /// }
1336 /// ```
1337 pub fn kill_with_and_wait(&self, signal: Signal) -> Result<Option<ExitStatus>, KillError> {
1338 match self.inner.kill_with(signal) {
1339 Some(sent) => {
1340 if !sent {
1341 return Err(KillError::FailedToSendSignal);
1342 }
1343 }
1344 None => return Err(KillError::SignalDoesNotExist),
1345 }
1346
1347 Ok(self.inner.wait())
1348 }
1349
1350 /// Wait for process termination and returns its [`ExitStatus`] if it could be retrieved,
1351 /// returns `None` otherwise.
1352 ///
1353 /// ```no_run
1354 /// use sysinfo::{Pid, System};
1355 ///
1356 /// let mut s = System::new_all();
1357 ///
1358 /// if let Some(process) = s.process(Pid::from(1337)) {
1359 /// println!("Waiting for pid 1337");
1360 /// let exit_status = process.wait();
1361 /// println!("Pid 1337 exited with: {exit_status:?}");
1362 /// }
1363 /// ```
1364 pub fn wait(&self) -> Option<ExitStatus> {
1365 self.inner.wait()
1366 }
1367
1368 /// Returns the name of the process.
1369 ///
1370 /// **⚠️ Important ⚠️**
1371 ///
1372 /// On **Linux**, there are two things to know about processes' name:
1373 /// 1. It is limited to 15 characters.
1374 /// 2. It is not always the exe name.
1375 ///
1376 /// If you are looking for a specific process, unless you know what you are
1377 /// doing, in most cases it's better to use [`Process::exe`] instead (which
1378 /// can be empty sometimes!).
1379 ///
1380 /// ```no_run
1381 /// use sysinfo::{Pid, System};
1382 ///
1383 /// let s = System::new_all();
1384 /// if let Some(process) = s.process(Pid::from(1337)) {
1385 /// println!("{:?}", process.name());
1386 /// }
1387 /// ```
1388 pub fn name(&self) -> &OsStr {
1389 self.inner.name()
1390 }
1391
1392 /// Returns the command line.
1393 ///
1394 /// **⚠️ Important ⚠️**
1395 ///
1396 /// On **Windows**, you might need to use `administrator` privileges when running your program
1397 /// to have access to this information.
1398 ///
1399 /// ```no_run
1400 /// use sysinfo::{Pid, System};
1401 ///
1402 /// let s = System::new_all();
1403 /// if let Some(process) = s.process(Pid::from(1337)) {
1404 /// println!("{:?}", process.cmd());
1405 /// }
1406 /// ```
1407 pub fn cmd(&self) -> &[OsString] {
1408 self.inner.cmd()
1409 }
1410
1411 /// Returns the path to the process.
1412 ///
1413 /// ```no_run
1414 /// use sysinfo::{Pid, System};
1415 ///
1416 /// let s = System::new_all();
1417 /// if let Some(process) = s.process(Pid::from(1337)) {
1418 /// println!("{:?}", process.exe());
1419 /// }
1420 /// ```
1421 ///
1422 /// ### Implementation notes
1423 ///
1424 /// On Linux, this method will return an empty path if there
1425 /// was an error trying to read `/proc/<pid>/exe`. This can
1426 /// happen, for example, if the permission levels or UID namespaces
1427 /// between the caller and target processes are different.
1428 ///
1429 /// It is also the case that `cmd[0]` is _not_ usually a correct
1430 /// replacement for this.
1431 /// A process [may change its `cmd[0]` value](https://man7.org/linux/man-pages/man5/proc.5.html)
1432 /// freely, making this an untrustworthy source of information.
1433 pub fn exe(&self) -> Option<&Path> {
1434 self.inner.exe()
1435 }
1436
1437 /// Returns the PID of the process.
1438 ///
1439 /// ```no_run
1440 /// use sysinfo::{Pid, System};
1441 ///
1442 /// let s = System::new_all();
1443 /// if let Some(process) = s.process(Pid::from(1337)) {
1444 /// println!("{}", process.pid());
1445 /// }
1446 /// ```
1447 pub fn pid(&self) -> Pid {
1448 self.inner.pid()
1449 }
1450
1451 /// Returns the environment variables of the process.
1452 ///
1453 /// ```no_run
1454 /// use sysinfo::{Pid, System};
1455 ///
1456 /// let s = System::new_all();
1457 /// if let Some(process) = s.process(Pid::from(1337)) {
1458 /// println!("{:?}", process.environ());
1459 /// }
1460 /// ```
1461 pub fn environ(&self) -> &[OsString] {
1462 self.inner.environ()
1463 }
1464
1465 /// Returns the current working directory.
1466 ///
1467 /// ```no_run
1468 /// use sysinfo::{Pid, System};
1469 ///
1470 /// let s = System::new_all();
1471 /// if let Some(process) = s.process(Pid::from(1337)) {
1472 /// println!("{:?}", process.cwd());
1473 /// }
1474 /// ```
1475 pub fn cwd(&self) -> Option<&Path> {
1476 self.inner.cwd()
1477 }
1478
1479 /// Returns the path of the root directory.
1480 ///
1481 /// ```no_run
1482 /// use sysinfo::{Pid, System};
1483 ///
1484 /// let s = System::new_all();
1485 /// if let Some(process) = s.process(Pid::from(1337)) {
1486 /// println!("{:?}", process.root());
1487 /// }
1488 /// ```
1489 pub fn root(&self) -> Option<&Path> {
1490 self.inner.root()
1491 }
1492
1493 /// Returns the memory usage (in bytes).
1494 ///
1495 /// This method returns the [size of the resident set], that is, the amount of memory that the
1496 /// process allocated and which is currently mapped in physical RAM. It does not include memory
1497 /// that is swapped out, or, in some operating systems, that has been allocated but never used.
1498 ///
1499 /// Thus, it represents exactly the amount of physical RAM that the process is using at the
1500 /// present time, but it might not be a good indicator of the total memory that the process will
1501 /// be using over its lifetime. For that purpose, you can try and use
1502 /// [`virtual_memory`](Process::virtual_memory).
1503 ///
1504 /// ```no_run
1505 /// use sysinfo::{Pid, System};
1506 ///
1507 /// let s = System::new_all();
1508 /// if let Some(process) = s.process(Pid::from(1337)) {
1509 /// println!("{} bytes", process.memory());
1510 /// }
1511 /// ```
1512 ///
1513 /// [size of the resident set]: https://en.wikipedia.org/wiki/Resident_set_size
1514 pub fn memory(&self) -> u64 {
1515 self.inner.memory()
1516 }
1517
1518 /// Returns the virtual memory usage (in bytes).
1519 ///
1520 /// This method returns the [size of virtual memory], that is, the amount of memory that the
1521 /// process can access, whether it is currently mapped in physical RAM or not. It includes
1522 /// physical RAM, allocated but not used regions, swapped-out regions, and even memory
1523 /// associated with [memory-mapped files](https://en.wikipedia.org/wiki/Memory-mapped_file).
1524 ///
1525 /// This value has limitations though. Depending on the operating system and type of process,
1526 /// this value might be a good indicator of the total memory that the process will be using over
1527 /// its lifetime. However, for example, in the version 14 of macOS this value is in the order of
1528 /// the hundreds of gigabytes for every process, and thus not very informative. Moreover, if a
1529 /// process maps into memory a very large file, this value will increase accordingly, even if
1530 /// the process is not actively using the memory.
1531 ///
1532 /// ```no_run
1533 /// use sysinfo::{Pid, System};
1534 ///
1535 /// let s = System::new_all();
1536 /// if let Some(process) = s.process(Pid::from(1337)) {
1537 /// println!("{} bytes", process.virtual_memory());
1538 /// }
1539 /// ```
1540 ///
1541 /// [size of virtual memory]: https://en.wikipedia.org/wiki/Virtual_memory
1542 pub fn virtual_memory(&self) -> u64 {
1543 self.inner.virtual_memory()
1544 }
1545
1546 /// Returns the parent PID.
1547 ///
1548 /// ```no_run
1549 /// use sysinfo::{Pid, System};
1550 ///
1551 /// let s = System::new_all();
1552 /// if let Some(process) = s.process(Pid::from(1337)) {
1553 /// println!("{:?}", process.parent());
1554 /// }
1555 /// ```
1556 pub fn parent(&self) -> Option<Pid> {
1557 self.inner.parent()
1558 }
1559
1560 /// Returns the status of the process.
1561 ///
1562 /// ```no_run
1563 /// use sysinfo::{Pid, System};
1564 ///
1565 /// let s = System::new_all();
1566 /// if let Some(process) = s.process(Pid::from(1337)) {
1567 /// println!("{:?}", process.status());
1568 /// }
1569 /// ```
1570 pub fn status(&self) -> ProcessStatus {
1571 self.inner.status()
1572 }
1573
1574 /// Returns the time where the process was started (in seconds) from epoch.
1575 ///
1576 /// ```no_run
1577 /// use sysinfo::{Pid, System};
1578 ///
1579 /// let s = System::new_all();
1580 /// if let Some(process) = s.process(Pid::from(1337)) {
1581 /// println!("Started at {} seconds", process.start_time());
1582 /// }
1583 /// ```
1584 pub fn start_time(&self) -> u64 {
1585 self.inner.start_time()
1586 }
1587
1588 /// Returns for how much time the process has been running (in seconds).
1589 ///
1590 /// ```no_run
1591 /// use sysinfo::{Pid, System};
1592 ///
1593 /// let s = System::new_all();
1594 /// if let Some(process) = s.process(Pid::from(1337)) {
1595 /// println!("Running since {} seconds", process.run_time());
1596 /// }
1597 /// ```
1598 pub fn run_time(&self) -> u64 {
1599 self.inner.run_time()
1600 }
1601
1602 /// Returns the total CPU usage (in %). Notice that it might be bigger than
1603 /// 100 if run on a multi-core machine.
1604 ///
1605 /// If you want a value between 0% and 100%, divide the returned value by
1606 /// the number of CPUs.
1607 ///
1608 /// ⚠️ To start to have accurate CPU usage, a process needs to be refreshed
1609 /// **twice** because CPU usage computation is based on time diff (process
1610 /// time on a given time period divided by total system time on the same
1611 /// time period).
1612 ///
1613 /// ⚠️ If you want accurate CPU usage number, better leave a bit of time
1614 /// between two calls of this method (take a look at
1615 /// [`MINIMUM_CPU_UPDATE_INTERVAL`][crate::MINIMUM_CPU_UPDATE_INTERVAL] for
1616 /// more information).
1617 ///
1618 /// ```no_run
1619 /// use sysinfo::{Pid, ProcessesToUpdate, ProcessRefreshKind, System};
1620 ///
1621 /// let mut s = System::new_all();
1622 /// // Wait a bit because CPU usage is based on diff.
1623 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
1624 /// // Refresh CPU usage to get actual value.
1625 /// s.refresh_processes_specifics(
1626 /// ProcessesToUpdate::All,
1627 /// true,
1628 /// ProcessRefreshKind::nothing().with_cpu()
1629 /// );
1630 /// if let Some(process) = s.process(Pid::from(1337)) {
1631 /// println!("{}%", process.cpu_usage());
1632 /// }
1633 /// ```
1634 pub fn cpu_usage(&self) -> f32 {
1635 self.inner.cpu_usage()
1636 }
1637
1638 /// Returns the total accumulated CPU usage (in CPU-milliseconds). Note
1639 /// that it might be bigger than the total clock run time of a process if
1640 /// run on a multi-core machine.
1641 ///
1642 /// ```no_run
1643 /// use sysinfo::{Pid, System};
1644 ///
1645 /// let s = System::new_all();
1646 /// if let Some(process) = s.process(Pid::from(1337)) {
1647 /// println!("{}", process.accumulated_cpu_time());
1648 /// }
1649 /// ```
1650 pub fn accumulated_cpu_time(&self) -> u64 {
1651 self.inner.accumulated_cpu_time()
1652 }
1653
1654 /// Returns number of bytes read and written to disk.
1655 ///
1656 /// ⚠️ On Windows, this method actually returns **ALL** I/O read and
1657 /// written bytes.
1658 ///
1659 /// ⚠️ Files might be cached in memory by your OS, meaning that reading/writing them might not
1660 /// increase the `read_bytes`/`written_bytes` values. You can find more information about it
1661 /// in the `proc_pid_io` manual (`man proc_pid_io` on unix platforms).
1662 ///
1663 /// ```no_run
1664 /// use sysinfo::{Pid, System};
1665 ///
1666 /// let s = System::new_all();
1667 /// if let Some(process) = s.process(Pid::from(1337)) {
1668 /// let disk_usage = process.disk_usage();
1669 /// println!("read bytes : new/total => {}/{}",
1670 /// disk_usage.read_bytes,
1671 /// disk_usage.total_read_bytes,
1672 /// );
1673 /// println!("written bytes: new/total => {}/{}",
1674 /// disk_usage.written_bytes,
1675 /// disk_usage.total_written_bytes,
1676 /// );
1677 /// }
1678 /// ```
1679 pub fn disk_usage(&self) -> DiskUsage {
1680 self.inner.disk_usage()
1681 }
1682
1683 /// Returns the ID of the owner user of this process or `None` if this
1684 /// information couldn't be retrieved. If you want to get the [`User`] from
1685 /// it, take a look at [`Users::get_user_by_id`].
1686 ///
1687 /// [`User`]: crate::User
1688 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
1689 ///
1690 /// ```no_run
1691 /// use sysinfo::{Pid, System};
1692 ///
1693 /// let mut s = System::new_all();
1694 ///
1695 /// if let Some(process) = s.process(Pid::from(1337)) {
1696 /// println!("User id for process 1337: {:?}", process.user_id());
1697 /// }
1698 /// ```
1699 pub fn user_id(&self) -> Option<&Uid> {
1700 self.inner.user_id()
1701 }
1702
1703 /// Returns the user ID of the effective owner of this process or `None` if
1704 /// this information couldn't be retrieved. If you want to get the [`User`]
1705 /// from it, take a look at [`Users::get_user_by_id`].
1706 ///
1707 /// If you run something with `sudo`, the real user ID of the launched
1708 /// process will be the ID of the user you are logged in as but effective
1709 /// user ID will be `0` (i-e root).
1710 ///
1711 /// ⚠️ It always returns `None` on Windows.
1712 ///
1713 /// [`User`]: crate::User
1714 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
1715 ///
1716 /// ```no_run
1717 /// use sysinfo::{Pid, System};
1718 ///
1719 /// let mut s = System::new_all();
1720 ///
1721 /// if let Some(process) = s.process(Pid::from(1337)) {
1722 /// println!("User id for process 1337: {:?}", process.effective_user_id());
1723 /// }
1724 /// ```
1725 pub fn effective_user_id(&self) -> Option<&Uid> {
1726 self.inner.effective_user_id()
1727 }
1728
1729 /// Returns the process group ID of the process.
1730 ///
1731 /// ⚠️ It always returns `None` on Windows.
1732 ///
1733 /// ```no_run
1734 /// use sysinfo::{Pid, System};
1735 ///
1736 /// let mut s = System::new_all();
1737 ///
1738 /// if let Some(process) = s.process(Pid::from(1337)) {
1739 /// println!("Group ID for process 1337: {:?}", process.group_id());
1740 /// }
1741 /// ```
1742 pub fn group_id(&self) -> Option<Gid> {
1743 self.inner.group_id()
1744 }
1745
1746 /// Returns the effective group ID of the process.
1747 ///
1748 /// If you run something with `sudo`, the real group ID of the launched
1749 /// process will be the primary group ID you are logged in as but effective
1750 /// group ID will be `0` (i-e root).
1751 ///
1752 /// ⚠️ It always returns `None` on Windows.
1753 ///
1754 /// ```no_run
1755 /// use sysinfo::{Pid, System};
1756 ///
1757 /// let mut s = System::new_all();
1758 ///
1759 /// if let Some(process) = s.process(Pid::from(1337)) {
1760 /// println!("User id for process 1337: {:?}", process.effective_group_id());
1761 /// }
1762 /// ```
1763 pub fn effective_group_id(&self) -> Option<Gid> {
1764 self.inner.effective_group_id()
1765 }
1766
1767 /// Returns the session ID for the current process or `None` if it couldn't
1768 /// be retrieved.
1769 ///
1770 /// ⚠️ This information is computed every time this method is called.
1771 ///
1772 /// ```no_run
1773 /// use sysinfo::{Pid, System};
1774 ///
1775 /// let mut s = System::new_all();
1776 ///
1777 /// if let Some(process) = s.process(Pid::from(1337)) {
1778 /// println!("Session ID for process 1337: {:?}", process.session_id());
1779 /// }
1780 /// ```
1781 pub fn session_id(&self) -> Option<Pid> {
1782 self.inner.session_id()
1783 }
1784
1785 /// Tasks run by this process. If there are none, returns `None`.
1786 ///
1787 /// ⚠️ This method always returns `None` on other platforms than Linux.
1788 ///
1789 /// ```no_run
1790 /// use sysinfo::{Pid, System};
1791 ///
1792 /// let mut s = System::new_all();
1793 ///
1794 /// if let Some(process) = s.process(Pid::from(1337)) {
1795 /// if let Some(tasks) = process.tasks() {
1796 /// println!("Listing tasks for process {:?}", process.pid());
1797 /// for task_pid in tasks {
1798 /// if let Some(task) = s.process(*task_pid) {
1799 /// println!("Task {:?}: {:?}", task.pid(), task.name());
1800 /// }
1801 /// }
1802 /// }
1803 /// }
1804 /// ```
1805 pub fn tasks(&self) -> Option<&HashSet<Pid>> {
1806 cfg_if! {
1807 if #[cfg(all(
1808 any(target_os = "linux", target_os = "android"),
1809 not(feature = "unknown-ci")
1810 ))] {
1811 self.inner.tasks.as_ref()
1812 } else {
1813 None
1814 }
1815 }
1816 }
1817
1818 /// If the process is a thread, it'll return `Some` with the kind of thread it is. Returns
1819 /// `None` otherwise.
1820 ///
1821 /// ⚠️ This method always returns `None` on other platforms than Linux.
1822 ///
1823 /// ```no_run
1824 /// use sysinfo::System;
1825 ///
1826 /// let s = System::new_all();
1827 ///
1828 /// for (_, process) in s.processes() {
1829 /// if let Some(thread_kind) = process.thread_kind() {
1830 /// println!("Process {:?} is a {thread_kind:?} thread", process.pid());
1831 /// }
1832 /// }
1833 /// ```
1834 pub fn thread_kind(&self) -> Option<ThreadKind> {
1835 cfg_if! {
1836 if #[cfg(all(
1837 any(target_os = "linux", target_os = "android"),
1838 not(feature = "unknown-ci")
1839 ))] {
1840 self.inner.thread_kind()
1841 } else {
1842 None
1843 }
1844 }
1845 }
1846
1847 /// Returns `true` if the process doesn't exist anymore but was not yet removed from
1848 /// the processes list because the `remove_dead_processes` argument was set to `false`
1849 /// in methods like [`System::refresh_processes`].
1850 ///
1851 /// ```no_run
1852 /// use sysinfo::{ProcessesToUpdate, System};
1853 ///
1854 /// let mut s = System::new_all();
1855 /// // We set the `remove_dead_processes` to `false`.
1856 /// s.refresh_processes(ProcessesToUpdate::All, false);
1857 ///
1858 /// for (_, process) in s.processes() {
1859 /// println!(
1860 /// "Process {:?} {}",
1861 /// process.pid(),
1862 /// if process.exists() { "exists" } else { "doesn't exist" },
1863 /// );
1864 /// }
1865 /// ```
1866 pub fn exists(&self) -> bool {
1867 self.inner.exists()
1868 }
1869
1870 /// Returns the number of open files in the current process.
1871 ///
1872 /// Returns `None` if it failed retrieving the information or if the current system is not
1873 /// supported.
1874 ///
1875 /// **Important**: this information is computed every time this function is called.
1876 ///
1877 /// ```no_run
1878 /// use sysinfo::System;
1879 ///
1880 /// let s = System::new_all();
1881 ///
1882 /// for (_, process) in s.processes() {
1883 /// println!(
1884 /// "Process {:?} {:?}",
1885 /// process.pid(),
1886 /// process.open_files(),
1887 /// );
1888 /// }
1889 /// ```
1890 pub fn open_files(&self) -> Option<usize> {
1891 self.inner.open_files()
1892 }
1893
1894 /// Returns the maximum number of open files for the current process.
1895 ///
1896 /// Returns `None` if it failed retrieving the information or if the current system is not
1897 /// supported.
1898 ///
1899 /// **Important**: this information is computed every time this function is called.
1900 ///
1901 /// ```no_run
1902 /// use sysinfo::System;
1903 ///
1904 /// let s = System::new_all();
1905 ///
1906 /// for (_, process) in s.processes() {
1907 /// println!(
1908 /// "Process {:?} {:?}",
1909 /// process.pid(),
1910 /// process.open_files_limit(),
1911 /// );
1912 /// }
1913 /// ```
1914 pub fn open_files_limit(&self) -> Option<usize> {
1915 self.inner.open_files_limit()
1916 }
1917}
1918
1919macro_rules! pid_decl {
1920 ($typ:ty) => {
1921 #[doc = include_str!("../../md_doc/pid.md")]
1922 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1923 #[repr(transparent)]
1924 pub struct Pid(pub(crate) $typ);
1925
1926 impl From<usize> for Pid {
1927 fn from(v: usize) -> Self {
1928 Self(v as _)
1929 }
1930 }
1931 impl From<Pid> for usize {
1932 fn from(v: Pid) -> Self {
1933 v.0 as _
1934 }
1935 }
1936 impl FromStr for Pid {
1937 type Err = <$typ as FromStr>::Err;
1938 fn from_str(s: &str) -> Result<Self, Self::Err> {
1939 Ok(Self(<$typ>::from_str(s)?))
1940 }
1941 }
1942 impl fmt::Display for Pid {
1943 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1944 write!(f, "{}", self.0)
1945 }
1946 }
1947 impl Pid {
1948 /// Allows to convert [`Pid`][crate::Pid] into [`u32`].
1949 ///
1950 /// ```
1951 /// use sysinfo::Pid;
1952 ///
1953 /// let pid = Pid::from_u32(0);
1954 /// let value: u32 = pid.as_u32();
1955 /// ```
1956 pub fn as_u32(self) -> u32 {
1957 self.0 as _
1958 }
1959 /// Allows to convert a [`u32`] into [`Pid`][crate::Pid].
1960 ///
1961 /// ```
1962 /// use sysinfo::Pid;
1963 ///
1964 /// let pid = Pid::from_u32(0);
1965 /// ```
1966 pub fn from_u32(v: u32) -> Self {
1967 Self(v as _)
1968 }
1969 }
1970 };
1971}
1972
1973cfg_if! {
1974 if #[cfg(all(
1975 not(feature = "unknown-ci"),
1976 any(
1977 target_os = "freebsd",
1978 target_os = "linux",
1979 target_os = "android",
1980 target_os = "macos",
1981 target_os = "ios",
1982 )
1983 ))] {
1984 use libc::pid_t;
1985
1986 pid_decl!(pid_t);
1987 } else {
1988 pid_decl!(usize);
1989 }
1990}
1991
1992/// This enum allows you to specify when you want the related information to be updated.
1993///
1994/// For example if you only want the [`Process::exe()`] information to be refreshed only if it's not
1995/// already set:
1996///
1997/// ```no_run
1998/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind};
1999///
2000/// let mut system = System::new();
2001/// system.refresh_processes_specifics(
2002/// ProcessesToUpdate::All,
2003/// true,
2004/// ProcessRefreshKind::nothing().with_exe(UpdateKind::OnlyIfNotSet),
2005/// );
2006/// ```
2007#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2008pub enum UpdateKind {
2009 /// Never update the related information.
2010 #[default]
2011 Never,
2012 /// Always update the related information.
2013 Always,
2014 /// Only update the related information if it was not already set at least once.
2015 OnlyIfNotSet,
2016}
2017
2018impl UpdateKind {
2019 /// If `self` is `OnlyIfNotSet`, `f` is called and its returned value is returned.
2020 #[allow(dead_code)] // Needed for unsupported targets.
2021 pub(crate) fn needs_update(self, f: impl Fn() -> bool) -> bool {
2022 match self {
2023 Self::Never => false,
2024 Self::Always => true,
2025 Self::OnlyIfNotSet => f(),
2026 }
2027 }
2028}
2029
2030/// This enum allows you to specify if you want all processes to be updated or just
2031/// some of them.
2032///
2033/// Example:
2034///
2035/// ```no_run
2036/// use sysinfo::{ProcessesToUpdate, System, get_current_pid};
2037///
2038/// let mut system = System::new();
2039/// // To refresh all processes:
2040/// system.refresh_processes(ProcessesToUpdate::All, true);
2041///
2042/// // To refresh only the current one:
2043/// system.refresh_processes(
2044/// ProcessesToUpdate::Some(&[get_current_pid().unwrap()]),
2045/// true,
2046/// );
2047/// ```
2048#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2049pub enum ProcessesToUpdate<'a> {
2050 /// To refresh all processes.
2051 All,
2052 /// To refresh only the processes with the listed [`Pid`].
2053 ///
2054 /// [`Pid`]: crate::Pid
2055 Some(&'a [Pid]),
2056}
2057
2058/// Used to determine what you want to refresh specifically on the [`Process`] type.
2059///
2060/// When all refresh are ruled out, a [`Process`] will still retrieve the following information:
2061/// * Process ID ([`Pid`])
2062/// * Parent process ID (on Windows it never changes though)
2063/// * Process name
2064/// * Start time
2065///
2066/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2067/// the information won't be retrieved if the information is accessible without needing
2068/// extra computation.
2069///
2070/// ⚠️ ** Linux Specific ** ⚠️
2071/// When using `ProcessRefreshKind::everything()`, in linux we will fetch all relevant
2072/// information from `/proc/<pid>/` as well as all the information from `/proc/<pid>/task/<tid>/`
2073/// folders. This makes the refresh mechanism a lot slower depending on the number of tasks
2074/// each process has.
2075///
2076/// If you don't care about tasks information, use `ProcessRefreshKind::everything().without_tasks()`
2077/// as much as possible.
2078///
2079/// ```
2080/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System};
2081///
2082/// let mut system = System::new();
2083///
2084/// // We don't want to update the CPU information.
2085/// system.refresh_processes_specifics(
2086/// ProcessesToUpdate::All,
2087/// true,
2088/// ProcessRefreshKind::everything().without_cpu(),
2089/// );
2090///
2091/// for (_, proc_) in system.processes() {
2092/// // We use a `==` comparison on float only because we know it's set to 0 here.
2093/// assert_eq!(proc_.cpu_usage(), 0.);
2094/// }
2095/// ```
2096///
2097/// [`Process`]: crate::Process
2098#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2099pub struct ProcessRefreshKind {
2100 cpu: bool,
2101 disk_usage: bool,
2102 memory: bool,
2103 user: UpdateKind,
2104 cwd: UpdateKind,
2105 root: UpdateKind,
2106 environ: UpdateKind,
2107 cmd: UpdateKind,
2108 exe: UpdateKind,
2109 tasks: bool,
2110}
2111
2112/// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2113/// By default, we want to list all processes and tasks are considered processes on their own
2114/// in linux so we still fetch them by default. However, the processes information are not
2115/// refreshed.
2116impl Default for ProcessRefreshKind {
2117 fn default() -> Self {
2118 Self {
2119 cpu: false,
2120 disk_usage: false,
2121 memory: false,
2122 user: UpdateKind::default(),
2123 cwd: UpdateKind::default(),
2124 root: UpdateKind::default(),
2125 environ: UpdateKind::default(),
2126 cmd: UpdateKind::default(),
2127 exe: UpdateKind::default(),
2128 tasks: true, // Process by default includes all tasks.
2129 }
2130 }
2131}
2132
2133impl ProcessRefreshKind {
2134 /// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2135 /// By default, we want to list all processes and tasks are considered processes on their own
2136 /// in linux so we still fetch them by default. However, the processes information are not
2137 /// refreshed.
2138 /// ```
2139 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2140 ///
2141 /// let r = ProcessRefreshKind::nothing();
2142 ///
2143 /// assert_eq!(r.cpu(), false);
2144 /// assert_eq!(r.user(), UpdateKind::Never);
2145 /// ```
2146 pub fn nothing() -> Self {
2147 Self::default()
2148 }
2149
2150 /// Creates a new `ProcessRefreshKind` with every refresh set to `true` or
2151 /// [`UpdateKind::OnlyIfNotSet`].
2152 ///
2153 /// ```
2154 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2155 ///
2156 /// let r = ProcessRefreshKind::everything();
2157 ///
2158 /// assert_eq!(r.cpu(), true);
2159 /// assert_eq!(r.user(), UpdateKind::OnlyIfNotSet);
2160 /// ```
2161 pub fn everything() -> Self {
2162 Self {
2163 cpu: true,
2164 disk_usage: true,
2165 memory: true,
2166 user: UpdateKind::OnlyIfNotSet,
2167 cwd: UpdateKind::OnlyIfNotSet,
2168 root: UpdateKind::OnlyIfNotSet,
2169 environ: UpdateKind::OnlyIfNotSet,
2170 cmd: UpdateKind::OnlyIfNotSet,
2171 exe: UpdateKind::OnlyIfNotSet,
2172 tasks: true,
2173 }
2174 }
2175
2176 impl_get_set!(
2177 ProcessRefreshKind,
2178 cpu,
2179 with_cpu,
2180 without_cpu,
2181 "\
2182It will retrieve both CPU usage and CPU accumulated time,"
2183 );
2184 impl_get_set!(
2185 ProcessRefreshKind,
2186 disk_usage,
2187 with_disk_usage,
2188 without_disk_usage
2189 );
2190 impl_get_set!(
2191 ProcessRefreshKind,
2192 user,
2193 with_user,
2194 without_user,
2195 UpdateKind,
2196 "\
2197It will retrieve the following information:
2198
2199 * user ID
2200 * user effective ID (if available on the platform)
2201 * user group ID (if available on the platform)
2202 * user effective ID (if available on the platform)"
2203 );
2204 impl_get_set!(ProcessRefreshKind, memory, with_memory, without_memory);
2205 impl_get_set!(ProcessRefreshKind, cwd, with_cwd, without_cwd, UpdateKind);
2206 impl_get_set!(
2207 ProcessRefreshKind,
2208 root,
2209 with_root,
2210 without_root,
2211 UpdateKind
2212 );
2213 impl_get_set!(
2214 ProcessRefreshKind,
2215 environ,
2216 with_environ,
2217 without_environ,
2218 UpdateKind
2219 );
2220 impl_get_set!(ProcessRefreshKind, cmd, with_cmd, without_cmd, UpdateKind);
2221 impl_get_set!(ProcessRefreshKind, exe, with_exe, without_exe, UpdateKind);
2222 impl_get_set!(ProcessRefreshKind, tasks, with_tasks, without_tasks);
2223}
2224
2225/// Used to determine what you want to refresh specifically on the [`Cpu`] type.
2226///
2227/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2228/// the information won't be retrieved if the information is accessible without needing
2229/// extra computation.
2230///
2231/// ```
2232/// use sysinfo::{CpuRefreshKind, System};
2233///
2234/// let mut system = System::new();
2235///
2236/// // We don't want to update all the CPU information.
2237/// system.refresh_cpu_specifics(CpuRefreshKind::everything().without_frequency());
2238///
2239/// for cpu in system.cpus() {
2240/// assert_eq!(cpu.frequency(), 0);
2241/// }
2242/// ```
2243///
2244/// [`Cpu`]: crate::Cpu
2245#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2246pub struct CpuRefreshKind {
2247 cpu_usage: bool,
2248 frequency: bool,
2249}
2250
2251impl CpuRefreshKind {
2252 /// Creates a new `CpuRefreshKind` with every refresh set to `false`.
2253 ///
2254 /// ```
2255 /// use sysinfo::CpuRefreshKind;
2256 ///
2257 /// let r = CpuRefreshKind::nothing();
2258 ///
2259 /// assert_eq!(r.frequency(), false);
2260 /// assert_eq!(r.cpu_usage(), false);
2261 /// ```
2262 pub fn nothing() -> Self {
2263 Self::default()
2264 }
2265
2266 /// Creates a new `CpuRefreshKind` with every refresh set to `true`.
2267 ///
2268 /// ```
2269 /// use sysinfo::CpuRefreshKind;
2270 ///
2271 /// let r = CpuRefreshKind::everything();
2272 ///
2273 /// assert_eq!(r.frequency(), true);
2274 /// assert_eq!(r.cpu_usage(), true);
2275 /// ```
2276 pub fn everything() -> Self {
2277 Self {
2278 cpu_usage: true,
2279 frequency: true,
2280 }
2281 }
2282
2283 impl_get_set!(CpuRefreshKind, cpu_usage, with_cpu_usage, without_cpu_usage);
2284 impl_get_set!(CpuRefreshKind, frequency, with_frequency, without_frequency);
2285}
2286
2287/// Used to determine which memory you want to refresh specifically.
2288///
2289/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2290/// the information won't be retrieved if the information is accessible without needing
2291/// extra computation.
2292///
2293/// ```
2294/// use sysinfo::{MemoryRefreshKind, System};
2295///
2296/// let mut system = System::new();
2297///
2298/// // We don't want to update all memories information.
2299/// system.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
2300///
2301/// println!("total RAM: {}", system.total_memory());
2302/// println!("free RAM: {}", system.free_memory());
2303/// ```
2304#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2305pub struct MemoryRefreshKind {
2306 ram: bool,
2307 swap: bool,
2308}
2309
2310impl MemoryRefreshKind {
2311 /// Creates a new `MemoryRefreshKind` with every refresh set to `false`.
2312 ///
2313 /// ```
2314 /// use sysinfo::MemoryRefreshKind;
2315 ///
2316 /// let r = MemoryRefreshKind::nothing();
2317 ///
2318 /// assert_eq!(r.ram(), false);
2319 /// assert_eq!(r.swap(), false);
2320 /// ```
2321 pub fn nothing() -> Self {
2322 Self::default()
2323 }
2324
2325 /// Creates a new `MemoryRefreshKind` with every refresh set to `true`.
2326 ///
2327 /// ```
2328 /// use sysinfo::MemoryRefreshKind;
2329 ///
2330 /// let r = MemoryRefreshKind::everything();
2331 ///
2332 /// assert_eq!(r.ram(), true);
2333 /// assert_eq!(r.swap(), true);
2334 /// ```
2335 pub fn everything() -> Self {
2336 Self {
2337 ram: true,
2338 swap: true,
2339 }
2340 }
2341
2342 impl_get_set!(MemoryRefreshKind, ram, with_ram, without_ram);
2343 impl_get_set!(MemoryRefreshKind, swap, with_swap, without_swap);
2344}
2345
2346/// Used to determine what you want to refresh specifically on the [`System`][crate::System] type.
2347///
2348/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2349/// the information won't be retrieved if the information is accessible without needing
2350/// extra computation.
2351///
2352/// ```
2353/// use sysinfo::{RefreshKind, System};
2354///
2355/// // We want everything except memory.
2356/// let mut system = System::new_with_specifics(RefreshKind::everything().without_memory());
2357///
2358/// assert_eq!(system.total_memory(), 0);
2359/// # if sysinfo::IS_SUPPORTED_SYSTEM && !cfg!(feature = "apple-sandbox") {
2360/// assert!(system.processes().len() > 0);
2361/// # }
2362/// ```
2363#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2364pub struct RefreshKind {
2365 processes: Option<ProcessRefreshKind>,
2366 memory: Option<MemoryRefreshKind>,
2367 cpu: Option<CpuRefreshKind>,
2368}
2369
2370impl RefreshKind {
2371 /// Creates a new `RefreshKind` with every refresh set to `false`/`None`.
2372 ///
2373 /// ```
2374 /// use sysinfo::RefreshKind;
2375 ///
2376 /// let r = RefreshKind::nothing();
2377 ///
2378 /// assert_eq!(r.processes().is_some(), false);
2379 /// assert_eq!(r.memory().is_some(), false);
2380 /// assert_eq!(r.cpu().is_some(), false);
2381 /// ```
2382 pub fn nothing() -> Self {
2383 Self::default()
2384 }
2385
2386 /// Creates a new `RefreshKind` with every refresh set to `true`/`Some(...)`.
2387 ///
2388 /// ```
2389 /// use sysinfo::RefreshKind;
2390 ///
2391 /// let r = RefreshKind::everything();
2392 ///
2393 /// assert_eq!(r.processes().is_some(), true);
2394 /// assert_eq!(r.memory().is_some(), true);
2395 /// assert_eq!(r.cpu().is_some(), true);
2396 /// ```
2397 pub fn everything() -> Self {
2398 Self {
2399 processes: Some(ProcessRefreshKind::everything()),
2400 memory: Some(MemoryRefreshKind::everything()),
2401 cpu: Some(CpuRefreshKind::everything()),
2402 }
2403 }
2404
2405 impl_get_set!(
2406 RefreshKind,
2407 processes,
2408 with_processes,
2409 without_processes,
2410 ProcessRefreshKind
2411 );
2412 impl_get_set!(
2413 RefreshKind,
2414 memory,
2415 with_memory,
2416 without_memory,
2417 MemoryRefreshKind
2418 );
2419 impl_get_set!(RefreshKind, cpu, with_cpu, without_cpu, CpuRefreshKind);
2420}
2421
2422/// Returns the pid for the current process.
2423///
2424/// `Err` is returned in case the platform isn't supported.
2425///
2426/// ```no_run
2427/// use sysinfo::get_current_pid;
2428///
2429/// match get_current_pid() {
2430/// Ok(pid) => {
2431/// println!("current pid: {}", pid);
2432/// }
2433/// Err(e) => {
2434/// println!("failed to get current pid: {}", e);
2435/// }
2436/// }
2437/// ```
2438#[allow(clippy::unnecessary_wraps)]
2439pub fn get_current_pid() -> Result<Pid, &'static str> {
2440 cfg_if! {
2441 if #[cfg(feature = "unknown-ci")] {
2442 fn inner() -> Result<Pid, &'static str> {
2443 Err("Unknown platform (CI)")
2444 }
2445 } else if #[cfg(any(
2446 target_os = "freebsd",
2447 target_os = "linux",
2448 target_os = "android",
2449 target_os = "macos",
2450 target_os = "ios",
2451 ))] {
2452 fn inner() -> Result<Pid, &'static str> {
2453 unsafe { Ok(Pid(libc::getpid())) }
2454 }
2455 } else if #[cfg(windows)] {
2456 fn inner() -> Result<Pid, &'static str> {
2457 use windows::Win32::System::Threading::GetCurrentProcessId;
2458
2459 unsafe { Ok(Pid(GetCurrentProcessId() as _)) }
2460 }
2461 } else {
2462 fn inner() -> Result<Pid, &'static str> {
2463 Err("Unknown platform")
2464 }
2465 }
2466 }
2467 inner()
2468}
2469
2470/// Contains all the methods of the [`Cpu`][crate::Cpu] struct.
2471///
2472/// ```no_run
2473/// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2474///
2475/// let mut s = System::new_with_specifics(
2476/// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2477/// );
2478///
2479/// // Wait a bit because CPU usage is based on diff.
2480/// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2481/// // Refresh CPUs again to get actual value.
2482/// s.refresh_cpu_all();
2483///
2484/// for cpu in s.cpus() {
2485/// println!("{}%", cpu.cpu_usage());
2486/// }
2487/// ```
2488pub struct Cpu {
2489 pub(crate) inner: CpuInner,
2490}
2491
2492impl Cpu {
2493 /// Returns this CPU's usage.
2494 ///
2495 /// Note: You'll need to refresh it at least twice (diff between the first and the second is
2496 /// how CPU usage is computed) at first if you want to have a non-zero value.
2497 ///
2498 /// ```no_run
2499 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2500 ///
2501 /// let mut s = System::new_with_specifics(
2502 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2503 /// );
2504 ///
2505 /// // Wait a bit because CPU usage is based on diff.
2506 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2507 /// // Refresh CPUs again to get actual value.
2508 /// s.refresh_cpu_all();
2509 ///
2510 /// for cpu in s.cpus() {
2511 /// println!("{}%", cpu.cpu_usage());
2512 /// }
2513 /// ```
2514 pub fn cpu_usage(&self) -> f32 {
2515 self.inner.cpu_usage()
2516 }
2517
2518 /// Returns this CPU's name.
2519 ///
2520 /// ```no_run
2521 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2522 ///
2523 /// let s = System::new_with_specifics(
2524 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2525 /// );
2526 /// for cpu in s.cpus() {
2527 /// println!("{}", cpu.name());
2528 /// }
2529 /// ```
2530 pub fn name(&self) -> &str {
2531 self.inner.name()
2532 }
2533
2534 /// Returns the CPU's vendor id.
2535 ///
2536 /// ```no_run
2537 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2538 ///
2539 /// let s = System::new_with_specifics(
2540 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2541 /// );
2542 /// for cpu in s.cpus() {
2543 /// println!("{}", cpu.vendor_id());
2544 /// }
2545 /// ```
2546 pub fn vendor_id(&self) -> &str {
2547 self.inner.vendor_id()
2548 }
2549
2550 /// Returns the CPU's brand.
2551 ///
2552 /// ```no_run
2553 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2554 ///
2555 /// let s = System::new_with_specifics(
2556 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2557 /// );
2558 /// for cpu in s.cpus() {
2559 /// println!("{}", cpu.brand());
2560 /// }
2561 /// ```
2562 pub fn brand(&self) -> &str {
2563 self.inner.brand()
2564 }
2565
2566 /// Returns the CPU's frequency.
2567 ///
2568 /// ```no_run
2569 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2570 ///
2571 /// let s = System::new_with_specifics(
2572 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2573 /// );
2574 /// for cpu in s.cpus() {
2575 /// println!("{}", cpu.frequency());
2576 /// }
2577 /// ```
2578 pub fn frequency(&self) -> u64 {
2579 self.inner.frequency()
2580 }
2581}
2582
2583#[cfg(test)]
2584mod test {
2585 use crate::*;
2586 use std::str::FromStr;
2587
2588 // In case `Process::updated` is misused, `System::refresh_processes` might remove them
2589 // so this test ensures that it doesn't happen.
2590 #[test]
2591 fn check_refresh_process_update() {
2592 if !IS_SUPPORTED_SYSTEM {
2593 return;
2594 }
2595 let mut s = System::new_all();
2596 let total = s.processes().len() as isize;
2597 s.refresh_processes(ProcessesToUpdate::All, false);
2598 let new_total = s.processes().len() as isize;
2599 // There should be almost no difference in the processes count.
2600 assert!(
2601 (new_total - total).abs() <= 5,
2602 "{} <= 5",
2603 (new_total - total).abs()
2604 );
2605 }
2606
2607 #[test]
2608 fn check_cpu_arch() {
2609 assert!(!System::cpu_arch().is_empty());
2610 }
2611
2612 // Ensure that the CPUs frequency isn't retrieved until we ask for it.
2613 #[test]
2614 fn check_cpu_frequency() {
2615 if !IS_SUPPORTED_SYSTEM {
2616 return;
2617 }
2618 let mut s = System::new();
2619 s.refresh_processes(ProcessesToUpdate::All, false);
2620 for proc_ in s.cpus() {
2621 assert_eq!(proc_.frequency(), 0);
2622 }
2623 s.refresh_cpu_usage();
2624 for proc_ in s.cpus() {
2625 assert_eq!(proc_.frequency(), 0);
2626 }
2627 // In a VM, it'll fail.
2628 if std::env::var("APPLE_CI").is_err() && std::env::var("FREEBSD_CI").is_err() {
2629 s.refresh_cpu_specifics(CpuRefreshKind::everything());
2630 for proc_ in s.cpus() {
2631 assert_ne!(proc_.frequency(), 0);
2632 }
2633 }
2634 }
2635
2636 #[test]
2637 fn check_process_memory_usage() {
2638 let mut s = System::new();
2639 s.refresh_specifics(RefreshKind::everything());
2640
2641 if IS_SUPPORTED_SYSTEM {
2642 // No process should have 0 as memory usage.
2643 #[cfg(not(feature = "apple-sandbox"))]
2644 assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2645 } else {
2646 // There should be no process, but if there is one, its memory usage should be 0.
2647 assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2648 }
2649 }
2650
2651 #[test]
2652 fn check_system_implemented_traits() {
2653 fn check<T: Sized + std::fmt::Debug + Default + Send + Sync>(_: T) {}
2654
2655 check(System::new());
2656 }
2657
2658 #[test]
2659 fn check_memory_usage() {
2660 let mut s = System::new();
2661
2662 assert_eq!(s.total_memory(), 0);
2663 assert_eq!(s.free_memory(), 0);
2664 assert_eq!(s.available_memory(), 0);
2665 assert_eq!(s.used_memory(), 0);
2666 assert_eq!(s.total_swap(), 0);
2667 assert_eq!(s.free_swap(), 0);
2668 assert_eq!(s.used_swap(), 0);
2669
2670 s.refresh_memory();
2671 if IS_SUPPORTED_SYSTEM {
2672 assert!(s.total_memory() > 0);
2673 assert!(s.used_memory() > 0);
2674 if s.total_swap() > 0 {
2675 // I think it's pretty safe to assume that there is still some swap left...
2676 assert!(s.free_swap() > 0);
2677 }
2678 } else {
2679 assert_eq!(s.total_memory(), 0);
2680 assert_eq!(s.used_memory(), 0);
2681 assert_eq!(s.total_swap(), 0);
2682 assert_eq!(s.free_swap(), 0);
2683 }
2684 }
2685
2686 #[cfg(target_os = "linux")]
2687 #[test]
2688 fn check_processes_cpu_usage() {
2689 if !IS_SUPPORTED_SYSTEM {
2690 return;
2691 }
2692 let mut s = System::new();
2693
2694 s.refresh_processes(ProcessesToUpdate::All, false);
2695 // All CPU usage will start at zero until the second refresh
2696 assert!(s
2697 .processes()
2698 .iter()
2699 .all(|(_, proc_)| proc_.cpu_usage() == 0.0));
2700
2701 // Wait a bit to update CPU usage values
2702 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
2703 s.refresh_processes(ProcessesToUpdate::All, true);
2704 assert!(s
2705 .processes()
2706 .iter()
2707 .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
2708 && proc_.cpu_usage() <= (s.cpus().len() as f32) * 100.0));
2709 assert!(s
2710 .processes()
2711 .iter()
2712 .any(|(_, proc_)| proc_.cpu_usage() > 0.0));
2713 }
2714
2715 #[test]
2716 fn check_cpu_usage() {
2717 if !IS_SUPPORTED_SYSTEM {
2718 return;
2719 }
2720 let mut s = System::new();
2721 for _ in 0..10 {
2722 s.refresh_cpu_usage();
2723 // Wait a bit to update CPU usage values
2724 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
2725 if s.cpus().iter().any(|c| c.cpu_usage() > 0.0) {
2726 // All good!
2727 return;
2728 }
2729 }
2730 panic!("CPU usage is always zero...");
2731 }
2732
2733 #[test]
2734 fn check_system_info() {
2735 // We don't want to test on unsupported systems.
2736 if IS_SUPPORTED_SYSTEM {
2737 assert!(!System::name()
2738 .expect("Failed to get system name")
2739 .is_empty());
2740
2741 assert!(!System::kernel_version()
2742 .expect("Failed to get kernel version")
2743 .is_empty());
2744
2745 assert!(!System::os_version()
2746 .expect("Failed to get os version")
2747 .is_empty());
2748
2749 assert!(!System::long_os_version()
2750 .expect("Failed to get long OS version")
2751 .is_empty());
2752 }
2753
2754 assert!(!System::distribution_id().is_empty());
2755 }
2756
2757 #[test]
2758 fn check_host_name() {
2759 // We don't want to test on unsupported systems.
2760 if IS_SUPPORTED_SYSTEM {
2761 assert!(System::host_name().is_some());
2762 }
2763 }
2764
2765 #[test]
2766 fn check_refresh_process_return_value() {
2767 // We don't want to test on unsupported systems.
2768 if IS_SUPPORTED_SYSTEM {
2769 let _pid = get_current_pid().expect("Failed to get current PID");
2770
2771 #[cfg(not(feature = "apple-sandbox"))]
2772 {
2773 let mut s = System::new();
2774 // First check what happens in case the process isn't already in our process list.
2775 assert_eq!(
2776 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
2777 1
2778 );
2779 // Then check that it still returns 1 if the process is already in our process list.
2780 assert_eq!(
2781 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
2782 1
2783 );
2784 }
2785 }
2786 }
2787
2788 #[test]
2789 fn check_cpus_number() {
2790 let mut s = System::new();
2791
2792 // This information isn't retrieved by default.
2793 assert!(s.cpus().is_empty());
2794 if IS_SUPPORTED_SYSTEM {
2795 // The physical cores count is recomputed every time the function is called, so the
2796 // information must be relevant even with nothing initialized.
2797 let physical_cores_count =
2798 System::physical_core_count().expect("failed to get number of physical cores");
2799
2800 s.refresh_cpu_usage();
2801 // The cpus shouldn't be empty anymore.
2802 assert!(!s.cpus().is_empty());
2803
2804 // In case we are running inside a VM, it's possible to not have a physical core, only
2805 // logical ones, which is why we don't test `physical_cores_count > 0`.
2806 let physical_cores_count2 =
2807 System::physical_core_count().expect("failed to get number of physical cores");
2808 assert!(physical_cores_count2 <= s.cpus().len());
2809 assert_eq!(physical_cores_count, physical_cores_count2);
2810 } else {
2811 assert_eq!(System::physical_core_count(), None);
2812 }
2813 assert!(System::physical_core_count().unwrap_or(0) <= s.cpus().len());
2814 }
2815
2816 // This test only exists to ensure that the `Display` and `Debug` traits are implemented on the
2817 // `ProcessStatus` enum on all targets.
2818 #[test]
2819 fn check_display_impl_process_status() {
2820 println!("{} {:?}", ProcessStatus::Parked, ProcessStatus::Idle);
2821 }
2822
2823 #[test]
2824 #[allow(clippy::unnecessary_fallible_conversions)]
2825 fn check_pid_from_impls() {
2826 assert!(crate::Pid::try_from(0usize).is_ok());
2827 // If it doesn't panic, it's fine.
2828 let _ = crate::Pid::from(0);
2829 assert!(crate::Pid::from_str("0").is_ok());
2830 }
2831
2832 #[test]
2833 #[allow(clippy::const_is_empty)]
2834 fn check_nb_supported_signals() {
2835 if IS_SUPPORTED_SYSTEM {
2836 assert!(
2837 !SUPPORTED_SIGNALS.is_empty(),
2838 "SUPPORTED_SIGNALS shouldn't be empty on supported systems!"
2839 );
2840 } else {
2841 assert!(
2842 SUPPORTED_SIGNALS.is_empty(),
2843 "SUPPORTED_SIGNALS should be empty on not support systems!"
2844 );
2845 }
2846 }
2847}
2848
2849#[cfg(doctest)]
2850mod doctest {
2851 // FIXME: Can be removed once negative trait bounds are supported.
2852 /// Check that `Process` doesn't implement `Clone`.
2853 ///
2854 /// First we check that the "basic" code works:
2855 ///
2856 /// ```no_run
2857 /// use sysinfo::{Process, System};
2858 ///
2859 /// let mut s = System::new_all();
2860 /// let p: &Process = s.processes().values().next().unwrap();
2861 /// ```
2862 ///
2863 /// And now we check if it fails when we try to clone it:
2864 ///
2865 /// ```compile_fail
2866 /// use sysinfo::{Process, System};
2867 ///
2868 /// let mut s = System::new_all();
2869 /// let p: &Process = s.processes().values().next().unwrap();
2870 /// let p = (*p).clone();
2871 /// ```
2872 mod process_clone {}
2873
2874 // FIXME: Can be removed once negative trait bounds are supported.
2875 /// Check that `System` doesn't implement `Clone`.
2876 ///
2877 /// First we check that the "basic" code works:
2878 ///
2879 /// ```no_run
2880 /// use sysinfo::{Process, System};
2881 ///
2882 /// let s = System::new();
2883 /// ```
2884 ///
2885 /// And now we check if it fails when we try to clone it:
2886 ///
2887 /// ```compile_fail
2888 /// use sysinfo::{Process, System};
2889 ///
2890 /// let s = System::new();
2891 /// let s = s.clone();
2892 /// ```
2893 mod system_clone {}
2894}