Add support for multiple processor groups.

Merge from upstream.
This commit is contained in:
Phyxion
2020-05-11 13:29:52 +02:00
parent a18136b55e
commit 3cc3d9139c
22 changed files with 390 additions and 135 deletions
@@ -5,38 +5,122 @@
// All Rights Reserved.
using System;
using System.Runtime.InteropServices;
using LibreHardwareMonitor.Interop;
namespace LibreHardwareMonitor.Hardware
{
internal static class ThreadAffinity
{
public static ulong Set(ulong mask)
/// <summary>
/// Initializes static members of the <see cref="ThreadAffinity" /> class.
/// </summary>
static ThreadAffinity()
{
if (mask == 0)
return 0;
ProcessorGroupCount = Software.OperatingSystem.IsUnix ? 1 : Kernel32.GetActiveProcessorGroupCount();
if (ProcessorGroupCount < 1)
ProcessorGroupCount = 1;
}
if (Software.OperatingSystem.IsLinux)
/// <summary>
/// Gets the processor group count.
/// </summary>
public static int ProcessorGroupCount { get; }
/// <summary>
/// Returns true if the <paramref name="affinity"/> is valid.
/// </summary>
/// <param name="affinity">The affinity.</param>
/// <returns><c>true</c> if the specified affinity is valid; otherwise, <c>false</c>.</returns>
public static bool IsValid(GroupAffinity affinity)
{
if (Software.OperatingSystem.IsUnix)
{
ulong result = 0;
if (Interop.LibC.sched_getaffinity(0, (IntPtr)Marshal.SizeOf(result), ref result) != 0)
return 0;
if (affinity.Group > 0)
return false;
}
return Interop.LibC.sched_setaffinity(0, (IntPtr)Marshal.SizeOf(mask), ref mask) != 0 ? (ulong) 0 : result;
try
{
GroupAffinity previousAffinity = Set(affinity);
if (previousAffinity == GroupAffinity.Undefined)
return false;
Set(previousAffinity);
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 (Software.OperatingSystem.IsUnix)
{
if (affinity.Group > 0)
throw new ArgumentOutOfRangeException(nameof(affinity));
ulong result = 0;
if (LibC.sched_getaffinity(0, (IntPtr)8, ref result) != 0)
return GroupAffinity.Undefined;
ulong mask = affinity.Mask;
if (LibC.sched_setaffinity(0, (IntPtr)8, ref mask) != 0)
return GroupAffinity.Undefined;
return new GroupAffinity(0, result);
}
UIntPtr uIntPtrMask;
try
{
uIntPtrMask = (UIntPtr)mask;
uIntPtrMask = (UIntPtr)affinity.Mask;
}
catch (OverflowException)
{
throw new ArgumentOutOfRangeException(nameof(mask));
throw new ArgumentOutOfRangeException(nameof(affinity));
}
var groupAffinity = new Kernel32.GROUP_AFFINITY { Group = affinity.Group, Mask = uIntPtrMask };
IntPtr currentThread = Kernel32.GetCurrentThread();
try
{
if (Kernel32.SetThreadGroupAffinity(currentThread,
ref groupAffinity,
out Kernel32.GROUP_AFFINITY previousGroupAffinity))
{
return new GroupAffinity(previousGroupAffinity.Group, (ulong)previousGroupAffinity.Mask);
}
return GroupAffinity.Undefined;
}
catch (EntryPointNotFoundException)
{
if (affinity.Group > 0)
throw new ArgumentOutOfRangeException(nameof(affinity));
ulong previous = (ulong)Kernel32.SetThreadAffinityMask(currentThread, uIntPtrMask);
return new GroupAffinity(0, previous);
}
return (ulong)Interop.Kernel32.SetThreadAffinityMask(Interop.Kernel32.GetCurrentThread(), uIntPtrMask);
}
}
}