예제 #1
0
        /// <summary>
        /// Invoked asynchronously when the process has written a line to stdout or stderr.
        /// Implements a very rough progress estimation system based on the current number
        /// of output lines and a total estimate.
        /// </summary>
        protected override void OnLineWritten(System.Diagnostics.DataReceivedEventArgs e)
        {
            const double MIN_PERCENTAGE_DELTA = 0.1;

            base.OnLineWritten(e);

            if (_expectedNumOutputLines <= 0 || ProgressChanged == null)
            {
                return;
            }

            double expectedPercentage;

            lock (_syncObject)
            {
                int numLines = ++_currentNumOutputLines;
                expectedPercentage = (100.0 * numLines) / _expectedNumOutputLines;

                if (expectedPercentage - _lastReportedProgressPercentage < MIN_PERCENTAGE_DELTA ||
                    _lastReportedProgressPercentage >= 100)                        // no more progress reports if last percentage >= 100%
                {
                    return;
                }

                expectedPercentage = Math.Min(100, expectedPercentage);                 // max 100%
                _lastReportedProgressPercentage = expectedPercentage;
            }

            SmartEventInvoker.FireEvent(ProgressChanged, this, new ProgressEventArgs(expectedPercentage));
        }
예제 #2
0
        private void WaitForExit(bool kill = false)
        {
            // after _process.WaitForExit(), we cannot simply wait for _fullyExitedWaitHandle because
            // there may be an Exited event handler dispatched in this thread, resulting in a deadlock
            // (this thread would wait for _fullyExitedWaitHandle and hence never execute the dispatched
            // handler while all event handlers need to complete before _fullyExitedWaitHandle is signaled)

            // what we do is hijacking these event handlers from the Exited event and invoking them
            // here in this thread before waiting for _fullyExitedWaitHandle
            // for this to work, this call must be either before the process exits (OnExited()) or
            // after it has exited and all Exited event handlers have finished
            if (HasExited)
            {
                if (HasFullyExited)
                {
                    return;
                }

                throw new ProcessExitingException();
            }

            EventHandler compatibleHandlers;

            lock (_syncObject)
            {
                compatibleHandlers = SmartEventInvoker.HijackCompatibleHandlers(ref Exited);

                if (kill)
                {
                    KillInternal();
                }
            }

            _process.WaitForExit();

            int numHandlers = GetNumDelegates(compatibleHandlers);

            if (numHandlers > 0)
            {
                compatibleHandlers(this, EventArgs.Empty);
            }

            int numPending = OnExitedEventHandlersFinished(numHandlers);

            if (numPending > 0)
            {
                _fullyExitedWaitHandle.WaitOne();
            }
        }
예제 #3
0
        /// <summary>
        /// Invoked asynchronously when the process has exited.
        /// </summary>
        private void OnExited(EventArgs e)
        {
            // the Exited event is sometimes triggered a second time
            // I guess that has to do with disposing of the process in another thread
            // while the Exited event hasn't been handled completely yet
            if (Interlocked.Exchange(ref _onExitedInvoked, 1) == 1)
            {
                return;
            }

            // hijack all (remaining) event handlers from the Exited event
            EventHandler exitedEventHandlers;

            lock (_syncObject)
            {
                exitedEventHandlers = Exited;
                Exited = null;
            }

            // invoke/dispatch them
            var iasyncs = SmartEventInvoker.FireEvent(exitedEventHandlers, this, e);

            int numHandlers   = GetNumDelegates(exitedEventHandlers);           // incl. dispatched ones
            int numDispatched = (iasyncs == null ? 0 : iasyncs.Count);
            int numInvoked    = numHandlers - numDispatched;

            OnExitedEventHandlersFinished(numInvoked);

            if (numDispatched > 0)
            {
                // in a new thread:
                var thread = new Thread(() =>
                {
                    // wait for all dispatched handlers to complete
                    SmartEventInvoker.Wait(iasyncs);
                    OnExitedEventHandlersFinished(numDispatched);
                });
                thread.Start();
            }
        }
예제 #4
0
 private void OnError(string text)
 {
     SmartEventInvoker.FireEvent(Error, this, new TextEventArgs(text));
 }
예제 #5
0
 private void OnReady()
 {
     SmartEventInvoker.FireEvent(Ready, this, EventArgs.Empty);
 }
예제 #6
0
 /// <summary>
 /// Invoked asynchronously when the process has written a line to stdout or stderr.
 /// </summary>
 protected virtual void OnLineWritten(DataReceivedEventArgs e)
 {
     SmartEventInvoker.FireEvent(LineWritten, this, e);
 }