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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178
// This file is part of cpu-affinity. It is subject to the license terms in the COPYRIGHT file found in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/cpu-affinity/master/COPYRIGHT. No part of cpu-affinity, including this file, may be copied, modified, propagated, or distributed except according to the terms contained in the COPYRIGHT file.
// Copyright © 2018 The developers of cpu-affinity. See the COPYRIGHT file in the top-level directory of this distribution and at https://raw.githubusercontent.com/lemonrock/cpu-affinity/master/COPYRIGHT.
/// Logical cores to use for process and thread affinity, abstracting away platform, library and Operating System differences.
///
/// Provides the following definitions:-
///
/// * Constant `LogicalCores::IsSettingProcessAffinitySupported`: Boolean that is true if the current platform contains a way to attempt to set process affinity.
/// * Constant `LogicalCores::IsSettingThreadAffinitySupported`: Boolean that is true if the current platform contains a way to attempt to set thread affinity. Note that this is true for Fuschia and Empscripten, but that setting thread affinity always fails as unsupported as of 3rd December 2018.
///
/// * Method `set_current_process_affinity(&self) -> io::Result<()>`: Tries to set the current process' affinity; may fail (eg may not be supported in particular revisions of an OS, particularly so on Fuschia and Emscripten).
/// * Method `set_process_affinity(&self, process_identifier) -> io::Result<()>`: As above, but for a particular process. Usually fails with permission denied if not root.
/// * Method `set_current_thread_affinity(&self) -> io::Result<()>`: Tries to set the thread process' affinity; may fail (eg may not be supported in particular revisions of an OS, particularly so on Fuschia and Emscripten).
/// * Method `set_thread_affinity(&self, thread_identifier) -> io::Result<()>`: As above, but for a thread process. Usually fails with permission denied if not root.
///
/// If support for a platform has not been explicitly added to this library then it will not fail on that platform but it will not change any process or thread affinities, either.
///
/// At this time, there is no support for Solaris.
/// If you're interested in adding support, see <https://stackoverflow.com/questions/14085515/obtain-lwp-id-from-a-pthread-t-on-solaris-to-use-with-processor-bind>.
///
/// DragonFlyBSD and FreeBSD currently (as of 3rd December 2018) support 256 cores.
///
/// Windows is a bit squiffy with more than 64 cores.
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct LogicalCores(HashSet<usize>);
impl From<usize> for LogicalCores
{
#[inline(always)]
fn from(core_index: usize) -> Self
{
let mut logical_cores = HashSet::with_capacity(1);
logical_cores.insert(core_index);
LogicalCores(logical_cores)
}
}
impl From<HashSet<usize>> for LogicalCores
{
#[inline(always)]
fn from(logical_cores: HashSet<usize>) -> Self
{
debug_assert_ne!(logical_cores.len(), 0, "There must be at least one logical core specified");
LogicalCores(logical_cores)
}
}
impl Into<HashSet<usize>> for LogicalCores
{
#[inline(always)]
fn into(self) -> HashSet<usize>
{
self.0
}
}
impl LogicalCores
{
/// Is setting process affinity is supported?
///
/// Note that on emscripten and fuschia an error (`ENOSYS`) by the platform will always be returned as of the 3rd December 2018.
///
/// The following do not support setting process affinity:-
///
/// * iOS
/// * Mac OS
/// * OpenBSD
/// * BitRig
pub const IsSettingProcessAffinitySupported: bool = Self::_IsSettingProcessAffinitySupported;
/// Is setting thread affinity is supported?
///
/// Note that on emscripten and fuschia an error (`ENOSYS`) by the platform will always be returned as of the 3rd December 2018.
///
/// The following do not support setting thread affinity:-
///
/// * Android
/// * iOS
/// * Mac OS
/// * OpenBSD
/// * BitRig
pub const IsSettingThreadAffinitySupported: bool = Self::_IsSettingThreadAffinitySupported;
/// Sets the current process' logical core affinity.
///
/// This is not efficiently implemented (it uses a loop).
///
/// Failure occurs if a CPU in the set does not exist, is offline or in some other way is unavailable to the `process_identifier` (`EINVAL`).
#[inline(always)]
pub fn set_current_process_affinity(&self) -> io::Result<()>
{
self._set_process_affinity(Self::current_process_identifier())
}
/// Sets the process' logical core affinity.
///
/// This is not efficiently implemented (it uses a loop).
///
/// Failure occurs if:-
///
/// * Permission is denied to change the process affinity for `process_identifier` (`EPERM`) (for example, the process isn't a child of this process);
/// * A CPU in the set does not exist, is offline or in some other way is unavailable to the `process_identifier` (`EINVAL`);
/// * `process_identifier` does not exist (`ESRCH`)
/// * Operating system is not yet implemented (`ENOSYS`) - typical of Emscripten and Fuschia.
#[inline(always)]
pub fn set_process_affinity(&self, process_identifier: ProcessIdentifier) -> io::Result<()>
{
self._set_process_affinity(process_identifier)
}
/// Sets the thread's logical core affinity.
///
/// Threads are never resident on just on core, and hence a lot of thread local opimizations (eg with clever non-blocking alogorithms) are useless.
#[inline(always)]
pub fn set_current_thread_affinity(&self) -> io::Result<()>
{
self._set_thread_affinity(Self::current_thread_identifier())
}
/// Sets the thread's logical core affinity.
///
/// This is only used as a *hint* on iOS and MacOS; it is near useless.
///
/// Threads are never resident on just on core, and hence a lot of thread local opimizations (eg with clever non-blocking alogorithms) are useless.
///
/// * Permission is denied to change the process affinity for `process_identifier` (`EPERM`) (for example, the process isn't a child of this process);
/// * A CPU in the set does not exist, is offline or in some other way is unavailable to the `process_identifier` (`EINVAL`);
/// * `process_identifier` does not exist (`ESRCH`)
/// * Operating system is not yet implemented (`ENOSYS`) - typical of Emscripten and Fuschia.
/// * `ERANGE` - on FreeBSD, the cpu set was far too large.
/// * `EDEADLK` - on FreeBSD, the cpu set could not be honoured.
#[inline(always)]
pub fn set_thread_affinity(&self, thread_identifier: ThreadIdentifier) -> io::Result<()>
{
self._set_thread_affinity(thread_identifier)
}
#[cfg(unix)]
const fn current_process_identifier() -> ProcessIdentifier
{
0
}
#[cfg(windows)]
fn current_process_identifier() -> ProcessIdentifier
{
unsafe { ::kernel32::GetCurrentProcess() }
}
#[cfg(unix)]
fn current_thread_identifier() -> ThreadIdentifier
{
unsafe { pthread_self() }
}
#[cfg(windows)]
fn current_thread_identifier() -> ThreadIdentifier
{
unsafe { ::kernel32::GetCurrentThread() }
}
#[allow(dead_code)]
#[inline(always)]
fn last_os_error() -> io::Error
{
io::Error::last_os_error()
}
}
#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "fuschia", target_os = "linux", target_env = "uclibc"))] include!("LogicalCores.android-emscripten-fuschia-linux-uclibc.rs");
#[cfg(target_os = "dragonfly")] include!("LogicalCores.dragonfly.rs");
#[cfg(target_os = "freebsd")] include!("LogicalCores.freebsd.rs");
#[cfg(any(target_os = "ios", target_os = "macos"))] include!("LogicalCores.ios_macos.rs");
#[cfg(target_os = "netbsd")] include!("LogicalCores.netbsd.rs");
#[cfg(not(any(target_os = "android", target_os = "dragonfly", target_os = "emscripten", target_os = "freebsd", target_os = "fuschia", target_os = "ios", target_os = "linux", target_os = "macos", target_os = "netbsd", target_env = "uclibc", windows)))] include!("LogicalCores.others.rs");
#[cfg(windows)] include!("LogicalCores.windows.rs");