This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using Microsoft.Win32.SafeHandles; | |
using System; | |
using System.Collections.Generic; | |
using System.Diagnostics; | |
using System.Runtime.InteropServices; | |
namespace CpuSet | |
{ | |
internal class Program | |
{ | |
const int bufferSize = 1024; | |
const int TRUE = 1; | |
const int ERROR_INSUFFICIENT_BUFFER = 122; | |
static unsafe void Main(string[] args) | |
{ | |
using Process current = Process.GetCurrentProcess(); | |
PrintCpuSets(current.SafeHandle); // Print current | |
uint[] cputSetIds = GetCpuSetIds(current.SafeHandle); // Get CPU set IDs (they are not indexed from 0 or 1) | |
fixed(uint* pinnedIds = cputSetIds) | |
{ | |
if (HasFailed(SetProcessDefaultCpuSets(current.SafeHandle, pinnedIds, (uint)cputSetIds.Length), nameof(SetProcessDefaultCpuSets))) | |
{ | |
return; | |
} | |
} | |
PrintCpuSets(current.SafeHandle); | |
if (HasFailed(SetProcessDefaultCpuSets(current.SafeHandle, (uint*)IntPtr.Zero, 0), nameof(SetProcessDefaultCpuSets))) // clear out any assignment | |
{ | |
return; | |
} | |
PrintCpuSets(current.SafeHandle); | |
} | |
static unsafe uint[] GetCpuSetIds(SafeProcessHandle processHandle) | |
{ | |
if (HasFailed(GetSystemCpuSetInformation(IntPtr.Zero.ToPointer(), 0L, out ulong ReturnedLength, processHandle, 0L), nameof(GetSystemCpuSetInformation), | |
ERROR_INSUFFICIENT_BUFFER)) // "If the Information buffer was NULL or not large enough, the error code ERROR_INSUFFICIENT_BUFFER is returned" | |
{ | |
Environment.Exit(0); | |
} | |
void* bufferPtr = stackalloc byte[(int)ReturnedLength]; | |
if (HasFailed(GetSystemCpuSetInformation(bufferPtr, ReturnedLength, out ulong _, processHandle, 0L), nameof(GetSystemCpuSetInformation))) | |
{ | |
Environment.Exit(0); | |
} | |
List<uint> ids = new (); | |
ReadOnlySpan<byte> buffer = new ReadOnlySpan<byte>(bufferPtr, (int)ReturnedLength); | |
do | |
{ | |
SYSTEM_CPU_SET_INFORMATION info = MemoryMarshal.Read<SYSTEM_CPU_SET_INFORMATION>(buffer); | |
ids.Add(info.Id); | |
buffer = buffer.Slice((int)info.Size); | |
} while (!buffer.IsEmpty); | |
return ids.ToArray(); | |
} | |
static unsafe void PrintCpuSets(SafeProcessHandle processHandle) | |
{ | |
uint* buffer = stackalloc uint[bufferSize]; | |
if (HasFailed(GetProcessDefaultCpuSets(processHandle, buffer, bufferSize, out uint RequiredIdCount), nameof(GetProcessDefaultCpuSets))) | |
{ | |
return; | |
} | |
if (RequiredIdCount == 0) | |
{ | |
Console.WriteLine("If no default CPU Sets are set for a given process, then the RequiredIdCount is set to 0 and the function succeeds."); | |
return; | |
} | |
Console.WriteLine($"The ids: {string.Join(", ", new Span<uint>(buffer, (int)RequiredIdCount).ToArray())}"); | |
} | |
static bool HasFailed(int returnedValue, string syscallName, int expectedErrorCode = -1) | |
{ | |
if (returnedValue != TRUE) | |
{ | |
int errorCode = Marshal.GetLastWin32Error(); | |
if (errorCode != expectedErrorCode) | |
{ | |
Console.WriteLine($"{syscallName} failed with {errorCode/*:X*/}"); | |
return true; | |
} | |
} | |
return false; | |
} | |
[DllImport("kernel32.dll", SetLastError = true)] | |
internal static extern unsafe int GetSystemCpuSetInformation(void* Information, ulong BufferLength, out ulong ReturnedLength, SafeProcessHandle Process, ulong Flags); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
internal static extern unsafe int GetProcessDefaultCpuSets(SafeProcessHandle Process, uint* CpuSetIds, uint CpuSetIdCount, out uint RequiredIdCount); | |
[DllImport("kernel32.dll", SetLastError = true)] | |
internal static extern unsafe int SetProcessDefaultCpuSets(SafeProcessHandle Process, uint* CpuSetIds, uint CpuSetIdCount); | |
#pragma warning disable CS0649 // unused fields | |
internal struct SYSTEM_CPU_SET_INFORMATION | |
{ | |
internal uint Size; | |
internal uint Type; | |
internal uint Id; | |
// the structure defines more fields, but they were not needed | |
} | |
#pragma warning restore CS0649 | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment