void AssignProcessToJobObject() { var securityAttributes = new WinInterop.SecurityAttributes(); securityAttributes.nLength = Marshal.SizeOf(securityAttributes); hJob = CheckResult(WinJobs.NativeMethods.CreateJobObject(securityAttributes, "procgov-" + Guid.NewGuid())); // create completion port hIOCP = CheckResult(WinJobs.NativeMethods.CreateIoCompletionPort(WinHandles.NativeMethods.INVALID_HANDLE_VALUE, IntPtr.Zero, IntPtr.Zero, 1)); var assocInfo = new WinJobs.JOBOBJECT_ASSOCIATE_COMPLETION_PORT { CompletionKey = IntPtr.Zero, CompletionPort = hIOCP }; uint size = (uint)Marshal.SizeOf(assocInfo); CheckResult(WinJobs.NativeMethods.SetInformationJobObject(hJob, WinJobs.JOBOBJECTINFOCLASS.AssociateCompletionPortInformation, ref assocInfo, size)); WinJobs.JobInformationLimitFlags flags = 0; if (!propagateOnChildProcesses) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; } if (maxProcessMemory > 0) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_PROCESS_MEMORY; } if (cpuAffinityMask != 0) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_AFFINITY; } if (processUserTimeLimitInMilliseconds > 0) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_PROCESS_TIME; } if (jobUserTimeLimitInMilliseconds > 0) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_JOB_TIME; } long systemAffinity, processAffinity; CheckResult(WinProcesses.NativeMethods.GetProcessAffinityMask(hProcess, out processAffinity, out systemAffinity)); // configure constraints var limitInfo = new WinJobs.JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new WinJobs.JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = flags, Affinity = systemAffinity & cpuAffinityMask, PerProcessUserTimeLimit = 10_000 * processUserTimeLimitInMilliseconds, // in 100ns PerJobUserTimeLimit = 10_000 * jobUserTimeLimitInMilliseconds // in 100ns },
void AssignProcessToJobObject() { var securityAttributes = new WinInterop.SecurityAttributes(); securityAttributes.nLength = Marshal.SizeOf(securityAttributes); hJob = CheckResult(WinJobs.NativeMethods.CreateJobObject(securityAttributes, "procgov-" + Guid.NewGuid())); // create completion port hIOCP = CheckResult( WinJobs.NativeMethods.CreateIoCompletionPort(WinHandles.NativeMethods.INVALID_HANDLE_VALUE, IntPtr.Zero, IntPtr.Zero, 1)); var assocInfo = new WinJobs.JOBOBJECT_ASSOCIATE_COMPLETION_PORT { CompletionKey = IntPtr.Zero, CompletionPort = hIOCP }; uint size = (uint)Marshal.SizeOf(assocInfo); CheckResult(WinJobs.NativeMethods.SetInformationJobObject(hJob, WinJobs.JOBOBJECTINFOCLASS.JobObjectAssociateCompletionPortInformation, ref assocInfo, size)); WinJobs.JobInformationLimitFlags flags = 0; if (!PropagateOnChildProcesses) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK; } if (MaxProcessMemory > 0) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_PROCESS_MEMORY; } if (MaxWorkingSetSize > 0) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_WORKINGSET; } if (ProcessUserTimeLimitInMilliseconds > 0) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_PROCESS_TIME; } if (JobUserTimeLimitInMilliseconds > 0) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_JOB_TIME; } // only if NUMA node is not provided we will set the CPU affinity, // otherwise we will set the affinity on a selected NUMA node if (CpuAffinityMask != 0 && numaNode == 0xffff) { flags |= WinJobs.JobInformationLimitFlags.JOB_OBJECT_LIMIT_AFFINITY; } CheckResult(WinProcesses.NativeMethods.GetProcessAffinityMask(hProcess, out _, out var systemAffinityMask)); if (flags != 0) { // configure basic constraints var limitInfo = new WinJobs.JOBOBJECT_EXTENDED_LIMIT_INFORMATION { BasicLimitInformation = new WinJobs.JOBOBJECT_BASIC_LIMIT_INFORMATION { LimitFlags = flags, Affinity = systemAffinityMask & CpuAffinityMask, PerProcessUserTimeLimit = 10_000 * ProcessUserTimeLimitInMilliseconds, // in 100ns PerJobUserTimeLimit = 10_000 * JobUserTimeLimitInMilliseconds, // in 100ns MaximumWorkingSetSize = (UIntPtr)MaxWorkingSetSize, },