Beispiel #1
0
        /// <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 !;
     }
 }
Beispiel #3
0
        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);
            }
        }
Beispiel #6
0
 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);
     }
 }
Beispiel #8
0
        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);
 }
Beispiel #11
0
 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;
     }
 }