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 /// Waits for process termination and returns its [`ExitStatus`] if it could be retrieved,
1351 /// returns `None` otherwise. It means that as long as the process is alive, this method will
1352 /// not return.
1353 ///
1354 /// ⚠️ On **macOS** and **FreeBSD**, if the process died and a new one took its PID, unless
1355 /// you refreshed, it will wait for the new process to end.
1356 ///
1357 /// On **Windows**, as long as we have a (internal) handle, we can always retrieve the exit
1358 /// status.
1359 ///
1360 /// On **Linux**/**Android**, we check that the start time of the PID we're waiting is the same
1361 /// as the current process'. If not it means the process died and a new one got its PID.
1362 ///
1363 /// ```no_run
1364 /// use sysinfo::{Pid, System};
1365 ///
1366 /// let mut s = System::new_all();
1367 ///
1368 /// if let Some(process) = s.process(Pid::from(1337)) {
1369 /// println!("Waiting for pid 1337");
1370 /// let exit_status = process.wait();
1371 /// println!("Pid 1337 exited with: {exit_status:?}");
1372 /// }
1373 /// ```
1374 pub fn wait(&self) -> Option<ExitStatus> {
1375 self.inner.wait()
1376 }
1377
1378 /// Returns the name of the process.
1379 ///
1380 /// **⚠️ Important ⚠️**
1381 ///
1382 /// On **Linux**, there are two things to know about processes' name:
1383 /// 1. It is limited to 15 characters.
1384 /// 2. It is not always the exe name.
1385 ///
1386 /// If you are looking for a specific process, unless you know what you are
1387 /// doing, in most cases it's better to use [`Process::exe`] instead (which
1388 /// can be empty sometimes!).
1389 ///
1390 /// ```no_run
1391 /// use sysinfo::{Pid, System};
1392 ///
1393 /// let s = System::new_all();
1394 /// if let Some(process) = s.process(Pid::from(1337)) {
1395 /// println!("{:?}", process.name());
1396 /// }
1397 /// ```
1398 pub fn name(&self) -> &OsStr {
1399 self.inner.name()
1400 }
1401
1402 /// Returns the command line.
1403 ///
1404 /// **⚠️ Important ⚠️**
1405 ///
1406 /// On **Windows**, you might need to use `administrator` privileges when running your program
1407 /// to have access to this information.
1408 ///
1409 /// ```no_run
1410 /// use sysinfo::{Pid, System};
1411 ///
1412 /// let s = System::new_all();
1413 /// if let Some(process) = s.process(Pid::from(1337)) {
1414 /// println!("{:?}", process.cmd());
1415 /// }
1416 /// ```
1417 pub fn cmd(&self) -> &[OsString] {
1418 self.inner.cmd()
1419 }
1420
1421 /// Returns the path to the process.
1422 ///
1423 /// ```no_run
1424 /// use sysinfo::{Pid, System};
1425 ///
1426 /// let s = System::new_all();
1427 /// if let Some(process) = s.process(Pid::from(1337)) {
1428 /// println!("{:?}", process.exe());
1429 /// }
1430 /// ```
1431 ///
1432 /// ### Implementation notes
1433 ///
1434 /// On Linux, this method will return an empty path if there
1435 /// was an error trying to read `/proc/<pid>/exe`. This can
1436 /// happen, for example, if the permission levels or UID namespaces
1437 /// between the caller and target processes are different.
1438 ///
1439 /// It is also the case that `cmd[0]` is _not_ usually a correct
1440 /// replacement for this.
1441 /// A process [may change its `cmd[0]` value](https://man7.org/linux/man-pages/man5/proc.5.html)
1442 /// freely, making this an untrustworthy source of information.
1443 pub fn exe(&self) -> Option<&Path> {
1444 self.inner.exe()
1445 }
1446
1447 /// Returns the PID of the process.
1448 ///
1449 /// ```no_run
1450 /// use sysinfo::{Pid, System};
1451 ///
1452 /// let s = System::new_all();
1453 /// if let Some(process) = s.process(Pid::from(1337)) {
1454 /// println!("{}", process.pid());
1455 /// }
1456 /// ```
1457 pub fn pid(&self) -> Pid {
1458 self.inner.pid()
1459 }
1460
1461 /// Returns the environment variables of the process.
1462 ///
1463 /// ```no_run
1464 /// use sysinfo::{Pid, System};
1465 ///
1466 /// let s = System::new_all();
1467 /// if let Some(process) = s.process(Pid::from(1337)) {
1468 /// println!("{:?}", process.environ());
1469 /// }
1470 /// ```
1471 pub fn environ(&self) -> &[OsString] {
1472 self.inner.environ()
1473 }
1474
1475 /// Returns the current working directory.
1476 ///
1477 /// ```no_run
1478 /// use sysinfo::{Pid, System};
1479 ///
1480 /// let s = System::new_all();
1481 /// if let Some(process) = s.process(Pid::from(1337)) {
1482 /// println!("{:?}", process.cwd());
1483 /// }
1484 /// ```
1485 pub fn cwd(&self) -> Option<&Path> {
1486 self.inner.cwd()
1487 }
1488
1489 /// Returns the path of the root directory.
1490 ///
1491 /// ```no_run
1492 /// use sysinfo::{Pid, System};
1493 ///
1494 /// let s = System::new_all();
1495 /// if let Some(process) = s.process(Pid::from(1337)) {
1496 /// println!("{:?}", process.root());
1497 /// }
1498 /// ```
1499 pub fn root(&self) -> Option<&Path> {
1500 self.inner.root()
1501 }
1502
1503 /// Returns the memory usage (in bytes).
1504 ///
1505 /// This method returns the [size of the resident set], that is, the amount of memory that the
1506 /// process allocated and which is currently mapped in physical RAM. It does not include memory
1507 /// that is swapped out, or, in some operating systems, that has been allocated but never used.
1508 ///
1509 /// Thus, it represents exactly the amount of physical RAM that the process is using at the
1510 /// present time, but it might not be a good indicator of the total memory that the process will
1511 /// be using over its lifetime. For that purpose, you can try and use
1512 /// [`virtual_memory`](Process::virtual_memory).
1513 ///
1514 /// ```no_run
1515 /// use sysinfo::{Pid, System};
1516 ///
1517 /// let s = System::new_all();
1518 /// if let Some(process) = s.process(Pid::from(1337)) {
1519 /// println!("{} bytes", process.memory());
1520 /// }
1521 /// ```
1522 ///
1523 /// [size of the resident set]: https://en.wikipedia.org/wiki/Resident_set_size
1524 pub fn memory(&self) -> u64 {
1525 self.inner.memory()
1526 }
1527
1528 /// Returns the virtual memory usage (in bytes).
1529 ///
1530 /// This method returns the [size of virtual memory], that is, the amount of memory that the
1531 /// process can access, whether it is currently mapped in physical RAM or not. It includes
1532 /// physical RAM, allocated but not used regions, swapped-out regions, and even memory
1533 /// associated with [memory-mapped files](https://en.wikipedia.org/wiki/Memory-mapped_file).
1534 ///
1535 /// This value has limitations though. Depending on the operating system and type of process,
1536 /// this value might be a good indicator of the total memory that the process will be using over
1537 /// its lifetime. However, for example, in the version 14 of macOS this value is in the order of
1538 /// the hundreds of gigabytes for every process, and thus not very informative. Moreover, if a
1539 /// process maps into memory a very large file, this value will increase accordingly, even if
1540 /// the process is not actively using the memory.
1541 ///
1542 /// ```no_run
1543 /// use sysinfo::{Pid, System};
1544 ///
1545 /// let s = System::new_all();
1546 /// if let Some(process) = s.process(Pid::from(1337)) {
1547 /// println!("{} bytes", process.virtual_memory());
1548 /// }
1549 /// ```
1550 ///
1551 /// [size of virtual memory]: https://en.wikipedia.org/wiki/Virtual_memory
1552 pub fn virtual_memory(&self) -> u64 {
1553 self.inner.virtual_memory()
1554 }
1555
1556 /// Returns the parent PID.
1557 ///
1558 /// ```no_run
1559 /// use sysinfo::{Pid, System};
1560 ///
1561 /// let s = System::new_all();
1562 /// if let Some(process) = s.process(Pid::from(1337)) {
1563 /// println!("{:?}", process.parent());
1564 /// }
1565 /// ```
1566 pub fn parent(&self) -> Option<Pid> {
1567 self.inner.parent()
1568 }
1569
1570 /// Returns the status of the process.
1571 ///
1572 /// ```no_run
1573 /// use sysinfo::{Pid, System};
1574 ///
1575 /// let s = System::new_all();
1576 /// if let Some(process) = s.process(Pid::from(1337)) {
1577 /// println!("{:?}", process.status());
1578 /// }
1579 /// ```
1580 pub fn status(&self) -> ProcessStatus {
1581 self.inner.status()
1582 }
1583
1584 /// Returns the time where the process was started (in seconds) from epoch.
1585 ///
1586 /// ```no_run
1587 /// use sysinfo::{Pid, System};
1588 ///
1589 /// let s = System::new_all();
1590 /// if let Some(process) = s.process(Pid::from(1337)) {
1591 /// println!("Started at {} seconds", process.start_time());
1592 /// }
1593 /// ```
1594 pub fn start_time(&self) -> u64 {
1595 self.inner.start_time()
1596 }
1597
1598 /// Returns for how much time the process has been running (in seconds).
1599 ///
1600 /// ```no_run
1601 /// use sysinfo::{Pid, System};
1602 ///
1603 /// let s = System::new_all();
1604 /// if let Some(process) = s.process(Pid::from(1337)) {
1605 /// println!("Running since {} seconds", process.run_time());
1606 /// }
1607 /// ```
1608 pub fn run_time(&self) -> u64 {
1609 self.inner.run_time()
1610 }
1611
1612 /// Returns the total CPU usage (in %). Notice that it might be bigger than
1613 /// 100 if run on a multi-core machine.
1614 ///
1615 /// If you want a value between 0% and 100%, divide the returned value by
1616 /// the number of CPUs.
1617 ///
1618 /// ⚠️ To start to have accurate CPU usage, a process needs to be refreshed
1619 /// **twice** because CPU usage computation is based on time diff (process
1620 /// time on a given time period divided by total system time on the same
1621 /// time period).
1622 ///
1623 /// ⚠️ If you want accurate CPU usage number, better leave a bit of time
1624 /// between two calls of this method (take a look at
1625 /// [`MINIMUM_CPU_UPDATE_INTERVAL`][crate::MINIMUM_CPU_UPDATE_INTERVAL] for
1626 /// more information).
1627 ///
1628 /// ```no_run
1629 /// use sysinfo::{Pid, ProcessesToUpdate, ProcessRefreshKind, System};
1630 ///
1631 /// let mut s = System::new_all();
1632 /// // Wait a bit because CPU usage is based on diff.
1633 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
1634 /// // Refresh CPU usage to get actual value.
1635 /// s.refresh_processes_specifics(
1636 /// ProcessesToUpdate::All,
1637 /// true,
1638 /// ProcessRefreshKind::nothing().with_cpu()
1639 /// );
1640 /// if let Some(process) = s.process(Pid::from(1337)) {
1641 /// println!("{}%", process.cpu_usage());
1642 /// }
1643 /// ```
1644 pub fn cpu_usage(&self) -> f32 {
1645 self.inner.cpu_usage()
1646 }
1647
1648 /// Returns the total accumulated CPU usage (in CPU-milliseconds). Note
1649 /// that it might be bigger than the total clock run time of a process if
1650 /// run on a multi-core machine.
1651 ///
1652 /// ```no_run
1653 /// use sysinfo::{Pid, System};
1654 ///
1655 /// let s = System::new_all();
1656 /// if let Some(process) = s.process(Pid::from(1337)) {
1657 /// println!("{}", process.accumulated_cpu_time());
1658 /// }
1659 /// ```
1660 pub fn accumulated_cpu_time(&self) -> u64 {
1661 self.inner.accumulated_cpu_time()
1662 }
1663
1664 /// Returns number of bytes read and written to disk.
1665 ///
1666 /// ⚠️ On Windows, this method actually returns **ALL** I/O read and
1667 /// written bytes.
1668 ///
1669 /// ⚠️ Files might be cached in memory by your OS, meaning that reading/writing them might not
1670 /// increase the `read_bytes`/`written_bytes` values. You can find more information about it
1671 /// in the `proc_pid_io` manual (`man proc_pid_io` on unix platforms).
1672 ///
1673 /// ```no_run
1674 /// use sysinfo::{Pid, System};
1675 ///
1676 /// let s = System::new_all();
1677 /// if let Some(process) = s.process(Pid::from(1337)) {
1678 /// let disk_usage = process.disk_usage();
1679 /// println!("read bytes : new/total => {}/{}",
1680 /// disk_usage.read_bytes,
1681 /// disk_usage.total_read_bytes,
1682 /// );
1683 /// println!("written bytes: new/total => {}/{}",
1684 /// disk_usage.written_bytes,
1685 /// disk_usage.total_written_bytes,
1686 /// );
1687 /// }
1688 /// ```
1689 pub fn disk_usage(&self) -> DiskUsage {
1690 self.inner.disk_usage()
1691 }
1692
1693 /// Returns the ID of the owner user of this process or `None` if this
1694 /// information couldn't be retrieved. If you want to get the [`User`] from
1695 /// it, take a look at [`Users::get_user_by_id`].
1696 ///
1697 /// [`User`]: crate::User
1698 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
1699 ///
1700 /// ```no_run
1701 /// use sysinfo::{Pid, System};
1702 ///
1703 /// let mut s = System::new_all();
1704 ///
1705 /// if let Some(process) = s.process(Pid::from(1337)) {
1706 /// println!("User id for process 1337: {:?}", process.user_id());
1707 /// }
1708 /// ```
1709 pub fn user_id(&self) -> Option<&Uid> {
1710 self.inner.user_id()
1711 }
1712
1713 /// Returns the user ID of the effective owner of this process or `None` if
1714 /// this information couldn't be retrieved. If you want to get the [`User`]
1715 /// from it, take a look at [`Users::get_user_by_id`].
1716 ///
1717 /// If you run something with `sudo`, the real user ID of the launched
1718 /// process will be the ID of the user you are logged in as but effective
1719 /// user ID will be `0` (i-e root).
1720 ///
1721 /// ⚠️ It always returns `None` on Windows.
1722 ///
1723 /// [`User`]: crate::User
1724 /// [`Users::get_user_by_id`]: crate::Users::get_user_by_id
1725 ///
1726 /// ```no_run
1727 /// use sysinfo::{Pid, System};
1728 ///
1729 /// let mut s = System::new_all();
1730 ///
1731 /// if let Some(process) = s.process(Pid::from(1337)) {
1732 /// println!("User id for process 1337: {:?}", process.effective_user_id());
1733 /// }
1734 /// ```
1735 pub fn effective_user_id(&self) -> Option<&Uid> {
1736 self.inner.effective_user_id()
1737 }
1738
1739 /// Returns the process group ID of the process.
1740 ///
1741 /// ⚠️ It always returns `None` on Windows.
1742 ///
1743 /// ```no_run
1744 /// use sysinfo::{Pid, System};
1745 ///
1746 /// let mut s = System::new_all();
1747 ///
1748 /// if let Some(process) = s.process(Pid::from(1337)) {
1749 /// println!("Group ID for process 1337: {:?}", process.group_id());
1750 /// }
1751 /// ```
1752 pub fn group_id(&self) -> Option<Gid> {
1753 self.inner.group_id()
1754 }
1755
1756 /// Returns the effective group ID of the process.
1757 ///
1758 /// If you run something with `sudo`, the real group ID of the launched
1759 /// process will be the primary group ID you are logged in as but effective
1760 /// group ID will be `0` (i-e root).
1761 ///
1762 /// ⚠️ It always returns `None` on Windows.
1763 ///
1764 /// ```no_run
1765 /// use sysinfo::{Pid, System};
1766 ///
1767 /// let mut s = System::new_all();
1768 ///
1769 /// if let Some(process) = s.process(Pid::from(1337)) {
1770 /// println!("User id for process 1337: {:?}", process.effective_group_id());
1771 /// }
1772 /// ```
1773 pub fn effective_group_id(&self) -> Option<Gid> {
1774 self.inner.effective_group_id()
1775 }
1776
1777 /// Returns the session ID for the current process or `None` if it couldn't
1778 /// be retrieved.
1779 ///
1780 /// ⚠️ This information is computed every time this method is called.
1781 ///
1782 /// ```no_run
1783 /// use sysinfo::{Pid, System};
1784 ///
1785 /// let mut s = System::new_all();
1786 ///
1787 /// if let Some(process) = s.process(Pid::from(1337)) {
1788 /// println!("Session ID for process 1337: {:?}", process.session_id());
1789 /// }
1790 /// ```
1791 pub fn session_id(&self) -> Option<Pid> {
1792 self.inner.session_id()
1793 }
1794
1795 /// Tasks run by this process. If there are none, returns `None`.
1796 ///
1797 /// ⚠️ This method always returns `None` on other platforms than Linux.
1798 ///
1799 /// ```no_run
1800 /// use sysinfo::{Pid, System};
1801 ///
1802 /// let mut s = System::new_all();
1803 ///
1804 /// if let Some(process) = s.process(Pid::from(1337)) {
1805 /// if let Some(tasks) = process.tasks() {
1806 /// println!("Listing tasks for process {:?}", process.pid());
1807 /// for task_pid in tasks {
1808 /// if let Some(task) = s.process(*task_pid) {
1809 /// println!("Task {:?}: {:?}", task.pid(), task.name());
1810 /// }
1811 /// }
1812 /// }
1813 /// }
1814 /// ```
1815 pub fn tasks(&self) -> Option<&HashSet<Pid>> {
1816 cfg_if! {
1817 if #[cfg(all(
1818 any(target_os = "linux", target_os = "android"),
1819 not(feature = "unknown-ci")
1820 ))] {
1821 self.inner.tasks.as_ref()
1822 } else {
1823 None
1824 }
1825 }
1826 }
1827
1828 /// If the process is a thread, it'll return `Some` with the kind of thread it is. Returns
1829 /// `None` otherwise.
1830 ///
1831 /// ⚠️ This method always returns `None` on other platforms than Linux.
1832 ///
1833 /// ```no_run
1834 /// use sysinfo::System;
1835 ///
1836 /// let s = System::new_all();
1837 ///
1838 /// for (_, process) in s.processes() {
1839 /// if let Some(thread_kind) = process.thread_kind() {
1840 /// println!("Process {:?} is a {thread_kind:?} thread", process.pid());
1841 /// }
1842 /// }
1843 /// ```
1844 pub fn thread_kind(&self) -> Option<ThreadKind> {
1845 cfg_if! {
1846 if #[cfg(all(
1847 any(target_os = "linux", target_os = "android"),
1848 not(feature = "unknown-ci")
1849 ))] {
1850 self.inner.thread_kind()
1851 } else {
1852 None
1853 }
1854 }
1855 }
1856
1857 /// Returns `true` if the process doesn't exist anymore but was not yet removed from
1858 /// the processes list because the `remove_dead_processes` argument was set to `false`
1859 /// in methods like [`System::refresh_processes`].
1860 ///
1861 /// ```no_run
1862 /// use sysinfo::{ProcessesToUpdate, System};
1863 ///
1864 /// let mut s = System::new_all();
1865 /// // We set the `remove_dead_processes` to `false`.
1866 /// s.refresh_processes(ProcessesToUpdate::All, false);
1867 ///
1868 /// for (_, process) in s.processes() {
1869 /// println!(
1870 /// "Process {:?} {}",
1871 /// process.pid(),
1872 /// if process.exists() { "exists" } else { "doesn't exist" },
1873 /// );
1874 /// }
1875 /// ```
1876 pub fn exists(&self) -> bool {
1877 self.inner.exists()
1878 }
1879
1880 /// Returns the number of open files in the current process.
1881 ///
1882 /// Returns `None` if it failed retrieving the information or if the current system is not
1883 /// supported.
1884 ///
1885 /// **Important**: this information is computed every time this function is called.
1886 ///
1887 /// ```no_run
1888 /// use sysinfo::System;
1889 ///
1890 /// let s = System::new_all();
1891 ///
1892 /// for (_, process) in s.processes() {
1893 /// println!(
1894 /// "Process {:?} {:?}",
1895 /// process.pid(),
1896 /// process.open_files(),
1897 /// );
1898 /// }
1899 /// ```
1900 pub fn open_files(&self) -> Option<usize> {
1901 self.inner.open_files()
1902 }
1903
1904 /// Returns the maximum number of open files for the current process.
1905 ///
1906 /// Returns `None` if it failed retrieving the information or if the current system is not
1907 /// supported.
1908 ///
1909 /// **Important**: this information is computed every time this function is called.
1910 ///
1911 /// ```no_run
1912 /// use sysinfo::System;
1913 ///
1914 /// let s = System::new_all();
1915 ///
1916 /// for (_, process) in s.processes() {
1917 /// println!(
1918 /// "Process {:?} {:?}",
1919 /// process.pid(),
1920 /// process.open_files_limit(),
1921 /// );
1922 /// }
1923 /// ```
1924 pub fn open_files_limit(&self) -> Option<usize> {
1925 self.inner.open_files_limit()
1926 }
1927}
1928
1929macro_rules! pid_decl {
1930 ($typ:ty) => {
1931 #[doc = include_str!("../../md_doc/pid.md")]
1932 #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1933 #[repr(transparent)]
1934 pub struct Pid(pub(crate) $typ);
1935
1936 impl From<usize> for Pid {
1937 fn from(v: usize) -> Self {
1938 Self(v as _)
1939 }
1940 }
1941 impl From<Pid> for usize {
1942 fn from(v: Pid) -> Self {
1943 v.0 as _
1944 }
1945 }
1946 impl FromStr for Pid {
1947 type Err = <$typ as FromStr>::Err;
1948 fn from_str(s: &str) -> Result<Self, Self::Err> {
1949 Ok(Self(<$typ>::from_str(s)?))
1950 }
1951 }
1952 impl fmt::Display for Pid {
1953 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1954 write!(f, "{}", self.0)
1955 }
1956 }
1957 impl Pid {
1958 /// Allows to convert [`Pid`][crate::Pid] into [`u32`].
1959 ///
1960 /// ```
1961 /// use sysinfo::Pid;
1962 ///
1963 /// let pid = Pid::from_u32(0);
1964 /// let value: u32 = pid.as_u32();
1965 /// ```
1966 pub fn as_u32(self) -> u32 {
1967 self.0 as _
1968 }
1969 /// Allows to convert a [`u32`] into [`Pid`][crate::Pid].
1970 ///
1971 /// ```
1972 /// use sysinfo::Pid;
1973 ///
1974 /// let pid = Pid::from_u32(0);
1975 /// ```
1976 pub fn from_u32(v: u32) -> Self {
1977 Self(v as _)
1978 }
1979 }
1980 };
1981}
1982
1983cfg_if! {
1984 if #[cfg(all(
1985 not(feature = "unknown-ci"),
1986 any(
1987 target_os = "freebsd",
1988 target_os = "linux",
1989 target_os = "android",
1990 target_os = "macos",
1991 target_os = "ios",
1992 )
1993 ))] {
1994 use libc::pid_t;
1995
1996 pid_decl!(pid_t);
1997 } else {
1998 pid_decl!(usize);
1999 }
2000}
2001
2002/// This enum allows you to specify when you want the related information to be updated.
2003///
2004/// For example if you only want the [`Process::exe()`] information to be refreshed only if it's not
2005/// already set:
2006///
2007/// ```no_run
2008/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System, UpdateKind};
2009///
2010/// let mut system = System::new();
2011/// system.refresh_processes_specifics(
2012/// ProcessesToUpdate::All,
2013/// true,
2014/// ProcessRefreshKind::nothing().with_exe(UpdateKind::OnlyIfNotSet),
2015/// );
2016/// ```
2017#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2018pub enum UpdateKind {
2019 /// Never update the related information.
2020 #[default]
2021 Never,
2022 /// Always update the related information.
2023 Always,
2024 /// Only update the related information if it was not already set at least once.
2025 OnlyIfNotSet,
2026}
2027
2028impl UpdateKind {
2029 /// If `self` is `OnlyIfNotSet`, `f` is called and its returned value is returned.
2030 #[allow(dead_code)] // Needed for unsupported targets.
2031 pub(crate) fn needs_update(self, f: impl Fn() -> bool) -> bool {
2032 match self {
2033 Self::Never => false,
2034 Self::Always => true,
2035 Self::OnlyIfNotSet => f(),
2036 }
2037 }
2038}
2039
2040/// This enum allows you to specify if you want all processes to be updated or just
2041/// some of them.
2042///
2043/// Example:
2044///
2045/// ```no_run
2046/// use sysinfo::{ProcessesToUpdate, System, get_current_pid};
2047///
2048/// let mut system = System::new();
2049/// // To refresh all processes:
2050/// system.refresh_processes(ProcessesToUpdate::All, true);
2051///
2052/// // To refresh only the current one:
2053/// system.refresh_processes(
2054/// ProcessesToUpdate::Some(&[get_current_pid().unwrap()]),
2055/// true,
2056/// );
2057/// ```
2058#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2059pub enum ProcessesToUpdate<'a> {
2060 /// To refresh all processes.
2061 All,
2062 /// To refresh only the processes with the listed [`Pid`].
2063 ///
2064 /// [`Pid`]: crate::Pid
2065 Some(&'a [Pid]),
2066}
2067
2068/// Used to determine what you want to refresh specifically on the [`Process`] type.
2069///
2070/// When all refresh are ruled out, a [`Process`] will still retrieve the following information:
2071/// * Process ID ([`Pid`])
2072/// * Parent process ID (on Windows it never changes though)
2073/// * Process name
2074/// * Start time
2075///
2076/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2077/// the information won't be retrieved if the information is accessible without needing
2078/// extra computation.
2079///
2080/// ⚠️ ** Linux Specific ** ⚠️
2081/// When using `ProcessRefreshKind::everything()`, in linux we will fetch all relevant
2082/// information from `/proc/<pid>/` as well as all the information from `/proc/<pid>/task/<tid>/`
2083/// folders. This makes the refresh mechanism a lot slower depending on the number of tasks
2084/// each process has.
2085///
2086/// If you don't care about tasks information, use `ProcessRefreshKind::everything().without_tasks()`
2087/// as much as possible.
2088///
2089/// ```
2090/// use sysinfo::{ProcessesToUpdate, ProcessRefreshKind, System};
2091///
2092/// let mut system = System::new();
2093///
2094/// // We don't want to update the CPU information.
2095/// system.refresh_processes_specifics(
2096/// ProcessesToUpdate::All,
2097/// true,
2098/// ProcessRefreshKind::everything().without_cpu(),
2099/// );
2100///
2101/// for (_, proc_) in system.processes() {
2102/// // We use a `==` comparison on float only because we know it's set to 0 here.
2103/// assert_eq!(proc_.cpu_usage(), 0.);
2104/// }
2105/// ```
2106///
2107/// [`Process`]: crate::Process
2108#[derive(Clone, Copy, Debug, PartialEq, Eq)]
2109pub struct ProcessRefreshKind {
2110 cpu: bool,
2111 disk_usage: bool,
2112 memory: bool,
2113 user: UpdateKind,
2114 cwd: UpdateKind,
2115 root: UpdateKind,
2116 environ: UpdateKind,
2117 cmd: UpdateKind,
2118 exe: UpdateKind,
2119 tasks: bool,
2120}
2121
2122/// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2123/// By default, we want to list all processes and tasks are considered processes on their own
2124/// in linux so we still fetch them by default. However, the processes information are not
2125/// refreshed.
2126impl Default for ProcessRefreshKind {
2127 fn default() -> Self {
2128 Self {
2129 cpu: false,
2130 disk_usage: false,
2131 memory: false,
2132 user: UpdateKind::default(),
2133 cwd: UpdateKind::default(),
2134 root: UpdateKind::default(),
2135 environ: UpdateKind::default(),
2136 cmd: UpdateKind::default(),
2137 exe: UpdateKind::default(),
2138 tasks: true, // Process by default includes all tasks.
2139 }
2140 }
2141}
2142
2143impl ProcessRefreshKind {
2144 /// Creates a new `ProcessRefreshKind` with every refresh set to `false`, except for `tasks`.
2145 /// By default, we want to list all processes and tasks are considered processes on their own
2146 /// in linux so we still fetch them by default. However, the processes information are not
2147 /// refreshed.
2148 /// ```
2149 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2150 ///
2151 /// let r = ProcessRefreshKind::nothing();
2152 ///
2153 /// assert_eq!(r.cpu(), false);
2154 /// assert_eq!(r.user(), UpdateKind::Never);
2155 /// ```
2156 pub fn nothing() -> Self {
2157 Self::default()
2158 }
2159
2160 /// Creates a new `ProcessRefreshKind` with every refresh set to `true` or
2161 /// [`UpdateKind::OnlyIfNotSet`].
2162 ///
2163 /// ```
2164 /// use sysinfo::{ProcessRefreshKind, UpdateKind};
2165 ///
2166 /// let r = ProcessRefreshKind::everything();
2167 ///
2168 /// assert_eq!(r.cpu(), true);
2169 /// assert_eq!(r.user(), UpdateKind::OnlyIfNotSet);
2170 /// ```
2171 pub fn everything() -> Self {
2172 Self {
2173 cpu: true,
2174 disk_usage: true,
2175 memory: true,
2176 user: UpdateKind::OnlyIfNotSet,
2177 cwd: UpdateKind::OnlyIfNotSet,
2178 root: UpdateKind::OnlyIfNotSet,
2179 environ: UpdateKind::OnlyIfNotSet,
2180 cmd: UpdateKind::OnlyIfNotSet,
2181 exe: UpdateKind::OnlyIfNotSet,
2182 tasks: true,
2183 }
2184 }
2185
2186 impl_get_set!(
2187 ProcessRefreshKind,
2188 cpu,
2189 with_cpu,
2190 without_cpu,
2191 "\
2192It will retrieve both CPU usage and CPU accumulated time,"
2193 );
2194 impl_get_set!(
2195 ProcessRefreshKind,
2196 disk_usage,
2197 with_disk_usage,
2198 without_disk_usage
2199 );
2200 impl_get_set!(
2201 ProcessRefreshKind,
2202 user,
2203 with_user,
2204 without_user,
2205 UpdateKind,
2206 "\
2207It will retrieve the following information:
2208
2209 * user ID
2210 * user effective ID (if available on the platform)
2211 * user group ID (if available on the platform)
2212 * user effective ID (if available on the platform)"
2213 );
2214 impl_get_set!(ProcessRefreshKind, memory, with_memory, without_memory);
2215 impl_get_set!(ProcessRefreshKind, cwd, with_cwd, without_cwd, UpdateKind);
2216 impl_get_set!(
2217 ProcessRefreshKind,
2218 root,
2219 with_root,
2220 without_root,
2221 UpdateKind
2222 );
2223 impl_get_set!(
2224 ProcessRefreshKind,
2225 environ,
2226 with_environ,
2227 without_environ,
2228 UpdateKind
2229 );
2230 impl_get_set!(ProcessRefreshKind, cmd, with_cmd, without_cmd, UpdateKind);
2231 impl_get_set!(ProcessRefreshKind, exe, with_exe, without_exe, UpdateKind);
2232 impl_get_set!(ProcessRefreshKind, tasks, with_tasks, without_tasks);
2233}
2234
2235/// Used to determine what you want to refresh specifically on the [`Cpu`] type.
2236///
2237/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2238/// the information won't be retrieved if the information is accessible without needing
2239/// extra computation.
2240///
2241/// ```
2242/// use sysinfo::{CpuRefreshKind, System};
2243///
2244/// let mut system = System::new();
2245///
2246/// // We don't want to update all the CPU information.
2247/// system.refresh_cpu_specifics(CpuRefreshKind::everything().without_frequency());
2248///
2249/// for cpu in system.cpus() {
2250/// assert_eq!(cpu.frequency(), 0);
2251/// }
2252/// ```
2253///
2254/// [`Cpu`]: crate::Cpu
2255#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2256pub struct CpuRefreshKind {
2257 cpu_usage: bool,
2258 frequency: bool,
2259}
2260
2261impl CpuRefreshKind {
2262 /// Creates a new `CpuRefreshKind` with every refresh set to `false`.
2263 ///
2264 /// ```
2265 /// use sysinfo::CpuRefreshKind;
2266 ///
2267 /// let r = CpuRefreshKind::nothing();
2268 ///
2269 /// assert_eq!(r.frequency(), false);
2270 /// assert_eq!(r.cpu_usage(), false);
2271 /// ```
2272 pub fn nothing() -> Self {
2273 Self::default()
2274 }
2275
2276 /// Creates a new `CpuRefreshKind` with every refresh set to `true`.
2277 ///
2278 /// ```
2279 /// use sysinfo::CpuRefreshKind;
2280 ///
2281 /// let r = CpuRefreshKind::everything();
2282 ///
2283 /// assert_eq!(r.frequency(), true);
2284 /// assert_eq!(r.cpu_usage(), true);
2285 /// ```
2286 pub fn everything() -> Self {
2287 Self {
2288 cpu_usage: true,
2289 frequency: true,
2290 }
2291 }
2292
2293 impl_get_set!(CpuRefreshKind, cpu_usage, with_cpu_usage, without_cpu_usage);
2294 impl_get_set!(CpuRefreshKind, frequency, with_frequency, without_frequency);
2295}
2296
2297/// Used to determine which memory you want to refresh specifically.
2298///
2299/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2300/// the information won't be retrieved if the information is accessible without needing
2301/// extra computation.
2302///
2303/// ```
2304/// use sysinfo::{MemoryRefreshKind, System};
2305///
2306/// let mut system = System::new();
2307///
2308/// // We don't want to update all memories information.
2309/// system.refresh_memory_specifics(MemoryRefreshKind::nothing().with_ram());
2310///
2311/// println!("total RAM: {}", system.total_memory());
2312/// println!("free RAM: {}", system.free_memory());
2313/// ```
2314#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2315pub struct MemoryRefreshKind {
2316 ram: bool,
2317 swap: bool,
2318}
2319
2320impl MemoryRefreshKind {
2321 /// Creates a new `MemoryRefreshKind` with every refresh set to `false`.
2322 ///
2323 /// ```
2324 /// use sysinfo::MemoryRefreshKind;
2325 ///
2326 /// let r = MemoryRefreshKind::nothing();
2327 ///
2328 /// assert_eq!(r.ram(), false);
2329 /// assert_eq!(r.swap(), false);
2330 /// ```
2331 pub fn nothing() -> Self {
2332 Self::default()
2333 }
2334
2335 /// Creates a new `MemoryRefreshKind` with every refresh set to `true`.
2336 ///
2337 /// ```
2338 /// use sysinfo::MemoryRefreshKind;
2339 ///
2340 /// let r = MemoryRefreshKind::everything();
2341 ///
2342 /// assert_eq!(r.ram(), true);
2343 /// assert_eq!(r.swap(), true);
2344 /// ```
2345 pub fn everything() -> Self {
2346 Self {
2347 ram: true,
2348 swap: true,
2349 }
2350 }
2351
2352 impl_get_set!(MemoryRefreshKind, ram, with_ram, without_ram);
2353 impl_get_set!(MemoryRefreshKind, swap, with_swap, without_swap);
2354}
2355
2356/// Used to determine what you want to refresh specifically on the [`System`][crate::System] type.
2357///
2358/// ⚠️ Just like all other refresh types, ruling out a refresh doesn't assure you that
2359/// the information won't be retrieved if the information is accessible without needing
2360/// extra computation.
2361///
2362/// ```
2363/// use sysinfo::{RefreshKind, System};
2364///
2365/// // We want everything except memory.
2366/// let mut system = System::new_with_specifics(RefreshKind::everything().without_memory());
2367///
2368/// assert_eq!(system.total_memory(), 0);
2369/// # if sysinfo::IS_SUPPORTED_SYSTEM && !cfg!(feature = "apple-sandbox") {
2370/// assert!(system.processes().len() > 0);
2371/// # }
2372/// ```
2373#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
2374pub struct RefreshKind {
2375 processes: Option<ProcessRefreshKind>,
2376 memory: Option<MemoryRefreshKind>,
2377 cpu: Option<CpuRefreshKind>,
2378}
2379
2380impl RefreshKind {
2381 /// Creates a new `RefreshKind` with every refresh set to `false`/`None`.
2382 ///
2383 /// ```
2384 /// use sysinfo::RefreshKind;
2385 ///
2386 /// let r = RefreshKind::nothing();
2387 ///
2388 /// assert_eq!(r.processes().is_some(), false);
2389 /// assert_eq!(r.memory().is_some(), false);
2390 /// assert_eq!(r.cpu().is_some(), false);
2391 /// ```
2392 pub fn nothing() -> Self {
2393 Self::default()
2394 }
2395
2396 /// Creates a new `RefreshKind` with every refresh set to `true`/`Some(...)`.
2397 ///
2398 /// ```
2399 /// use sysinfo::RefreshKind;
2400 ///
2401 /// let r = RefreshKind::everything();
2402 ///
2403 /// assert_eq!(r.processes().is_some(), true);
2404 /// assert_eq!(r.memory().is_some(), true);
2405 /// assert_eq!(r.cpu().is_some(), true);
2406 /// ```
2407 pub fn everything() -> Self {
2408 Self {
2409 processes: Some(ProcessRefreshKind::everything()),
2410 memory: Some(MemoryRefreshKind::everything()),
2411 cpu: Some(CpuRefreshKind::everything()),
2412 }
2413 }
2414
2415 impl_get_set!(
2416 RefreshKind,
2417 processes,
2418 with_processes,
2419 without_processes,
2420 ProcessRefreshKind
2421 );
2422 impl_get_set!(
2423 RefreshKind,
2424 memory,
2425 with_memory,
2426 without_memory,
2427 MemoryRefreshKind
2428 );
2429 impl_get_set!(RefreshKind, cpu, with_cpu, without_cpu, CpuRefreshKind);
2430}
2431
2432/// Returns the pid for the current process.
2433///
2434/// `Err` is returned in case the platform isn't supported.
2435///
2436/// ```no_run
2437/// use sysinfo::get_current_pid;
2438///
2439/// match get_current_pid() {
2440/// Ok(pid) => {
2441/// println!("current pid: {}", pid);
2442/// }
2443/// Err(e) => {
2444/// println!("failed to get current pid: {}", e);
2445/// }
2446/// }
2447/// ```
2448#[allow(clippy::unnecessary_wraps)]
2449pub fn get_current_pid() -> Result<Pid, &'static str> {
2450 cfg_if! {
2451 if #[cfg(feature = "unknown-ci")] {
2452 fn inner() -> Result<Pid, &'static str> {
2453 Err("Unknown platform (CI)")
2454 }
2455 } else if #[cfg(any(
2456 target_os = "freebsd",
2457 target_os = "linux",
2458 target_os = "android",
2459 target_os = "macos",
2460 target_os = "ios",
2461 ))] {
2462 fn inner() -> Result<Pid, &'static str> {
2463 unsafe { Ok(Pid(libc::getpid())) }
2464 }
2465 } else if #[cfg(windows)] {
2466 fn inner() -> Result<Pid, &'static str> {
2467 use windows::Win32::System::Threading::GetCurrentProcessId;
2468
2469 unsafe { Ok(Pid(GetCurrentProcessId() as _)) }
2470 }
2471 } else {
2472 fn inner() -> Result<Pid, &'static str> {
2473 Err("Unknown platform")
2474 }
2475 }
2476 }
2477 inner()
2478}
2479
2480/// Contains all the methods of the [`Cpu`][crate::Cpu] struct.
2481///
2482/// ```no_run
2483/// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2484///
2485/// let mut s = System::new_with_specifics(
2486/// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2487/// );
2488///
2489/// // Wait a bit because CPU usage is based on diff.
2490/// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2491/// // Refresh CPUs again to get actual value.
2492/// s.refresh_cpu_all();
2493///
2494/// for cpu in s.cpus() {
2495/// println!("{}%", cpu.cpu_usage());
2496/// }
2497/// ```
2498pub struct Cpu {
2499 pub(crate) inner: CpuInner,
2500}
2501
2502impl Cpu {
2503 /// Returns this CPU's usage.
2504 ///
2505 /// Note: You'll need to refresh it at least twice (diff between the first and the second is
2506 /// how CPU usage is computed) at first if you want to have a non-zero value.
2507 ///
2508 /// ```no_run
2509 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2510 ///
2511 /// let mut s = System::new_with_specifics(
2512 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2513 /// );
2514 ///
2515 /// // Wait a bit because CPU usage is based on diff.
2516 /// std::thread::sleep(sysinfo::MINIMUM_CPU_UPDATE_INTERVAL);
2517 /// // Refresh CPUs again to get actual value.
2518 /// s.refresh_cpu_all();
2519 ///
2520 /// for cpu in s.cpus() {
2521 /// println!("{}%", cpu.cpu_usage());
2522 /// }
2523 /// ```
2524 pub fn cpu_usage(&self) -> f32 {
2525 self.inner.cpu_usage()
2526 }
2527
2528 /// Returns this CPU's name.
2529 ///
2530 /// ```no_run
2531 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2532 ///
2533 /// let s = System::new_with_specifics(
2534 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2535 /// );
2536 /// for cpu in s.cpus() {
2537 /// println!("{}", cpu.name());
2538 /// }
2539 /// ```
2540 pub fn name(&self) -> &str {
2541 self.inner.name()
2542 }
2543
2544 /// Returns the CPU's vendor id.
2545 ///
2546 /// ```no_run
2547 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2548 ///
2549 /// let s = System::new_with_specifics(
2550 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2551 /// );
2552 /// for cpu in s.cpus() {
2553 /// println!("{}", cpu.vendor_id());
2554 /// }
2555 /// ```
2556 pub fn vendor_id(&self) -> &str {
2557 self.inner.vendor_id()
2558 }
2559
2560 /// Returns the CPU's brand.
2561 ///
2562 /// ```no_run
2563 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2564 ///
2565 /// let s = System::new_with_specifics(
2566 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2567 /// );
2568 /// for cpu in s.cpus() {
2569 /// println!("{}", cpu.brand());
2570 /// }
2571 /// ```
2572 pub fn brand(&self) -> &str {
2573 self.inner.brand()
2574 }
2575
2576 /// Returns the CPU's frequency.
2577 ///
2578 /// ```no_run
2579 /// use sysinfo::{System, RefreshKind, CpuRefreshKind};
2580 ///
2581 /// let s = System::new_with_specifics(
2582 /// RefreshKind::nothing().with_cpu(CpuRefreshKind::everything()),
2583 /// );
2584 /// for cpu in s.cpus() {
2585 /// println!("{}", cpu.frequency());
2586 /// }
2587 /// ```
2588 pub fn frequency(&self) -> u64 {
2589 self.inner.frequency()
2590 }
2591}
2592
2593#[cfg(test)]
2594mod test {
2595 use crate::*;
2596 use std::str::FromStr;
2597
2598 // In case `Process::updated` is misused, `System::refresh_processes` might remove them
2599 // so this test ensures that it doesn't happen.
2600 #[test]
2601 fn check_refresh_process_update() {
2602 if !IS_SUPPORTED_SYSTEM {
2603 return;
2604 }
2605 let mut s = System::new_all();
2606 let total = s.processes().len() as isize;
2607 s.refresh_processes(ProcessesToUpdate::All, false);
2608 let new_total = s.processes().len() as isize;
2609 // There should be almost no difference in the processes count.
2610 assert!(
2611 (new_total - total).abs() <= 5,
2612 "{} <= 5",
2613 (new_total - total).abs()
2614 );
2615 }
2616
2617 #[test]
2618 fn check_cpu_arch() {
2619 assert!(!System::cpu_arch().is_empty());
2620 }
2621
2622 // Ensure that the CPUs frequency isn't retrieved until we ask for it.
2623 #[test]
2624 fn check_cpu_frequency() {
2625 if !IS_SUPPORTED_SYSTEM {
2626 return;
2627 }
2628 let mut s = System::new();
2629 s.refresh_processes(ProcessesToUpdate::All, false);
2630 for proc_ in s.cpus() {
2631 assert_eq!(proc_.frequency(), 0);
2632 }
2633 s.refresh_cpu_usage();
2634 for proc_ in s.cpus() {
2635 assert_eq!(proc_.frequency(), 0);
2636 }
2637 // In a VM, it'll fail.
2638 if std::env::var("APPLE_CI").is_err() && std::env::var("FREEBSD_CI").is_err() {
2639 s.refresh_cpu_specifics(CpuRefreshKind::everything());
2640 for proc_ in s.cpus() {
2641 assert_ne!(proc_.frequency(), 0);
2642 }
2643 }
2644 }
2645
2646 #[test]
2647 fn check_process_memory_usage() {
2648 let mut s = System::new();
2649 s.refresh_specifics(RefreshKind::everything());
2650
2651 if IS_SUPPORTED_SYSTEM {
2652 // No process should have 0 as memory usage.
2653 #[cfg(not(feature = "apple-sandbox"))]
2654 assert!(!s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2655 } else {
2656 // There should be no process, but if there is one, its memory usage should be 0.
2657 assert!(s.processes().iter().all(|(_, proc_)| proc_.memory() == 0));
2658 }
2659 }
2660
2661 #[test]
2662 fn check_system_implemented_traits() {
2663 fn check<T: Sized + std::fmt::Debug + Default + Send + Sync>(_: T) {}
2664
2665 check(System::new());
2666 }
2667
2668 #[test]
2669 fn check_memory_usage() {
2670 let mut s = System::new();
2671
2672 assert_eq!(s.total_memory(), 0);
2673 assert_eq!(s.free_memory(), 0);
2674 assert_eq!(s.available_memory(), 0);
2675 assert_eq!(s.used_memory(), 0);
2676 assert_eq!(s.total_swap(), 0);
2677 assert_eq!(s.free_swap(), 0);
2678 assert_eq!(s.used_swap(), 0);
2679
2680 s.refresh_memory();
2681 if IS_SUPPORTED_SYSTEM {
2682 assert!(s.total_memory() > 0);
2683 assert!(s.used_memory() > 0);
2684 if s.total_swap() > 0 {
2685 // I think it's pretty safe to assume that there is still some swap left...
2686 assert!(s.free_swap() > 0);
2687 }
2688 } else {
2689 assert_eq!(s.total_memory(), 0);
2690 assert_eq!(s.used_memory(), 0);
2691 assert_eq!(s.total_swap(), 0);
2692 assert_eq!(s.free_swap(), 0);
2693 }
2694 }
2695
2696 #[cfg(target_os = "linux")]
2697 #[test]
2698 fn check_processes_cpu_usage() {
2699 if !IS_SUPPORTED_SYSTEM {
2700 return;
2701 }
2702 let mut s = System::new();
2703
2704 s.refresh_processes(ProcessesToUpdate::All, false);
2705 // All CPU usage will start at zero until the second refresh
2706 assert!(s
2707 .processes()
2708 .iter()
2709 .all(|(_, proc_)| proc_.cpu_usage() == 0.0));
2710
2711 // Wait a bit to update CPU usage values
2712 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
2713 s.refresh_processes(ProcessesToUpdate::All, true);
2714 assert!(s
2715 .processes()
2716 .iter()
2717 .all(|(_, proc_)| proc_.cpu_usage() >= 0.0
2718 && proc_.cpu_usage() <= (s.cpus().len() as f32) * 100.0));
2719 assert!(s
2720 .processes()
2721 .iter()
2722 .any(|(_, proc_)| proc_.cpu_usage() > 0.0));
2723 }
2724
2725 #[test]
2726 fn check_cpu_usage() {
2727 if !IS_SUPPORTED_SYSTEM {
2728 return;
2729 }
2730 let mut s = System::new();
2731 for _ in 0..10 {
2732 s.refresh_cpu_usage();
2733 // Wait a bit to update CPU usage values
2734 std::thread::sleep(MINIMUM_CPU_UPDATE_INTERVAL);
2735 if s.cpus().iter().any(|c| c.cpu_usage() > 0.0) {
2736 // All good!
2737 return;
2738 }
2739 }
2740 panic!("CPU usage is always zero...");
2741 }
2742
2743 #[test]
2744 fn check_system_info() {
2745 // We don't want to test on unsupported systems.
2746 if IS_SUPPORTED_SYSTEM {
2747 assert!(!System::name()
2748 .expect("Failed to get system name")
2749 .is_empty());
2750
2751 assert!(!System::kernel_version()
2752 .expect("Failed to get kernel version")
2753 .is_empty());
2754
2755 assert!(!System::os_version()
2756 .expect("Failed to get os version")
2757 .is_empty());
2758
2759 assert!(!System::long_os_version()
2760 .expect("Failed to get long OS version")
2761 .is_empty());
2762 }
2763
2764 assert!(!System::distribution_id().is_empty());
2765 }
2766
2767 #[test]
2768 fn check_host_name() {
2769 // We don't want to test on unsupported systems.
2770 if IS_SUPPORTED_SYSTEM {
2771 assert!(System::host_name().is_some());
2772 }
2773 }
2774
2775 #[test]
2776 fn check_refresh_process_return_value() {
2777 // We don't want to test on unsupported systems.
2778 if IS_SUPPORTED_SYSTEM {
2779 let _pid = get_current_pid().expect("Failed to get current PID");
2780
2781 #[cfg(not(feature = "apple-sandbox"))]
2782 {
2783 let mut s = System::new();
2784 // First check what happens in case the process isn't already in our process list.
2785 assert_eq!(
2786 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
2787 1
2788 );
2789 // Then check that it still returns 1 if the process is already in our process list.
2790 assert_eq!(
2791 s.refresh_processes(ProcessesToUpdate::Some(&[_pid]), true),
2792 1
2793 );
2794 }
2795 }
2796 }
2797
2798 #[test]
2799 fn check_cpus_number() {
2800 let mut s = System::new();
2801
2802 // This information isn't retrieved by default.
2803 assert!(s.cpus().is_empty());
2804 if IS_SUPPORTED_SYSTEM {
2805 // The physical cores count is recomputed every time the function is called, so the
2806 // information must be relevant even with nothing initialized.
2807 let physical_cores_count =
2808 System::physical_core_count().expect("failed to get number of physical cores");
2809
2810 s.refresh_cpu_usage();
2811 // The cpus shouldn't be empty anymore.
2812 assert!(!s.cpus().is_empty());
2813
2814 // In case we are running inside a VM, it's possible to not have a physical core, only
2815 // logical ones, which is why we don't test `physical_cores_count > 0`.
2816 let physical_cores_count2 =
2817 System::physical_core_count().expect("failed to get number of physical cores");
2818 assert!(physical_cores_count2 <= s.cpus().len());
2819 assert_eq!(physical_cores_count, physical_cores_count2);
2820 } else {
2821 assert_eq!(System::physical_core_count(), None);
2822 }
2823 assert!(System::physical_core_count().unwrap_or(0) <= s.cpus().len());
2824 }
2825
2826 // This test only exists to ensure that the `Display` and `Debug` traits are implemented on the
2827 // `ProcessStatus` enum on all targets.
2828 #[test]
2829 fn check_display_impl_process_status() {
2830 println!("{} {:?}", ProcessStatus::Parked, ProcessStatus::Idle);
2831 }
2832
2833 #[test]
2834 #[allow(clippy::unnecessary_fallible_conversions)]
2835 fn check_pid_from_impls() {
2836 assert!(crate::Pid::try_from(0usize).is_ok());
2837 // If it doesn't panic, it's fine.
2838 let _ = crate::Pid::from(0);
2839 assert!(crate::Pid::from_str("0").is_ok());
2840 }
2841
2842 #[test]
2843 #[allow(clippy::const_is_empty)]
2844 fn check_nb_supported_signals() {
2845 if IS_SUPPORTED_SYSTEM {
2846 assert!(
2847 !SUPPORTED_SIGNALS.is_empty(),
2848 "SUPPORTED_SIGNALS shouldn't be empty on supported systems!"
2849 );
2850 } else {
2851 assert!(
2852 SUPPORTED_SIGNALS.is_empty(),
2853 "SUPPORTED_SIGNALS should be empty on not support systems!"
2854 );
2855 }
2856 }
2857}
2858
2859#[cfg(doctest)]
2860mod doctest {
2861 // FIXME: Can be removed once negative trait bounds are supported.
2862 /// Check that `Process` doesn't implement `Clone`.
2863 ///
2864 /// First we check that the "basic" code works:
2865 ///
2866 /// ```no_run
2867 /// use sysinfo::{Process, System};
2868 ///
2869 /// let mut s = System::new_all();
2870 /// let p: &Process = s.processes().values().next().unwrap();
2871 /// ```
2872 ///
2873 /// And now we check if it fails when we try to clone it:
2874 ///
2875 /// ```compile_fail
2876 /// use sysinfo::{Process, System};
2877 ///
2878 /// let mut s = System::new_all();
2879 /// let p: &Process = s.processes().values().next().unwrap();
2880 /// let p = (*p).clone();
2881 /// ```
2882 mod process_clone {}
2883
2884 // FIXME: Can be removed once negative trait bounds are supported.
2885 /// Check that `System` doesn't implement `Clone`.
2886 ///
2887 /// First we check that the "basic" code works:
2888 ///
2889 /// ```no_run
2890 /// use sysinfo::{Process, System};
2891 ///
2892 /// let s = System::new();
2893 /// ```
2894 ///
2895 /// And now we check if it fails when we try to clone it:
2896 ///
2897 /// ```compile_fail
2898 /// use sysinfo::{Process, System};
2899 ///
2900 /// let s = System::new();
2901 /// let s = s.clone();
2902 /// ```
2903 mod system_clone {}
2904}