I'm running a program in C#, and I want to know the list of JobObjects that are assigned to the current process. Is there a way to do this?
To be more specific about my use-case, I'm trying to find the memory limit of the current process. The problem is that the function that returns the limits, returns the limits of the last one. So, if 1 JobObject is assigned to the current process, it is simple, but otherwise I don't understand how do it. It is demonstrated in the example below:
[DllImport("kernel32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity]
public static extern IntPtr CreateJobObjectW(IntPtr securityAttrs, [MarshalAs(UnmanagedType.LPWStr)] string name);
[DllImport("kernel32.dll", SetLastError = true), SuppressUnmanagedCodeSecurity]
public static extern bool AssignProcessToJobObject(IntPtr job, IntPtr process);
[DllImport("kernel32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool QueryInformationJobObject(IntPtr hJob, JobObjectInfoType infoClass, IntPtr info, UInt32 infoLength, IntPtr returnLength);
public static IntPtr CreateAndAssignJobObject(string name)
{
var jobObjectHandle = CreateJobObjectW(securityAttrs: IntPtr.Zero, name);
var processHandle = Process.GetCurrentProcess().Handle;
AssignProcessToJobObject(jobObjectHandle, processHandle);
return jobObjectHandle;
}
public static void LimitJobObjectMemory(IntPtr jobObjectHandle, ulong memoryLimit)
{
// Set the memory limit of the JobObject to 'memoryLimit'
}
/// <summary>
/// Gets a struct containing the extended limit information for the job object.
/// </summary>
private static JOBOBJECT_EXTENDED_LIMIT_INFORMATION GetExtendedLimitInformation()
{
var extendedInfo = new JOBOBJECT_EXTENDED_LIMIT_INFORMATION();
int infoSize = Marshal.SizeOf(typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
IntPtr extendedInfoPtr = Marshal.AllocHGlobal(infoSize);
try
{
Marshal.StructureToPtr(extendedInfo, extendedInfoPtr, false);
if (!QueryInformationJobObject(
IntPtr.Zero,
JobObjectInfoType.ExtendedLimitInformation,
extendedInfoPtr,
(UInt32)infoSize,
IntPtr.Zero))
{
throw new UtilsException($"QueryInformationJobObject failed; err={Marshal.GetLastWin32Error()}");
}
extendedInfo = (JOBOBJECT_EXTENDED_LIMIT_INFORMATION)Marshal.PtrToStructure(extendedInfoPtr, typeof(JOBOBJECT_EXTENDED_LIMIT_INFORMATION));
}
finally
{
Marshal.FreeHGlobal(extendedInfoPtr);
}
return extendedInfo;
}
public static void Main()
{
var job1Handle = CreateAndAssignJobObject("job1");
LimitJobObjectMemory(job1Handle, 4_000_000_000);
var job2Handle = CreateAndAssignJobObject("job2");
}
I'll explain what happens in the code: I create the first JobObject (job1Handle), limit its memory, and then create the second JobObject. Now, when I request the limits of the current process, I get the limits defined in the last JobObject. How can I get an aggregation (minimum, for instance) of the memory limit in all JobObjects of the process? Or more generally, how to enumerate the JobObjects assigned to the process?