@@ -171,7 +171,7 @@ pub(crate) fn available_cpus() -> Option<NonEmptyVec<usize>> {
171171 words = words. checked_mul ( 2 ) ?;
172172 words
173173 . checked_mul ( word_bits)
174- . map ( |bits| bits > MAX_AFFINITY_CPUS ) ?;
174+ . filter ( |bits| * bits <= MAX_AFFINITY_CPUS ) ?;
175175 }
176176 _ => return None ,
177177 }
@@ -200,12 +200,15 @@ pub(crate) fn available_cpus() -> Option<NonEmptyVec<usize>> {
200200}
201201
202202/// Sets the current thread's affinity mask to the given logical CPU ids.
203+ ///
204+ /// Returns an error if `cpus` is empty, contains an unreasonably large CPU id,
205+ /// or if the operating system rejects the affinity change.
203206#[ cfg( target_os = "linux" ) ]
204207pub ( crate ) fn set_cpu_affinity ( cpus : & [ usize ] ) -> Result < ( ) , std:: io:: Error > {
205- let Some ( max_cpu) = cpus. iter ( ) . copied ( ) . max ( ) else {
208+ let Some ( max_cpu) = cpus. iter ( ) . max ( ) else {
206209 return Err ( std:: io:: Error :: from_raw_os_error ( libc:: EINVAL ) ) ;
207210 } ;
208- if max_cpu >= MAX_AFFINITY_CPUS {
211+ if * max_cpu >= MAX_AFFINITY_CPUS {
209212 return Err ( std:: io:: Error :: from_raw_os_error ( libc:: EINVAL ) ) ;
210213 }
211214
@@ -236,16 +239,21 @@ pub(crate) fn set_cpu_affinity(cpus: &[usize]) -> Result<(), std::io::Error> {
236239 }
237240}
238241
242+ /// Sets the current thread's affinity mask to the given logical CPU ids.
243+ ///
244+ /// Always returns an error since setting CPU affinity is not available on this platform.
239245#[ cfg( not( target_os = "linux" ) ) ]
240246pub ( crate ) fn set_cpu_affinity ( _cpus : & [ usize ] ) -> Result < ( ) , std:: io:: Error > {
241247 Err ( std:: io:: Error :: other (
242- "cpu pinning is not available on this platform" ,
248+ "cpu affinity is not available on this platform" ,
243249 ) )
244250}
245251
246252#[ cfg( test) ]
247253mod tests {
248254 use super :: * ;
255+ #[ cfg( target_os = "linux" ) ]
256+ use commonware_utils:: vec:: NonEmptyVec ;
249257
250258 #[ cfg( target_os = "linux" ) ]
251259 #[ test]
@@ -261,18 +269,22 @@ mod tests {
261269 fn test_set_cpu_affinity_linux ( ) {
262270 std:: thread:: spawn ( || {
263271 let cpus = available_cpus ( ) . unwrap ( ) ;
264-
265272 let cpu = * cpus. first ( ) ;
266- set_cpu_affinity ( & [ cpu] ) . unwrap ( ) ;
267- assert_eq ! ( available_cpus( ) . unwrap( ) . into_vec( ) , vec![ cpu] ) ;
273+ let pinned = NonEmptyVec :: new ( cpu) ;
274+ set_cpu_affinity ( & pinned) . unwrap ( ) ;
275+ assert_eq ! ( available_cpus( ) , Some ( pinned) ) ;
268276
269- let invalid_cpu = ( 0 ..=MAX_AFFINITY_CPUS )
270- . find ( |candidate| !cpus. contains ( candidate) )
271- . unwrap ( ) ;
277+ let invalid_cpu = cpus. last ( ) . checked_add ( 1 ) . unwrap ( ) ;
272278 assert ! (
273279 set_cpu_affinity( & [ invalid_cpu] ) . is_err( ) ,
274- "expected pinning to a disallowed CPU to fail" ,
280+ "expected affinity to a disallowed CPU to fail" ,
275281 ) ;
282+
283+ let err = set_cpu_affinity ( & [ ] ) . unwrap_err ( ) ;
284+ assert_eq ! ( err. raw_os_error( ) , Some ( libc:: EINVAL ) ) ;
285+
286+ let err = set_cpu_affinity ( & [ MAX_AFFINITY_CPUS ] ) . unwrap_err ( ) ;
287+ assert_eq ! ( err. raw_os_error( ) , Some ( libc:: EINVAL ) ) ;
276288 } )
277289 . join ( )
278290 . unwrap ( ) ;
@@ -287,8 +299,6 @@ mod tests {
287299 #[ cfg( not( target_os = "linux" ) ) ]
288300 #[ test]
289301 fn test_set_cpu_affinity_non_linux ( ) {
290- for cpus in [ vec ! [ 0 ] , vec ! [ 1 ] , vec ! [ usize :: MAX ] ] {
291- assert ! ( set_cpu_affinity( & cpus) . is_err( ) ) ;
292- }
302+ assert ! ( set_cpu_affinity( & [ 0 ] ) . is_err( ) ) ;
293303 }
294304}
0 commit comments