singrdk/base/Windows/WindowsInteropLib/Kernel32.cs

383 lines
12 KiB
C#

////////////////////////////////////////////////////////////////////////////////
//
// Microsoft Research Singularity
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// File: Windows.cs
//
// Note: P/Invoke definitions for manipulating threads, processes, and jobs.
//
using System;
using System.Diagnostics;
using System.ComponentModel;
using System.Runtime.InteropServices;
// This only works on kernels later than Vista, XP64, and W2003S.
// Notably, it does not work on XP 32-bit. So, we can't learn which
// processors are virtual processors (HyperThreading), so we can't
// make sure that we schedule jobs only on the main virtual processor
// of each physical core yet. The reason to do this is because
// HyperThreading really doesn't work for CPU-bound tasks; in nearly
// all tests, running CPU-bound tasks on both virtual processors of
// a single hyper-threaded core results in *worse* performance, largely
// due to the increased cache pressure.
//
// #define ENABLE_LOGICAL_PROCESSOR_INFORMATION
namespace Windows
{
public class Kernel32
{
const string DllName = "KERNEL32.DLL";
[DllImport(DllName, CharSet = CharSet.Unicode)]
static extern IntPtr CreateJobObject(
IntPtr SecurityAttributes,
string Name);
public static IntPtr CreateJobObject()
{
IntPtr handle = CreateJobObject(IntPtr.Zero, null);
if (handle == IntPtr.Zero || handle == ((IntPtr)~0)) {
int error = Marshal.GetLastWin32Error();
throw new Exception("The job object could not be created.",
new Win32Exception(error));
}
return handle;
}
[DllImport(DllName, SetLastError = true)]
public static extern bool CloseHandle(IntPtr ObjectHandle);
[DllImport(DllName, SetLastError = true)]
public static extern bool AssignProcessToJobObject(
IntPtr JobHandle,
IntPtr ProcessHandle);
[DllImport(DllName, SetLastError=true)]
static unsafe extern bool QueryInformationJobObject(
IntPtr JobHandle,
JobObjectInformationClass InformationClass,
void* Buffer,
int BufferLength,
out int ReturnLength);
public static JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
QueryJobObjectBasicAccountingInformation(IntPtr JobHandle)
{
unsafe
{
JOBOBJECT_BASIC_ACCOUNTING_INFORMATION buffer;
int length;
if (!QueryInformationJobObject(
JobHandle,
JobObjectInformationClass.Accounting,
&buffer,
sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION),
out length))
{
int error = Marshal.GetLastWin32Error();
throw new Exception("Failed to query information from job object.",
new Win32Exception(error));
}
return buffer;
}
}
public static bool IsCurrentProcessInJob()
{
unsafe
{
JOBOBJECT_BASIC_ACCOUNTING_INFORMATION information = new JOBOBJECT_BASIC_ACCOUNTING_INFORMATION();
int returnLength = 0;
if (QueryInformationJobObject(IntPtr.Zero, JobObjectInformationClass.Accounting,
&information, sizeof(JOBOBJECT_BASIC_ACCOUNTING_INFORMATION), out returnLength))
{
return true;
}
else {
return false;
}
}
}
[DllImport(DllName, SetLastError = true, CharSet=CharSet.Unicode)]
static unsafe extern int FormatMessage(
FormatMessageFlag flags,
void* Source,
int MessageId,
int LanguageId,
void* Buffer,
int BufferLength,
void* Arguments);
public static unsafe string FormatMessageFromSystem(int messageId, int languageId)
{
char* buffer = null;
int length = FormatMessage(
FormatMessageFlag.AllocateBuffer | FormatMessageFlag.FromSystem,
null,
messageId,
languageId,
(void*)&buffer,
0,
null);
if (length == 0)
return null;
string result = new String(buffer, 0, length);
Marshal.FreeHGlobal((IntPtr)(void*)buffer);
return result;
}
public unsafe static string FormatMessageFromSystem(int messageId)
{
return FormatMessageFromSystem(messageId, 0);
}
public static string GetErrorText(int error)
{
string text = FormatMessageFromSystem(error);
if (text == null) {
if (error < 0x10000 && error >= 0)
return String.Format("Unknown error: {0]", error);
else
return String.Format("Unknown error: 0x{0:x}", error);
}
else {
return text;
}
}
[DllImport(DllName, SetLastError = true)]
public static extern uint SetThreadIdealProcessor(
IntPtr ThreadHandle,
int IdealProcessor);
[DllImport(DllName, SetLastError = true)]
public static extern bool GetProcessAffinityMask(
IntPtr ProcessHandle,
out UIntPtr ProcessAffinityMask,
out UIntPtr SystemAffinityMask);
[DllImport(DllName)]
public static extern IntPtr GetCurrentThread();
[DllImport(DllName)]
public static extern IntPtr GetCurrentProcess();
[DllImport(DllName, SetLastError = true)]
public static extern bool GetThreadTimes(
IntPtr hThread,
out /* FILETIME */ long lpCreationTime,
out /* FILETIME */ long lpExitTime,
out /* FILETIME */ long lpKernelTime,
out /* FILETIME */ long lpUserTime
);
public void GetThreadTimes(
IntPtr ThreadHandle,
out DateTime creationTime,
out DateTime exitTime,
out TimeSpan kernelTime,
out TimeSpan userTime)
{
long ticks_creationTime;
long ticks_exitTime;
long ticks_kernelTime;
long ticks_userTime;
if (GetThreadTimes(ThreadHandle,
out ticks_creationTime,
out ticks_exitTime,
out ticks_kernelTime,
out ticks_userTime))
{
creationTime = new DateTime(ticks_creationTime);
exitTime = new DateTime(ticks_exitTime);
kernelTime = new TimeSpan(ticks_kernelTime);
userTime = new TimeSpan(ticks_userTime);
}
else {
throw new Exception("The thread times could not be retrieved.",
new Win32Exception(Marshal.GetLastWin32Error()));
}
}
public static int GetProcessorCount()
{
UIntPtr processAffinityMask;
UIntPtr systemAffinityMask;
if (!GetProcessAffinityMask(GetCurrentProcess(), out processAffinityMask, out systemAffinityMask)) {
Console.WriteLine("nib: Failed to get process affinity mask! Assuming 1 processor.");
return 1;
}
ulong mask = (ulong)processAffinityMask;
int count = 0;
while (mask != 0) {
if ((mask & 1) != 0)
count++;
mask >>= 1;
}
if (count == 0)
return 1;
Console.WriteLine("nib: Found {0} processors.", count);
return count;
}
public static string GetLastErrorText()
{
int error = Marshal.GetLastWin32Error();
return GetErrorText(error);
}
#if ENABLE_LOGICAL_PROCESSOR_INFORMATION
[DllImport(DllName, SetLastError=true)]
static unsafe extern bool GetLogicalProcessorInformation(
SYSTEM_LOGICAL_PROCESSOR_INFORMATION* buffer,
ref int length);
public static SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] GetLogicalProcessorInformation()
{
unsafe
{
int length = 0;
GetLogicalProcessorInformation(null, ref length);
if (length == 0)
return new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[0];
int count = length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] array = new SYSTEM_LOGICAL_PROCESSOR_INFORMATION[count];
bool result;
fixed (SYSTEM_LOGICAL_PROCESSOR_INFORMATION* array_pinned = &array[0])
{
int length2 = sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION) * count;
result = GetLogicalProcessorInformation(array_pinned, ref length2);
}
if (result)
return array;
else
throw new Exception("Failed to query logical processor information.",
new Win32Exception(Marshal.GetLastWin32Error()));
}
}
public static int[] GetPhysicalProcessorList()
{
SYSTEM_LOGICAL_PROCESSOR_INFORMATION[] logical_info = GetLogicalProcessorInformation();
for (int i = 0; i < logical_info.Length; i++) {
Debug.WriteLine(logical_info.ToString());
}
return null;
}
#endif
}
[Flags]
enum FormatMessageFlag
{
AllocateBuffer = 0x100,
FromSystem = 0x1000,
FromModule = 0x800,
}
public enum JobObjectInformationClass
{
Accounting = 1, // JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
}
[StructLayout(LayoutKind.Sequential)]
public struct JOBOBJECT_BASIC_ACCOUNTING_INFORMATION
{
public TimeSpan TotalUserTime;
public TimeSpan TotalKernelTime;
public TimeSpan ThisPeriodTotalUserTime;
public TimeSpan ThisPeriodTotalKernelTime;
public uint TotalPageFaultCount;
public uint TotalProcesses;
public uint ActiveProcesses;
public uint TotalTerminatedProcesses;
}
#if ENABLE_LOGICAL_PROCESSOR_INFORMATION
[StructLayout(LayoutKind.Sequential)]
struct SYSTEM_LOGICAL_PROCESSOR_INFORMATION
{
public UIntPtr ProcessorMask;
public LOGICAL_PROCESSOR_RELATIONSHIP Relationship;
//
//union {
// struct
// {
// BYTE Flags;
// } ProcessorCore;
// struct
// {
// DWORD NodeNumber;
// } NumaNode;
// CACHE_DESCRIPTOR Cache;
// ULONGLONG Reserved[2];
//}
//
public ProcessorRelationUnion RelationUnion;
}
[StructLayout(LayoutKind.Explicit)]
struct ProcessorRelationUnion
{
[FieldOffset(0)] public CACHE_DESCRIPTOR Cache;
[FieldOffset(0)] public uint NumaNodeNumber;
[FieldOffset(0)] public byte ProcessorCoreFlags;
}
[StructLayout(LayoutKind.Sequential)]
struct CACHE_DESCRIPTOR
{
public byte Level;
public byte Associativity;
public ushort LineSize;
public uint Size;
public PROCESSOR_CACHE_TYPE Type;
}
enum PROCESSOR_CACHE_TYPE
{
Unified = 0,
Instruction = 1,
Data = 2,
Trace = 3,
}
enum LOGICAL_PROCESSOR_RELATIONSHIP : uint
{
ProcessorCore = 0,
NumaNode = 1,
RelationCache = 2,
}
#endif
}