public void Dispose() { if (_state != null) { GC.SuppressFinalize(this); _state.ReleaseRef(); _state = null; } }
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); } } }