static JobObjectInfo() { // create a JobObject and determine what options are supported on this OS.. SafeJobObjectHandle jobHandle = null; try { jobHandle = Interop.Kernel32.CreateJobObject(IntPtr.Zero, null); if (jobHandle.IsInvalid) { return; } _jobsSupported = true; // notification limit // notification limit 2 // net rate control // violation limit // violation limit 2 // job object group info // cpu rate control // group information ex IntPtr memoryPtr = IntPtr.Zero; try { int memorySize = 1024; memoryPtr = Marshal.AllocHGlobal(memorySize); // ask for specific structures to determine the level of support.. _jobsGroupSupported = IsSupported(jobHandle, Interop.Kernel32.JobObjectInformationClass.GroupInformation, memoryPtr, memorySize); _jobsGroupExSupported = IsSupported(jobHandle, Interop.Kernel32.JobObjectInformationClass.GroupInformationEx, memoryPtr, memorySize); _jobsLimitViolationSupported = IsSupported(jobHandle, Interop.Kernel32.JobObjectInformationClass.LimitViolationInformation, memoryPtr, memorySize); _jobsLimitViolation2Supported = IsSupported(jobHandle, Interop.Kernel32.JobObjectInformationClass.LimitViolationInformation2, memoryPtr, memorySize); } finally { if (memoryPtr != IntPtr.Zero) { Marshal.FreeHGlobal(memoryPtr); } } } finally { jobHandle?.Dispose(); } }
private void Dispose(bool disposing) { // remove completion handler before disposing handle, this should prevent a possible race with // another job object recyclying the handle value.. if ((_handle != null) && (!_handle.IsClosed) && (!_handle.IsInvalid) && (_completionPort != null)) { _completionPort.SetCompletionAction(_handle.DangerousGetHandle(), null); } // hold the _idleTaskLock while cancelling the idle task AND disposing the JobObject handle, we need // to ensure that if another thread is calling into GetIdleTask that it sees this instance has having // been disposed.. lock (_idleTaskLock) { _handle?.Dispose(); CompleteIdleTask(true); } _completionPort?.Dispose(); }
public unsafe IChildProcessStateHolder SpawnProcess( ref ChildProcessStartInfoInternal startInfo, string resolvedPath, SafeHandle stdIn, SafeHandle stdOut, SafeHandle stdErr) { var arguments = startInfo.Arguments; var environmentVariables = startInfo.EnvironmentVariables; var workingDirectory = startInfo.WorkingDirectory; var flags = startInfo.Flags; Debug.Assert(startInfo.CreateNewConsole || ConsolePal.HasConsoleWindow()); var commandLine = WindowsCommandLineUtil.MakeCommandLine(resolvedPath, arguments ?? Array.Empty <string>(), !flags.HasDisableArgumentQuoting()); var environmentBlock = startInfo.UseCustomEnvironmentVariables ? WindowsEnvironmentBlockUtil.MakeEnvironmentBlock(environmentVariables.Span) : null; // Objects that need cleanup InputWriterOnlyPseudoConsole?pseudoConsole = null; SafeJobObjectHandle? jobObjectHandle = null; SafeProcessHandle? processHandle = null; SafeThreadHandle? threadHandle = null; try { pseudoConsole = startInfo.CreateNewConsole ? InputWriterOnlyPseudoConsole.Create() : null; if (pseudoConsole is not null && flags.HasUseCustomCodePage()) { ChangeCodePage(pseudoConsole, startInfo.CodePage, workingDirectory); } bool killOnClose = startInfo.AllowSignal && WindowsVersion.NeedsWorkaroundForWindows1809; jobObjectHandle = CreateJobObject(killOnClose, startInfo.DisableWindowsErrorReportingDialog); using var inheritableHandleStore = new InheritableHandleStore(3); var childStdIn = stdIn != null?inheritableHandleStore.Add(stdIn) : null; var childStdOut = stdOut != null?inheritableHandleStore.Add(stdOut) : null; var childStdErr = stdErr != null?inheritableHandleStore.Add(stdErr) : null; IntPtr jobObjectHandles = jobObjectHandle.DangerousGetHandle(); Span <IntPtr> inheritableHandles = stackalloc IntPtr[inheritableHandleStore.Count]; inheritableHandleStore.DangerousGetHandles(inheritableHandles); fixed(IntPtr *pInheritableHandles = inheritableHandles) { using var attr = new ProcThreadAttributeList(3); if (pseudoConsole is not null) { attr.UpdatePseudoConsole(pseudoConsole.Handle.DangerousGetHandle()); } attr.UpdateHandleList(pInheritableHandles, inheritableHandles.Length); attr.UpdateJobList(&jobObjectHandles, 1); const int CreationFlags = Kernel32.CREATE_UNICODE_ENVIRONMENT | Kernel32.EXTENDED_STARTUPINFO_PRESENT; int processId; (processId, processHandle, threadHandle) = InvokeCreateProcess( commandLine, CreationFlags, environmentBlock, workingDirectory, childStdIn, childStdOut, childStdErr, attr); return(new WindowsChildProcessState(processId, processHandle, jobObjectHandle, pseudoConsole, startInfo.AllowSignal)); } } catch { if (processHandle is not null) { Kernel32.TerminateProcess(processHandle, -1); processHandle.Dispose(); } pseudoConsole?.Dispose(); jobObjectHandle?.Dispose(); throw; } finally { threadHandle?.Dispose(); } }