public Task <Stream> ProcessEvents(int processId, TimeSpan duration, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            lock (_lock)
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException(nameof(DiagnosticsMonitor));
                }

                if (_currentTask != null)
                {
                    throw new InvalidOperationException("Only one stream processing is allowed");
                }

                EventPipeSession session = null;
                var client = new DiagnosticsClient(processId);

                try
                {
                    session = client.StartEventPipeSession(_sourceConfig.GetProviders(), _sourceConfig.RequestRundown, _sourceConfig.BufferSizeInMB);
                }
                catch (EndOfStreamException e)
                {
                    throw new InvalidOperationException("End of stream", e);
                }
                catch (Exception ex) when(!(ex is OperationCanceledException))
                {
                    throw new InvalidOperationException("Failed to start the event pipe session", ex);
                }

                CancellationTokenSource linkedSource = CancellationTokenSource.CreateLinkedTokenSource(_stopProcessingSource.Token, cancellationToken);

                _currentTask = Task.Run(async() =>
                {
                    try
                    {
                        await Task.Delay(duration, linkedSource.Token);
                    }
                    finally
                    {
                        linkedSource.Dispose();
                        StopSession(session);
                    }
                });

                return(Task.FromResult(session.EventStream));
            }
        }
        public Task <Stream> ProcessEvents(DiagnosticsClient client, TimeSpan duration, CancellationToken cancellationToken)
        {
            cancellationToken.ThrowIfCancellationRequested();

            lock (_lock)
            {
                if (_disposed)
                {
                    throw new ObjectDisposedException(nameof(DiagnosticsMonitor));
                }

                if (_currentTask != null)
                {
                    throw new InvalidOperationException("Only one stream processing is allowed");
                }

                EventPipeSession session = null;
                try
                {
                    session = client.StartEventPipeSession(_sourceConfig.GetProviders(), _sourceConfig.RequestRundown, _sourceConfig.BufferSizeInMB);
                }
                catch (EndOfStreamException e)
                {
                    throw new InvalidOperationException("End of stream", e);
                }
                catch (Exception ex) when(!(ex is OperationCanceledException))
                {
                    throw new InvalidOperationException("Failed to start the event pipe session", ex);
                }

                _currentTask = Task.Run(async() =>
                {
                    using var linkedSource = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
                    linkedSource.CancelAfter(duration);
                    using var _ = linkedSource.Token.Register(() => _stopProcessingSource.TrySetResult(null));

                    // Use TaskCompletionSource instead of Task.Delay with cancellation to avoid
                    // using exceptions for normal termination of event stream.
                    await _stopProcessingSource.Task.ConfigureAwait(false);

                    StopSession(session);
                });

                return(Task.FromResult(session.EventStream));
            }
        }