1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker
5*bb4ee6a4SAndroid Build Coastguard Worker use libc::EINVAL;
6*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::processthreadsapi::GetCurrentThread;
7*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::winbase::SetThreadAffinityMask;
8*bb4ee6a4SAndroid Build Coastguard Worker
9*bb4ee6a4SAndroid Build Coastguard Worker use super::errno_result;
10*bb4ee6a4SAndroid Build Coastguard Worker use super::Error;
11*bb4ee6a4SAndroid Build Coastguard Worker use super::Result;
12*bb4ee6a4SAndroid Build Coastguard Worker
13*bb4ee6a4SAndroid Build Coastguard Worker /// Set the CPU affinity of the current thread to a given set of CPUs.
14*bb4ee6a4SAndroid Build Coastguard Worker /// The cpus must be a subset of those in the process affinity mask.
15*bb4ee6a4SAndroid Build Coastguard Worker /// If there are more than 64 processors, the affinity mask must specify
16*bb4ee6a4SAndroid Build Coastguard Worker /// processors in the thread's current processor group.
17*bb4ee6a4SAndroid Build Coastguard Worker ///
18*bb4ee6a4SAndroid Build Coastguard Worker /// Returns the previous bits set for cpu_affinity.
19*bb4ee6a4SAndroid Build Coastguard Worker /// # Examples
20*bb4ee6a4SAndroid Build Coastguard Worker ///
21*bb4ee6a4SAndroid Build Coastguard Worker /// Set the calling thread's CPU affinity so it will run on only CPUs
22*bb4ee6a4SAndroid Build Coastguard Worker /// 0, 1, 5, and 6.
23*bb4ee6a4SAndroid Build Coastguard Worker ///
24*bb4ee6a4SAndroid Build Coastguard Worker /// ```
25*bb4ee6a4SAndroid Build Coastguard Worker /// # use base::windows::set_cpu_affinity;
26*bb4ee6a4SAndroid Build Coastguard Worker /// set_cpu_affinity(vec![0, 1, 5, 6]).unwrap();
27*bb4ee6a4SAndroid Build Coastguard Worker /// ```
set_cpu_affinity<I: IntoIterator<Item = usize>>(cpus: I) -> Result<usize>28*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_cpu_affinity<I: IntoIterator<Item = usize>>(cpus: I) -> Result<usize> {
29*bb4ee6a4SAndroid Build Coastguard Worker let mut affinity_mask: usize = 0;
30*bb4ee6a4SAndroid Build Coastguard Worker for cpu in cpus {
31*bb4ee6a4SAndroid Build Coastguard Worker if cpu >= 64 {
32*bb4ee6a4SAndroid Build Coastguard Worker return Err(Error::new(EINVAL));
33*bb4ee6a4SAndroid Build Coastguard Worker }
34*bb4ee6a4SAndroid Build Coastguard Worker affinity_mask |= 1 << cpu;
35*bb4ee6a4SAndroid Build Coastguard Worker }
36*bb4ee6a4SAndroid Build Coastguard Worker set_cpu_affinity_mask(affinity_mask)
37*bb4ee6a4SAndroid Build Coastguard Worker }
38*bb4ee6a4SAndroid Build Coastguard Worker
set_cpu_affinity_mask(affinity_mask: usize) -> Result<usize>39*bb4ee6a4SAndroid Build Coastguard Worker pub fn set_cpu_affinity_mask(affinity_mask: usize) -> Result<usize> {
40*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe as return value is checked.
41*bb4ee6a4SAndroid Build Coastguard Worker let res: usize = unsafe {
42*bb4ee6a4SAndroid Build Coastguard Worker let thread_handle = GetCurrentThread();
43*bb4ee6a4SAndroid Build Coastguard Worker SetThreadAffinityMask(thread_handle, affinity_mask)
44*bb4ee6a4SAndroid Build Coastguard Worker };
45*bb4ee6a4SAndroid Build Coastguard Worker if res == 0 {
46*bb4ee6a4SAndroid Build Coastguard Worker return errno_result::<usize>();
47*bb4ee6a4SAndroid Build Coastguard Worker }
48*bb4ee6a4SAndroid Build Coastguard Worker Ok(res)
49*bb4ee6a4SAndroid Build Coastguard Worker }
50*bb4ee6a4SAndroid Build Coastguard Worker
get_cpu_affinity() -> Result<Vec<usize>>51*bb4ee6a4SAndroid Build Coastguard Worker pub fn get_cpu_affinity() -> Result<Vec<usize>> {
52*bb4ee6a4SAndroid Build Coastguard Worker // Unimplemented for now, since this is unused on Windows. Thread affinity can be read by
53*bb4ee6a4SAndroid Build Coastguard Worker // calling GetThreadAffinityMask twice, to get and restore the previous affinities.
54*bb4ee6a4SAndroid Build Coastguard Worker Err(Error::new(EINVAL))
55*bb4ee6a4SAndroid Build Coastguard Worker }
56*bb4ee6a4SAndroid Build Coastguard Worker
57*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
58*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
59*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::processthreadsapi::GetCurrentProcess;
60*bb4ee6a4SAndroid Build Coastguard Worker use winapi::um::winbase::GetProcessAffinityMask;
61*bb4ee6a4SAndroid Build Coastguard Worker
62*bb4ee6a4SAndroid Build Coastguard Worker use super::super::sched::*;
63*bb4ee6a4SAndroid Build Coastguard Worker #[test]
cpu_affinity()64*bb4ee6a4SAndroid Build Coastguard Worker fn cpu_affinity() {
65*bb4ee6a4SAndroid Build Coastguard Worker let mut process_affinity_mask: usize = 0;
66*bb4ee6a4SAndroid Build Coastguard Worker let mut system_affinity_mask: usize = 0;
67*bb4ee6a4SAndroid Build Coastguard Worker // SAFETY: trivially safe as return value is checked.
68*bb4ee6a4SAndroid Build Coastguard Worker let res = unsafe {
69*bb4ee6a4SAndroid Build Coastguard Worker GetProcessAffinityMask(
70*bb4ee6a4SAndroid Build Coastguard Worker GetCurrentProcess(),
71*bb4ee6a4SAndroid Build Coastguard Worker &mut process_affinity_mask as *mut usize,
72*bb4ee6a4SAndroid Build Coastguard Worker &mut system_affinity_mask as *mut usize,
73*bb4ee6a4SAndroid Build Coastguard Worker )
74*bb4ee6a4SAndroid Build Coastguard Worker };
75*bb4ee6a4SAndroid Build Coastguard Worker assert_ne!(res, 0);
76*bb4ee6a4SAndroid Build Coastguard Worker let mut prev_thread_affinity = set_cpu_affinity(vec![0, 1]).unwrap();
77*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(process_affinity_mask, prev_thread_affinity);
78*bb4ee6a4SAndroid Build Coastguard Worker // reset to original process affinity and grab previous affinity.
79*bb4ee6a4SAndroid Build Coastguard Worker prev_thread_affinity = set_cpu_affinity_mask(process_affinity_mask).unwrap();
80*bb4ee6a4SAndroid Build Coastguard Worker // cpu 0 + cpu 1, means bit 0 and bit 1 are set (1 + 2 = 3). Verify that is the case.
81*bb4ee6a4SAndroid Build Coastguard Worker assert_eq!(prev_thread_affinity, 3);
82*bb4ee6a4SAndroid Build Coastguard Worker }
83*bb4ee6a4SAndroid Build Coastguard Worker }
84