diff options
Diffstat (limited to 'rust/kernel')
| -rw-r--r-- | rust/kernel/cpu.rs | 125 | ||||
| -rw-r--r-- | rust/kernel/cpufreq.rs | 173 | ||||
| -rw-r--r-- | rust/kernel/cpumask.rs | 51 | 
3 files changed, 287 insertions, 62 deletions
| diff --git a/rust/kernel/cpu.rs b/rust/kernel/cpu.rs index 10c5c3b25873..b75403b0eb56 100644 --- a/rust/kernel/cpu.rs +++ b/rust/kernel/cpu.rs @@ -6,6 +6,127 @@  use crate::{bindings, device::Device, error::Result, prelude::ENODEV}; +/// Returns the maximum number of possible CPUs in the current system configuration. +#[inline] +pub fn nr_cpu_ids() -> u32 { +    #[cfg(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS))] +    { +        bindings::NR_CPUS +    } + +    #[cfg(not(any(NR_CPUS_1, CONFIG_FORCE_NR_CPUS)))] +    // SAFETY: `nr_cpu_ids` is a valid global provided by the kernel. +    unsafe { +        bindings::nr_cpu_ids +    } +} + +/// The CPU ID. +/// +/// Represents a CPU identifier as a wrapper around an [`u32`]. +/// +/// # Invariants +/// +/// The CPU ID lies within the range `[0, nr_cpu_ids())`. +/// +/// # Examples +/// +/// ``` +/// use kernel::cpu::CpuId; +/// +/// let cpu = 0; +/// +/// // SAFETY: 0 is always a valid CPU number. +/// let id = unsafe { CpuId::from_u32_unchecked(cpu) }; +/// +/// assert_eq!(id.as_u32(), cpu); +/// assert!(CpuId::from_i32(0).is_some()); +/// assert!(CpuId::from_i32(-1).is_none()); +/// ``` +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub struct CpuId(u32); + +impl CpuId { +    /// Creates a new [`CpuId`] from the given `id` without checking bounds. +    /// +    /// # Safety +    /// +    /// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`). +    #[inline] +    pub unsafe fn from_i32_unchecked(id: i32) -> Self { +        debug_assert!(id >= 0); +        debug_assert!((id as u32) < nr_cpu_ids()); + +        // INVARIANT: The function safety guarantees `id` is a valid CPU id. +        Self(id as u32) +    } + +    /// Creates a new [`CpuId`] from the given `id`, checking that it is valid. +    pub fn from_i32(id: i32) -> Option<Self> { +        if id < 0 || id as u32 >= nr_cpu_ids() { +            None +        } else { +            // INVARIANT: `id` has just been checked as a valid CPU ID. +            Some(Self(id as u32)) +        } +    } + +    /// Creates a new [`CpuId`] from the given `id` without checking bounds. +    /// +    /// # Safety +    /// +    /// The caller must ensure that `id` is a valid CPU ID (i.e., `0 <= id < nr_cpu_ids()`). +    #[inline] +    pub unsafe fn from_u32_unchecked(id: u32) -> Self { +        debug_assert!(id < nr_cpu_ids()); + +        // Ensure the `id` fits in an [`i32`] as it's also representable that way. +        debug_assert!(id <= i32::MAX as u32); + +        // INVARIANT: The function safety guarantees `id` is a valid CPU id. +        Self(id) +    } + +    /// Creates a new [`CpuId`] from the given `id`, checking that it is valid. +    pub fn from_u32(id: u32) -> Option<Self> { +        if id >= nr_cpu_ids() { +            None +        } else { +            // INVARIANT: `id` has just been checked as a valid CPU ID. +            Some(Self(id)) +        } +    } + +    /// Returns CPU number. +    #[inline] +    pub fn as_u32(&self) -> u32 { +        self.0 +    } + +    /// Returns the ID of the CPU the code is currently running on. +    /// +    /// The returned value is considered unstable because it may change +    /// unexpectedly due to preemption or CPU migration. It should only be +    /// used when the context ensures that the task remains on the same CPU +    /// or the users could use a stale (yet valid) CPU ID. +    pub fn current() -> Self { +        // SAFETY: raw_smp_processor_id() always returns a valid CPU ID. +        unsafe { Self::from_u32_unchecked(bindings::raw_smp_processor_id()) } +    } +} + +impl From<CpuId> for u32 { +    fn from(id: CpuId) -> Self { +        id.as_u32() +    } +} + +impl From<CpuId> for i32 { +    fn from(id: CpuId) -> Self { +        id.as_u32() as i32 +    } +} +  /// Creates a new instance of CPU's device.  ///  /// # Safety @@ -17,9 +138,9 @@ use crate::{bindings, device::Device, error::Result, prelude::ENODEV};  /// Callers must ensure that the CPU device is not used after it has been unregistered.  /// This can be achieved, for example, by registering a CPU hotplug notifier and removing  /// any references to the CPU device within the notifier's callback. -pub unsafe fn from_cpu(cpu: u32) -> Result<&'static Device> { +pub unsafe fn from_cpu(cpu: CpuId) -> Result<&'static Device> {      // SAFETY: It is safe to call `get_cpu_device()` for any CPU. -    let ptr = unsafe { bindings::get_cpu_device(cpu) }; +    let ptr = unsafe { bindings::get_cpu_device(u32::from(cpu)) };      if ptr.is_null() {          return Err(ENODEV);      } diff --git a/rust/kernel/cpufreq.rs b/rust/kernel/cpufreq.rs index b0a9c6182aec..11b03e9d7e89 100644 --- a/rust/kernel/cpufreq.rs +++ b/rust/kernel/cpufreq.rs @@ -10,6 +10,7 @@  use crate::{      clk::Hertz, +    cpu::CpuId,      cpumask,      device::{Bound, Device},      devres::Devres, @@ -465,8 +466,9 @@ impl Policy {      /// Returns the primary CPU for the [`Policy`].      #[inline] -    pub fn cpu(&self) -> u32 { -        self.as_ref().cpu +    pub fn cpu(&self) -> CpuId { +        // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. +        unsafe { CpuId::from_u32_unchecked(self.as_ref().cpu) }      }      /// Returns the minimum frequency for the [`Policy`]. @@ -525,7 +527,7 @@ impl Policy {      #[inline]      pub fn generic_get(&self) -> Result<u32> {          // SAFETY: By the type invariant, the pointer stored in `self` is valid. -        Ok(unsafe { bindings::cpufreq_generic_get(self.cpu()) }) +        Ok(unsafe { bindings::cpufreq_generic_get(u32::from(self.cpu())) })      }      /// Provides a wrapper to the register with energy model using the OPP core. @@ -678,9 +680,9 @@ impl Policy {  struct PolicyCpu<'a>(&'a mut Policy);  impl<'a> PolicyCpu<'a> { -    fn from_cpu(cpu: u32) -> Result<Self> { +    fn from_cpu(cpu: CpuId) -> Result<Self> {          // SAFETY: It is safe to call `cpufreq_cpu_get` for any valid CPU. -        let ptr = from_err_ptr(unsafe { bindings::cpufreq_cpu_get(cpu) })?; +        let ptr = from_err_ptr(unsafe { bindings::cpufreq_cpu_get(u32::from(cpu)) })?;          Ok(Self(              // SAFETY: The `ptr` is guaranteed to be valid and remains valid for the lifetime of @@ -1055,8 +1057,11 @@ impl<T: Driver> Registration<T> {  impl<T: Driver> Registration<T> {      /// Driver's `init` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn init_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {          from_result(|| {              // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the              // lifetime of `policy`. @@ -1070,8 +1075,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `exit` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn exit_callback(ptr: *mut bindings::cpufreq_policy) {          // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the          // lifetime of `policy`.          let policy = unsafe { Policy::from_raw_mut(ptr) }; @@ -1082,8 +1090,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `online` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn online_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {          from_result(|| {              // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the              // lifetime of `policy`. @@ -1094,8 +1105,13 @@ impl<T: Driver> Registration<T> {      /// Driver's `offline` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn offline_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn offline_callback( +        ptr: *mut bindings::cpufreq_policy, +    ) -> kernel::ffi::c_int {          from_result(|| {              // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the              // lifetime of `policy`. @@ -1106,8 +1122,13 @@ impl<T: Driver> Registration<T> {      /// Driver's `suspend` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn suspend_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn suspend_callback( +        ptr: *mut bindings::cpufreq_policy, +    ) -> kernel::ffi::c_int {          from_result(|| {              // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the              // lifetime of `policy`. @@ -1118,8 +1139,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `resume` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn resume_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int {          from_result(|| {              // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the              // lifetime of `policy`. @@ -1130,8 +1154,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `ready` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn ready_callback(ptr: *mut bindings::cpufreq_policy) {          // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the          // lifetime of `policy`.          let policy = unsafe { Policy::from_raw_mut(ptr) }; @@ -1140,8 +1167,13 @@ impl<T: Driver> Registration<T> {      /// Driver's `verify` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn verify_callback(ptr: *mut bindings::cpufreq_policy_data) -> kernel::ffi::c_int { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn verify_callback( +        ptr: *mut bindings::cpufreq_policy_data, +    ) -> kernel::ffi::c_int {          from_result(|| {              // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the              // lifetime of `policy`. @@ -1152,8 +1184,13 @@ impl<T: Driver> Registration<T> {      /// Driver's `setpolicy` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn setpolicy_callback(ptr: *mut bindings::cpufreq_policy) -> kernel::ffi::c_int { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn setpolicy_callback( +        ptr: *mut bindings::cpufreq_policy, +    ) -> kernel::ffi::c_int {          from_result(|| {              // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the              // lifetime of `policy`. @@ -1164,8 +1201,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `target` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn target_callback( +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn target_callback(          ptr: *mut bindings::cpufreq_policy,          target_freq: u32,          relation: u32, @@ -1180,8 +1220,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `target_index` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn target_index_callback( +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn target_index_callback(          ptr: *mut bindings::cpufreq_policy,          index: u32,      ) -> kernel::ffi::c_int { @@ -1200,8 +1243,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `fast_switch` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn fast_switch_callback( +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn fast_switch_callback(          ptr: *mut bindings::cpufreq_policy,          target_freq: u32,      ) -> kernel::ffi::c_uint { @@ -1212,21 +1258,31 @@ impl<T: Driver> Registration<T> {      }      /// Driver's `adjust_perf` callback. -    extern "C" fn adjust_perf_callback( +    /// +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    unsafe extern "C" fn adjust_perf_callback(          cpu: u32,          min_perf: usize,          target_perf: usize,          capacity: usize,      ) { -        if let Ok(mut policy) = PolicyCpu::from_cpu(cpu) { +        // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. +        let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) }; + +        if let Ok(mut policy) = PolicyCpu::from_cpu(cpu_id) {              T::adjust_perf(&mut policy, min_perf, target_perf, capacity);          }      }      /// Driver's `get_intermediate` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn get_intermediate_callback( +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn get_intermediate_callback(          ptr: *mut bindings::cpufreq_policy,          index: u32,      ) -> kernel::ffi::c_uint { @@ -1243,8 +1299,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `target_intermediate` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn target_intermediate_callback( +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn target_intermediate_callback(          ptr: *mut bindings::cpufreq_policy,          index: u32,      ) -> kernel::ffi::c_int { @@ -1262,12 +1321,24 @@ impl<T: Driver> Registration<T> {      }      /// Driver's `get` callback. -    extern "C" fn get_callback(cpu: u32) -> kernel::ffi::c_uint { -        PolicyCpu::from_cpu(cpu).map_or(0, |mut policy| T::get(&mut policy).map_or(0, |f| f)) +    /// +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    unsafe extern "C" fn get_callback(cpu: u32) -> kernel::ffi::c_uint { +        // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. +        let cpu_id = unsafe { CpuId::from_u32_unchecked(cpu) }; + +        PolicyCpu::from_cpu(cpu_id).map_or(0, |mut policy| T::get(&mut policy).map_or(0, |f| f))      }      /// Driver's `update_limit` callback. -    extern "C" fn update_limits_callback(ptr: *mut bindings::cpufreq_policy) { +    /// +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn update_limits_callback(ptr: *mut bindings::cpufreq_policy) {          // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the          // lifetime of `policy`.          let policy = unsafe { Policy::from_raw_mut(ptr) }; @@ -1276,10 +1347,16 @@ impl<T: Driver> Registration<T> {      /// Driver's `bios_limit` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> kernel::ffi::c_int { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn bios_limit_callback(cpu: i32, limit: *mut u32) -> kernel::ffi::c_int { +        // SAFETY: The C API guarantees that `cpu` refers to a valid CPU number. +        let cpu_id = unsafe { CpuId::from_i32_unchecked(cpu) }; +          from_result(|| { -            let mut policy = PolicyCpu::from_cpu(cpu as u32)?; +            let mut policy = PolicyCpu::from_cpu(cpu_id)?;              // SAFETY: `limit` is guaranteed by the C code to be valid.              T::bios_limit(&mut policy, &mut (unsafe { *limit })).map(|()| 0) @@ -1288,8 +1365,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `set_boost` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn set_boost_callback( +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn set_boost_callback(          ptr: *mut bindings::cpufreq_policy,          state: i32,      ) -> kernel::ffi::c_int { @@ -1303,8 +1383,11 @@ impl<T: Driver> Registration<T> {      /// Driver's `register_em` callback.      /// -    /// SAFETY: Called from C. Inputs must be valid pointers. -    extern "C" fn register_em_callback(ptr: *mut bindings::cpufreq_policy) { +    /// # Safety +    /// +    /// - This function may only be called from the cpufreq C infrastructure. +    /// - The pointer arguments must be valid pointers. +    unsafe extern "C" fn register_em_callback(ptr: *mut bindings::cpufreq_policy) {          // SAFETY: The `ptr` is guaranteed to be valid by the contract with the C code for the          // lifetime of `policy`.          let policy = unsafe { Policy::from_raw_mut(ptr) }; diff --git a/rust/kernel/cpumask.rs b/rust/kernel/cpumask.rs index c90bfac9346a..19c607709b5f 100644 --- a/rust/kernel/cpumask.rs +++ b/rust/kernel/cpumask.rs @@ -6,6 +6,7 @@  use crate::{      alloc::{AllocError, Flags}, +    cpu::CpuId,      prelude::*,      types::Opaque,  }; @@ -35,9 +36,10 @@ use core::ops::{Deref, DerefMut};  ///  /// ```  /// use kernel::bindings; +/// use kernel::cpu::CpuId;  /// use kernel::cpumask::Cpumask;  /// -/// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: u32, clear_cpu: i32) { +/// fn set_clear_cpu(ptr: *mut bindings::cpumask, set_cpu: CpuId, clear_cpu: CpuId) {  ///     // SAFETY: The `ptr` is valid for writing and remains valid for the lifetime of the  ///     // returned reference.  ///     let mask = unsafe { Cpumask::as_mut_ref(ptr) }; @@ -90,9 +92,9 @@ impl Cpumask {      /// This mismatches kernel naming convention and corresponds to the C      /// function `__cpumask_set_cpu()`.      #[inline] -    pub fn set(&mut self, cpu: u32) { +    pub fn set(&mut self, cpu: CpuId) {          // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `__cpumask_set_cpu`. -        unsafe { bindings::__cpumask_set_cpu(cpu, self.as_raw()) }; +        unsafe { bindings::__cpumask_set_cpu(u32::from(cpu), self.as_raw()) };      }      /// Clear `cpu` in the cpumask. @@ -101,19 +103,19 @@ impl Cpumask {      /// This mismatches kernel naming convention and corresponds to the C      /// function `__cpumask_clear_cpu()`.      #[inline] -    pub fn clear(&mut self, cpu: i32) { +    pub fn clear(&mut self, cpu: CpuId) {          // SAFETY: By the type invariant, `self.as_raw` is a valid argument to          // `__cpumask_clear_cpu`. -        unsafe { bindings::__cpumask_clear_cpu(cpu, self.as_raw()) }; +        unsafe { bindings::__cpumask_clear_cpu(i32::from(cpu), self.as_raw()) };      }      /// Test `cpu` in the cpumask.      ///      /// Equivalent to the kernel's `cpumask_test_cpu` API.      #[inline] -    pub fn test(&self, cpu: i32) -> bool { +    pub fn test(&self, cpu: CpuId) -> bool {          // SAFETY: By the type invariant, `self.as_raw` is a valid argument to `cpumask_test_cpu`. -        unsafe { bindings::cpumask_test_cpu(cpu, self.as_raw()) } +        unsafe { bindings::cpumask_test_cpu(i32::from(cpu), self.as_raw()) }      }      /// Set all CPUs in the cpumask. @@ -178,21 +180,40 @@ impl Cpumask {  /// The following example demonstrates how to create and update a [`CpumaskVar`].  ///  /// ``` +/// use kernel::cpu::CpuId;  /// use kernel::cpumask::CpumaskVar;  ///  /// let mut mask = CpumaskVar::new_zero(GFP_KERNEL).unwrap();  ///  /// assert!(mask.empty()); -/// mask.set(2); -/// assert!(mask.test(2)); -/// mask.set(3); -/// assert!(mask.test(3)); -/// assert_eq!(mask.weight(), 2); +/// let mut count = 0; +/// +/// let cpu2 = CpuId::from_u32(2); +/// if let Some(cpu) = cpu2 { +///     mask.set(cpu); +///     assert!(mask.test(cpu)); +///     count += 1; +/// } +/// +/// let cpu3 = CpuId::from_u32(3); +/// if let Some(cpu) = cpu3 { +///     mask.set(cpu); +///     assert!(mask.test(cpu)); +///     count += 1; +/// } +/// +/// assert_eq!(mask.weight(), count);  ///  /// let mask2 = CpumaskVar::try_clone(&mask).unwrap(); -/// assert!(mask2.test(2)); -/// assert!(mask2.test(3)); -/// assert_eq!(mask2.weight(), 2); +/// +/// if let Some(cpu) = cpu2 { +///     assert!(mask2.test(cpu)); +/// } +/// +/// if let Some(cpu) = cpu3 { +///     assert!(mask2.test(cpu)); +/// } +/// assert_eq!(mask2.weight(), count);  /// ```  pub struct CpumaskVar {      #[cfg(CONFIG_CPUMASK_OFFSTACK)] | 
