1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
#![cfg_attr(not(feature = "std"), no_std)] #[cfg_attr(unix, path = "./unix.rs")] mod imp; #[derive(Debug, PartialEq, Eq, PartialOrd, Ord)] /// A prioritisation level /// /// The priority of a [`Process`] controls how much CPU time it gets /// compared to other processes. Most programs don't need to be handled /// especially, and should be given a [normal](Priority::normal) priority /// to allow the OS to handle scheduling pub struct Priority(imp::Priority); impl Priority { // TODO: consider declaring these as `const fn` /// The priority level given to normal processes; The default priority /// level. /// /// ```rust /// # use meek::{Process, Priority}; /// assert_eq!(Process::current().priority().unwrap(), Priority::normal(), /// "I'm normal! Normal I tell you!"); /// ``` pub fn normal() -> Self { Self(imp::Priority::normal()) } /// Raise the priority level. /// /// Be particularly careful with giving processes higher priority levels: /// Any process with a lower level will be halted until it pauses. /// Therefore, make sure any work it does is breif, and it uses OS APIs for /// delays ([`std::thread::sleep`] instead of `loop {}`) pub fn higher(&self) -> impl Iterator<Item = Self> { self.0.higher().map(Self) } /// Lower the priority level. /// /// Processes with lower priority levels will pause if other processes need /// to do work. They can be used for screen-savers e.t.c. pub fn lower(&self) -> impl Iterator<Item = Self> { self.0.lower().map(Self) } } #[derive(Debug)] /// A process running on this machine. /// /// These values should be treated as references to the processes held by the /// OS. As we don't own the process ourselves, there is no guarantee that the /// [`Process`] "reference" is still valid: someone else could've killed it. /// The methods return a [`NotFound`] error if they are ever called on a dead /// process. pub struct Process<'a>(imp::Process<'a>); impl Process<'_> { /// Get the currently running process /// /// Note that this is will last for `'static`, since there is no way for /// the value to be used *after this process dies*. pub fn current() -> Process<'static> { Process(imp::Process::current()) } /// Update the priority of this process /// /// Each platform has a set of rules around who can set whose priority, /// and you should check the documentation for your platform to make sure /// you are setting up the right permissions. [`Error`] doesn't expose /// the reason for the error (yet? File an issue if this would be useful /// for you). pub fn set_priority(&mut self, priority: Priority) -> Result<(), Error> { self.0.set_priority(priority.0) } /// Fetch the priority of this process pub fn priority(&self) -> Result<Priority, NotFound> { self.0.priority().map(Priority) } } // TODO: This API sorta sucks. Would Process::of_child(&Child) be better? // The name's less than obvious #[cfg(feature = "std")] impl<'a> From<&'a mut std::process::Child> for Process<'a> { fn from(child: &'a mut std::process::Child) -> Self { Self(child.into()) } } /// The process couldn't be found. /// /// See [`Process`] for details. #[derive(Debug)] pub struct NotFound; // TODO: Choose a more descriptive name for this type #[derive(Debug)] pub enum Error { // This could be much cleaner with [enum variant types], which would // let `Process::priority` return `Result<Priority, Error::NotFound>` // // [enum variant types]: https://github.com/rust-lang/rfcs/pull/2593 NotFound(NotFound), /// The [`Process`] handle didn't have the suitable permissions to /// set priority. NotAllowed, } impl From<NotFound> for Error { fn from(n: NotFound) -> Self { Self::NotFound(n) } } impl core::fmt::Display for NotFound { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { f.write_str("couldn't set priority of missing process") } } impl core::fmt::Display for Error { fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result { match self { Self::NotFound(n) => core::fmt::Display::fmt(n, f), Self::NotAllowed => f.write_str("missing permissions to set priority"), } } } #[cfg(feature = "std")] impl std::error::Error for NotFound {} #[cfg(feature = "std")] impl std::error::Error for Error {}