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);
                }
            }
        }