mirror of
https://github.com/openhardwaremonitor/openhardwaremonitor
synced 2025-08-22 09:57:20 +00:00
152 lines
4.6 KiB
C#
Executable File
152 lines
4.6 KiB
C#
Executable File
/*
|
|
|
|
This Source Code Form is subject to the terms of the Mozilla Public
|
|
License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
|
|
Copyright (C) 2010-2020 Michael Möller <mmoeller@openhardwaremonitor.org>
|
|
|
|
*/
|
|
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
namespace OpenHardwareMonitor.Hardware {
|
|
|
|
internal static class ThreadAffinity {
|
|
|
|
static ThreadAffinity() {
|
|
ProcessorGroupCount = GetProcessorGroupCount();
|
|
}
|
|
|
|
private static int GetProcessorGroupCount() {
|
|
if (OperatingSystem.IsUnix)
|
|
return 1;
|
|
|
|
try {
|
|
return NativeMethods.GetActiveProcessorGroupCount();
|
|
} catch {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
public static int ProcessorGroupCount { get; }
|
|
|
|
public static bool IsValid(GroupAffinity affinity) {
|
|
if (OperatingSystem.IsUnix) {
|
|
if (affinity.Group > 0)
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
var previous = Set(affinity);
|
|
if (previous == GroupAffinity.Undefined)
|
|
return false;
|
|
Set(previous);
|
|
return true;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Sets the processor group affinity for the current thread.
|
|
/// </summary>
|
|
/// <param name="affinity">The processor group affinity.</param>
|
|
/// <returns>The previous processor group affinity.</returns>
|
|
public static GroupAffinity Set(GroupAffinity affinity) {
|
|
if (affinity == GroupAffinity.Undefined)
|
|
return GroupAffinity.Undefined;
|
|
|
|
if (OperatingSystem.IsUnix) {
|
|
if (affinity.Group > 0)
|
|
throw new ArgumentOutOfRangeException("affinity.Group");
|
|
|
|
ulong result = 0;
|
|
if (NativeMethods.sched_getaffinity(0, (IntPtr)8, ref result) != 0)
|
|
return GroupAffinity.Undefined;
|
|
|
|
ulong mask = affinity.Mask;
|
|
if (NativeMethods.sched_setaffinity(0, (IntPtr)8, ref mask) != 0)
|
|
return GroupAffinity.Undefined;
|
|
|
|
return new GroupAffinity(0, result);
|
|
} else {
|
|
UIntPtr uIntPtrMask;
|
|
try {
|
|
uIntPtrMask = (UIntPtr)affinity.Mask;
|
|
} catch (OverflowException) {
|
|
throw new ArgumentOutOfRangeException("affinity.Mask");
|
|
}
|
|
|
|
var groupAffinity = new NativeMethods.GROUP_AFFINITY {
|
|
Group = affinity.Group,
|
|
Mask = uIntPtrMask
|
|
};
|
|
|
|
var currentThread = NativeMethods.GetCurrentThread();
|
|
|
|
try {
|
|
if (NativeMethods.SetThreadGroupAffinity(currentThread,
|
|
ref groupAffinity, out var previousGroupAffinity))
|
|
{
|
|
return new GroupAffinity(previousGroupAffinity.Group,
|
|
(ulong)previousGroupAffinity.Mask);
|
|
} else {
|
|
return GroupAffinity.Undefined;
|
|
}
|
|
} catch (EntryPointNotFoundException) {
|
|
if (affinity.Group > 0)
|
|
throw new ArgumentOutOfRangeException("affinity.Group");
|
|
|
|
var previous = (ulong)NativeMethods.SetThreadAffinityMask(
|
|
currentThread, uIntPtrMask);
|
|
|
|
return new GroupAffinity(0, previous);
|
|
}
|
|
}
|
|
}
|
|
|
|
private static class NativeMethods {
|
|
private const string KERNEL = "kernel32.dll";
|
|
|
|
[DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
|
|
public static extern UIntPtr
|
|
SetThreadAffinityMask(IntPtr handle, UIntPtr mask);
|
|
|
|
[DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
|
|
public static extern IntPtr GetCurrentThread();
|
|
|
|
[DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
|
|
public static extern ushort GetActiveProcessorGroupCount();
|
|
|
|
[StructLayout(LayoutKind.Sequential, Pack = 4)]
|
|
public struct GROUP_AFFINITY {
|
|
public UIntPtr Mask;
|
|
[MarshalAs(UnmanagedType.U2)]
|
|
public ushort Group;
|
|
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 3,
|
|
ArraySubType = UnmanagedType.U2)]
|
|
public ushort[] Reserved;
|
|
}
|
|
|
|
[DllImport(KERNEL, CallingConvention = CallingConvention.Winapi)]
|
|
public static extern bool SetThreadGroupAffinity(
|
|
IntPtr thread,
|
|
ref GROUP_AFFINITY groupAffinity,
|
|
out GROUP_AFFINITY previousGroupAffinity);
|
|
|
|
private const string LIBC = "libc";
|
|
|
|
[DllImport(LIBC)]
|
|
public static extern int sched_getaffinity(int pid, IntPtr maskSize,
|
|
ref ulong mask);
|
|
|
|
[DllImport(LIBC)]
|
|
public static extern int sched_setaffinity(int pid, IntPtr maskSize,
|
|
ref ulong mask);
|
|
}
|
|
}
|
|
}
|
|
|