1818pub mod unix;
1919#[ cfg( unix) ]
2020pub use unix:: * ;
21+
2122#[ cfg( windows) ]
2223pub mod windows;
2324#[ cfg( windows) ]
@@ -31,19 +32,23 @@ pub enum Error {
3132 /// Target OS' error type. In most systems it is an integer which
3233 /// later should be used with target OS' API for understanding the value.
3334 OS ( i32 ) ,
34- /// FFI failure
35+ /// FFI failure.
3536 Ffi ( & ' static str ) ,
3637}
3738
39+ /// Platform-specific thread priority value.
40+ #[ derive( Copy , Clone , Debug , Default , Eq , PartialEq , Ord , PartialOrd , Hash ) ]
41+ pub struct ThreadPriorityValue ( pub u32 ) ;
42+
3843/// Thread priority enumeration.
39- #[ derive( Debug , Copy , Clone , Eq , PartialEq , Ord , PartialOrd ) ]
44+ #[ derive( Debug , Copy , Clone , Hash , Eq , PartialEq , Ord , PartialOrd ) ]
4045pub enum ThreadPriority {
4146 /// Holds a value representing the minimum possible priority.
4247 Min ,
4348 /// Holds a specific priority value. Should be in [0; 100] range,
4449 /// a percentage value. The `u32` value is reserved for different
4550 /// OS'es support.
46- Specific ( u32 ) ,
51+ Specific ( ThreadPriorityValue ) ,
4752 /// Holds scheduling parameters for Deadline scheduling. These are, in order,
4853 /// the nanoseconds for runtime, deadline, and period. Please note that the
4954 /// kernel enforces runtime <= deadline <= period.
@@ -90,3 +95,260 @@ impl Thread {
9095 } )
9196 }
9297}
98+
99+ /// A copy of the [`std::thread::Builder`] builder allowing to set priority settings.
100+ ///
101+ /// ```rust
102+ /// use thread_priority::*;
103+ ///
104+ /// let thread = ThreadBuilder::default()
105+ /// .name("MyThread")
106+ /// .priority(ThreadPriority::Max)
107+ /// .spawn(|result| {
108+ /// // This is printed out from within the spawned thread.
109+ /// println!("Set priority result: {:?}", result);
110+ /// assert!(result.is_ok());
111+ /// }).unwrap();
112+ /// thread.join();
113+ ///
114+ /// // Another example where we don't care about the priority having been set.
115+ /// let thread = ThreadBuilder::default()
116+ /// .name("MyThread")
117+ /// .priority(ThreadPriority::Max)
118+ /// .spawn_careless(|| {
119+ /// // This is printed out from within the spawned thread.
120+ /// println!("We don't care about the priority result.");
121+ /// }).unwrap();
122+ /// thread.join();
123+ /// ```
124+ #[ derive( Clone , Debug , Default , Hash , Eq , PartialEq , Ord , PartialOrd ) ]
125+ pub struct ThreadBuilder {
126+ name : Option < String > ,
127+ stack_size : Option < usize > ,
128+ priority : Option < ThreadPriority > ,
129+
130+ #[ cfg( unix) ]
131+ policy : Option < ThreadSchedulePolicy > ,
132+ // #[cfg(windows)]
133+ // winapi_priority: Option<WinAPIThreadPriority>,
134+ // #[cfg(windows)]
135+ // boost_enabled: bool,
136+ // #[cfg(windows)]
137+ // ideal_processor: IdealProcessor,
138+ }
139+
140+ impl ThreadBuilder {
141+ /// Names the thread-to-be. Currently the name is used for identification
142+ /// only in panic messages.
143+ ///
144+ /// The name must not contain null bytes (`\0`).
145+ ///
146+ /// For more information about named threads, see
147+ /// [`std::thread::Builder::name()`].
148+ pub fn name < VALUE : Into < String > > ( mut self , value : VALUE ) -> Self {
149+ self . name = Some ( value. into ( ) ) ;
150+ self
151+ }
152+
153+ /// Sets the size of the stack (in bytes) for the new thread.
154+ ///
155+ /// The actual stack size may be greater than this value if
156+ /// the platform specifies a minimal stack size.
157+ ///
158+ /// For more information about the stack size for threads, see
159+ /// [`std::thread::Builder::stack_size()`].
160+ pub fn stack_size < VALUE : Into < usize > > ( mut self , value : VALUE ) -> Self {
161+ self . stack_size = Some ( value. into ( ) ) ;
162+ self
163+ }
164+
165+ /// The thread's custom priority.
166+ ///
167+ /// For more information about the stack size for threads, see
168+ /// [`ThreadPriority`].
169+ pub fn priority < VALUE : Into < ThreadPriority > > ( mut self , value : VALUE ) -> Self {
170+ self . priority = Some ( value. into ( ) ) ;
171+ self
172+ }
173+
174+ /// The thread's unix scheduling policy.
175+ ///
176+ /// For more information, see
177+ /// [`crate::unix::ThreadSchedulePolicy`] and [`crate::unix::set_thread_priority_and_policy`].
178+ #[ cfg( unix) ]
179+ pub fn policy < VALUE : Into < unix:: ThreadSchedulePolicy > > ( mut self , value : VALUE ) -> Self {
180+ self . policy = Some ( value. into ( ) ) ;
181+ self
182+ }
183+
184+ /// Spawns a new thread by taking ownership of the `Builder`, and returns an
185+ /// [`std::io::Result`] to its [`std::thread::JoinHandle`].
186+ ///
187+ /// See [`std::thread::Builder::spawn`]
188+ pub fn spawn < F , T > ( mut self , f : F ) -> std:: io:: Result < std:: thread:: JoinHandle < T > >
189+ where
190+ F : FnOnce ( Result < ( ) , Error > ) -> T ,
191+ F : Send + ' static ,
192+ T : Send + ' static ,
193+ {
194+ let priority = self . priority ;
195+ let policy = self . policy ;
196+
197+ self . build_std ( ) . spawn ( move || match ( priority, policy) {
198+ ( Some ( priority) , Some ( policy) ) => f ( set_thread_priority_and_policy (
199+ thread_native_id ( ) ,
200+ priority,
201+ policy,
202+ ) ) ,
203+ ( Some ( priority) , None ) => f ( priority. set_for_current ( ) ) ,
204+ ( None , Some ( _policy) ) => {
205+ unimplemented ! ( "Setting the policy separately isn't currently supported." ) ;
206+ }
207+ _ => f ( Ok ( ( ) ) ) ,
208+ } )
209+ }
210+
211+ fn build_std ( & mut self ) -> std:: thread:: Builder {
212+ let mut builder = std:: thread:: Builder :: new ( ) ;
213+
214+ if let Some ( name) = & self . name {
215+ builder = builder. name ( name. to_owned ( ) ) ;
216+ }
217+
218+ if let Some ( stack_size) = self . stack_size {
219+ builder = builder. stack_size ( stack_size) ;
220+ }
221+
222+ builder
223+ }
224+
225+ /// Spawns a new thread by taking ownership of the `Builder`, and returns an
226+ /// [`std::io::Result`] to its [`std::thread::JoinHandle`].
227+ ///
228+ /// See [`std::thread::Builder::spawn`]
229+ pub fn spawn_careless < F , T > ( self , f : F ) -> std:: io:: Result < std:: thread:: JoinHandle < T > >
230+ where
231+ F : FnOnce ( ) -> T ,
232+ F : Send + ' static ,
233+ T : Send + ' static ,
234+ {
235+ self . spawn ( |priority_set_result| {
236+ if let Err ( e) = priority_set_result {
237+ log:: warn!(
238+ "Couldn't set the priority for the thread with Rust Thread ID {:?} named {:?}: {:?}" ,
239+ std:: thread:: current( ) . id( ) ,
240+ std:: thread:: current( ) . name( ) ,
241+ e,
242+ ) ;
243+ }
244+
245+ f ( )
246+ } )
247+ }
248+ }
249+
250+ /// Adds thread building functions using the priority.
251+ pub trait ThreadBuilderExt {
252+ /// Spawn a thread with set priority. The passed functor `f` is executed in the spawned thread and
253+ /// receives as the only argument the result of setting the thread priority.
254+ /// See [`std::thread::Builder::spawn`] and [`ThreadPriority::set_for_current`] for more info.
255+ ///
256+ /// # Example
257+ ///
258+ /// ```rust
259+ /// use thread_priority::*;
260+ /// use thread_priority::ThreadBuilderExt;
261+ ///
262+ /// let thread = std::thread::Builder::new()
263+ /// .name("MyNewThread".to_owned())
264+ /// .spawn_with_priority(ThreadPriority::Max, |result| {
265+ /// // This is printed out from within the spawned thread.
266+ /// println!("Set priority result: {:?}", result);
267+ /// assert!(result.is_ok());
268+ /// }).unwrap();
269+ /// thread.join();
270+ /// ```
271+ fn spawn_with_priority < F , T > (
272+ self ,
273+ priority : ThreadPriority ,
274+ f : F ,
275+ ) -> std:: io:: Result < std:: thread:: JoinHandle < T > >
276+ where
277+ F : FnOnce ( Result < ( ) , Error > ) -> T ,
278+ F : Send + ' static ,
279+ T : Send + ' static ;
280+ }
281+
282+ impl ThreadBuilderExt for std:: thread:: Builder {
283+ fn spawn_with_priority < F , T > (
284+ self ,
285+ priority : ThreadPriority ,
286+ f : F ,
287+ ) -> std:: io:: Result < std:: thread:: JoinHandle < T > >
288+ where
289+ F : FnOnce ( Result < ( ) , Error > ) -> T ,
290+ F : Send + ' static ,
291+ T : Send + ' static ,
292+ {
293+ self . spawn ( move || f ( priority. set_for_current ( ) ) )
294+ }
295+ }
296+
297+ /// Spawns a thread with the specified priority.
298+ ///
299+ /// See [`ThreadBuilderExt::spawn_with_priority`].
300+ ///
301+ /// ```rust
302+ /// use thread_priority::*;
303+ ///
304+ /// let thread = spawn(ThreadPriority::Max, |result| {
305+ /// // This is printed out from within the spawned thread.
306+ /// println!("Set priority result: {:?}", result);
307+ /// assert!(result.is_ok());
308+ /// });
309+ /// thread.join();
310+ /// ```
311+ pub fn spawn < F , T > ( priority : ThreadPriority , f : F ) -> std:: thread:: JoinHandle < T >
312+ where
313+ F : FnOnce ( Result < ( ) , Error > ) -> T ,
314+ F : Send + ' static ,
315+ T : Send + ' static ,
316+ {
317+ std:: thread:: spawn ( move || f ( priority. set_for_current ( ) ) )
318+ }
319+
320+ /// Spawns a thread with the specified priority.
321+ /// This is different from [`spawn`] in a way that the passed function doesn't
322+ /// need to accept the [`ThreadPriority::set_for_current`] result.
323+ /// In case of an error, the error is logged using the logging facilities.
324+ ///
325+ /// See [`spawn`].
326+ ///
327+ /// ```rust
328+ /// use thread_priority::*;
329+ ///
330+ /// let thread = spawn_careless(ThreadPriority::Max, || {
331+ /// // This is printed out from within the spawned thread.
332+ /// println!("We don't care about the priority result.");
333+ /// });
334+ /// thread.join();
335+ /// ```
336+ pub fn spawn_careless < F , T > ( priority : ThreadPriority , f : F ) -> std:: thread:: JoinHandle < T >
337+ where
338+ F : FnOnce ( ) -> T ,
339+ F : Send + ' static ,
340+ T : Send + ' static ,
341+ {
342+ std:: thread:: spawn ( move || {
343+ if let Err ( e) = priority. set_for_current ( ) {
344+ log:: warn!(
345+ "Couldn't set the priority for the thread with Rust Thread ID {:?} named {:?}: {:?}" ,
346+ std:: thread:: current( ) . id( ) ,
347+ std:: thread:: current( ) . name( ) ,
348+ e,
349+ ) ;
350+ }
351+
352+ f ( )
353+ } )
354+ }
0 commit comments