/// <summary> /// Ensures that the mapping table contains an entry for the process ID, /// increments its ref count, and returns it. /// </summary> /// <param name="processId">The process ID for which we need wait state.</param> /// <returns>The wait state object.</returns> internal static ProcessWaitState AddRef(int processId, bool isNewChild) { lock (s_childProcessWaitStates) { ProcessWaitState pws; if (isNewChild) { // When the PID is recycled for a new child, we remove the old child. s_childProcessWaitStates.Remove(processId); pws = new ProcessWaitState(processId, isChild: true); s_childProcessWaitStates.Add(processId, pws); pws._outstandingRefCount++; // For Holder pws._outstandingRefCount++; // Decremented in CheckChildren } else { lock (s_processWaitStates) { // We are referencing an existing process. // This may be a child process, so we check s_childProcessWaitStates too. if (!s_childProcessWaitStates.TryGetValue(processId, out pws) && !s_processWaitStates.TryGetValue(processId, out pws)) { pws = new ProcessWaitState(processId, isChild: false); s_processWaitStates.Add(processId, pws); } pws._outstandingRefCount++; } } return(pws); } }
public void Dispose() { if (_state != null) { GC.SuppressFinalize(this); _state.ReleaseRef(); _state = null !; } }
internal ProcessWaitHandle(ProcessWaitState processWaitState) { // Get the wait state's event, and use that event's safe wait handle // in place of ours. This will let code register for completion notifications // on this ProcessWaitHandle and be notified when the wait state's handle completes. ManualResetEvent mre = processWaitState.EnsureExitedEvent(); this.SetSafeWaitHandle(mre.GetSafeWaitHandle()); }
public void Dispose() { if (_state != null) { _state.ReleaseRef(); _state = null; GC.SuppressFinalize(this); } }
/// <summary> /// Ensures that the mapping table contains an entry for the process ID, /// increments its ref count, and returns it. /// </summary> /// <param name="processId">The process ID for which we need wait state.</param> /// <param name="isNewChild">Whether the wait state will represent a newly created child process.</param> /// <param name="usesTerminal">Whether the wait state will represent a process that is expected to use the terminal.</param> /// <returns>The wait state object.</returns> internal static ProcessWaitState AddRef(int processId, bool isNewChild, bool usesTerminal) { lock (s_childProcessWaitStates) { ProcessWaitState?pws; if (isNewChild) { // When the PID is recycled for a new child, we remove the old child. s_childProcessWaitStates.Remove(processId); pws = new ProcessWaitState(processId, isChild: true, usesTerminal); s_childProcessWaitStates.Add(processId, pws); pws._outstandingRefCount++; // For Holder pws._outstandingRefCount++; // Decremented in CheckChildren } else { lock (s_processWaitStates) { DateTime exitTime = default; // We are referencing an existing process. // This may be a child process, so we check s_childProcessWaitStates too. if (s_childProcessWaitStates.TryGetValue(processId, out pws)) { // child process } else if (s_processWaitStates.TryGetValue(processId, out pws)) { // This is best effort for dealing with recycled pids for non-child processes. // As long as we haven't observed process exit, it's safe to share the ProcessWaitState. // Once we've observed the exit, we'll create a new ProcessWaitState just in case // this may be a recycled pid. // If it wasn't, that ProcessWaitState will observe too that the process has exited. // We pass the ExitTime so it can be the same, but we'll clear it when we see there // is a live process with that pid. if (pws.GetExited(out _, refresh: false)) { s_processWaitStates.Remove(processId); exitTime = pws.ExitTime; pws = null; } } if (pws == null) { pws = new ProcessWaitState(processId, isChild: false, usesTerminal: false, exitTime); s_processWaitStates.Add(processId, pws); } pws._outstandingRefCount++; } } return(pws); } }
private static void OnSigChild(int reapAll) { // Lock to avoid races with Process.Start s_processStartLock.EnterWriteLock(); try { ProcessWaitState.CheckChildren(reapAll != 0); } finally { s_processStartLock.ExitWriteLock(); } }
/// <summary> /// Ensures that the mapping table contains an entry for the process ID, /// increments its ref count, and returns it. /// </summary> /// <param name="processId">The process ID for which we need wait state.</param> /// <returns>The wait state object.</returns> internal static ProcessWaitState AddRef(int processId) { lock (s_processWaitStates) { ProcessWaitState pws; if (!s_processWaitStates.TryGetValue(processId, out pws)) { pws = new ProcessWaitState(processId); s_processWaitStates.Add(processId, pws); } pws._outstandingRefCount++; return(pws); } }
private static int OnSigChild(int reapAll, int configureConsole) { // configureConsole is non zero when there are PosixSignalRegistrations that // may Cancel the terminal configuration that happens when there are no more // children using the terminal. // When the registrations don't cancel the terminal configuration, // DelayedSigChildConsoleConfiguration will be called. // Lock to avoid races with Process.Start s_processStartLock.EnterWriteLock(); try { bool childrenUsingTerminalPre = AreChildrenUsingTerminal; ProcessWaitState.CheckChildren(reapAll != 0, configureConsole != 0); bool childrenUsingTerminalPost = AreChildrenUsingTerminal; // return whether console configuration was skipped. return(childrenUsingTerminalPre && !childrenUsingTerminalPost && configureConsole == 0 ? 1 : 0); } finally { s_processStartLock.ExitWriteLock(); } }
internal static void CheckChildren(bool reapAll) { // This is called on SIGCHLD from a native thread. // A lock in Process ensures no new processes are spawned while we are checking. lock (s_childProcessWaitStates) { bool checkAll = false; // Check terminated processes. int pid; do { // Find a process that terminated without reaping it yet. pid = Interop.Sys.WaitIdAnyExitedNoHangNoWait(); if (pid > 0) { if (s_childProcessWaitStates.TryGetValue(pid, out ProcessWaitState? pws)) { // Known Process. if (pws.TryReapChild()) { pws.ReleaseRef(); } } else { // unlikely: This is not a managed Process, so we are not responsible for reaping. // Fall back to checking all Processes. checkAll = true; break; } } else if (pid == 0) { // No more terminated children. } else { // Unexpected. int errorCode = Marshal.GetLastWin32Error(); Environment.FailFast("Error while checking for terminated children. errno = " + errorCode); } } while (pid > 0); if (checkAll) { // We track things to unref so we don't invalidate our iterator by changing s_childProcessWaitStates. ProcessWaitState? firstToRemove = null; List <ProcessWaitState>?additionalToRemove = null; foreach (KeyValuePair <int, ProcessWaitState> kv in s_childProcessWaitStates) { ProcessWaitState pws = kv.Value; if (pws.TryReapChild()) { if (firstToRemove == null) { firstToRemove = pws; } else { if (additionalToRemove == null) { additionalToRemove = new List <ProcessWaitState>(); } additionalToRemove.Add(pws); } } } if (firstToRemove != null) { firstToRemove.ReleaseRef(); if (additionalToRemove != null) { foreach (ProcessWaitState pws in additionalToRemove) { pws.ReleaseRef(); } } } } if (reapAll) { do { int exitCode; pid = Interop.Sys.WaitPidExitedNoHang(-1, out exitCode); } while (pid > 0); } } }
internal Holder(int processId, bool isNewChild = false, bool usesTerminal = false) { _state = ProcessWaitState.AddRef(processId, isNewChild, usesTerminal); }
internal Holder(int processId, bool isNewChild = false) { _state = ProcessWaitState.AddRef(processId, isNewChild); }
internal Holder(int processId) { _state = ProcessWaitState.AddRef(processId); }
internal Holder(int processId) { _state = ProcessWaitState.AddRef(processId); }
/// <summary> /// Ensures that the mapping table contains an entry for the process ID, /// increments its ref count, and returns it. /// </summary> /// <param name="processId">The process ID for which we need wait state.</param> /// <returns>The wait state object.</returns> internal static ProcessWaitState AddRef(int processId) { lock (s_processWaitStates) { ProcessWaitState pws; if (!s_processWaitStates.TryGetValue(processId, out pws)) { pws = new ProcessWaitState(processId); s_processWaitStates.Add(processId, pws); } pws._outstandingRefCount++; return pws; } }