Esempio n. 1
0
        internal async Task SetBreakpointAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            await Session.InvokeDebugHelperAsync(GetAddBreakpointExpression(true), cancellationToken);

            ++UseCount;
        }
Esempio n. 2
0
        public Task <IAsyncReaderWriterLockToken> WriterLockAsync(CancellationToken cancellationToken = default(CancellationToken), ReentrancyToken reentrancyToken = default(ReentrancyToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            var task = ReentrantOrCanceled(true, cancellationToken, reentrancyToken);

            if (task != null)
            {
                return(task);
            }

            var  source = new LockSource(this, true);
            bool isFirstWriter;

            _queue.AddWriter(source, out isFirstWriter);
            if (isFirstWriter)
            {
                source.Release();
            }
            else
            {
                source.RegisterCancellation(cancellationToken);
            }

            return(source.Task);
        }
Esempio n. 3
0
        internal async Task SetBreakpointAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            await Tracer.Session.ExecuteAsync(GetAddBreakpointExpression(true), cancellationToken);

            ++UseCount;
        }
Esempio n. 4
0
        public async Task Run(IMessageTransport transport, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            if (_runTask != null)
            {
                throw new InvalidOperationException("This host is already running.");
            }

            if (transport != null)
            {
                lock (_transportLock) {
                    _transport = transport;
                }
            }
            else if (_transport == null)
            {
                throw new ArgumentNullException(nameof(transport));
            }

            try {
                await(_runTask = RunWorker(ct));
            } catch (OperationCanceledException) when(ct.IsCancellationRequested)
            {
                // Expected cancellation, do not propagate, just exit process
            } catch (MessageTransportException ex) when(ct.IsCancellationRequested)
            {
                // Network errors during cancellation are expected, but should not be exposed to clients.
                throw new OperationCanceledException(new OperationCanceledException().Message, ex);
            } catch (Exception ex) {
                Trace.Fail("Exception in RHost run loop:\n" + ex);
                throw;
            }
        }
Esempio n. 5
0
        private async Task ShowLocalizedDialogFormat(Message request, MessageButtons buttons, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            var response = await ShowDialog(new RContext[0], GetLocalizedString(request), buttons, ct);

            await RespondAsync(request, ct, response);
        }
Esempio n. 6
0
        private async Task EvaluateUntilCancelled(IReadOnlyList <IRContext> contexts, CancellationToken evaluationCancellationToken, CancellationToken hostCancellationToken)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            var  ct      = CancellationTokenSource.CreateLinkedTokenSource(hostCancellationToken, evaluationCancellationToken).Token;
            bool mutated = true; // start with true on the assumption that the preceding interaction has mutated something

            while (!ct.IsCancellationRequested)
            {
                try {
                    if (await EvaluateAll(contexts, mutated, hostCancellationToken))
                    {
                        // EvaluateAll has raised the event already, so reset the flag.
                        mutated = false;
                    }
                    else if (mutated)
                    {
                        // EvaluateAll did not raise the event, but we have a pending mutate to inform about.
                        OnMutated();
                    }

                    if (ct.IsCancellationRequested)
                    {
                        return;
                    }

                    var evaluationSource = await _pendingEvaluationSources.ReceiveAsync(ct);

                    mutated |= await evaluationSource.BeginEvaluationAsync(contexts, _host, hostCancellationToken);
                } catch (OperationCanceledException) {
                    return;
                }
            }
        }
Esempio n. 7
0
        private async Task <string> ShowDialog(RContext[] contexts, string message, MessageButtons buttons, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            MessageButtons input = await _callbacks.ShowDialog(contexts, message, buttons, ct);

            ct.ThrowIfCancellationRequested();

            string response;

            switch (input)
            {
            case MessageButtons.No:
                response = "N";
                break;

            case MessageButtons.Cancel:
                response = "C";
                break;

            case MessageButtons.Yes:
                response = "Y";
                break;

            default: {
                var error = Invariant($"YesNoCancel: callback returned an invalid value: {input}");
                Trace.Fail(error);
                throw new InvalidOperationException(error);
            }
            }
            return(response);
        }
Esempio n. 8
0
        public async Task Run(CancellationToken cancellationToken = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            if (_runTask != null)
            {
                throw new InvalidOperationException("This host is already running.");
            }

            var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken, _cts.Token);

            try {
                _runTask = RunWorker(cts.Token);
                await _runTask;
            } catch (OperationCanceledException) when(cancellationToken.IsCancellationRequested || _cts.Token.IsCancellationRequested)
            {
                // Expected cancellation, do not propagate, just exit process
            } catch (MessageTransportException ex) when(cancellationToken.IsCancellationRequested || _cts.Token.IsCancellationRequested)
            {
                // Network errors during cancellation are expected, but should not be exposed to clients.
                throw new OperationCanceledException(new OperationCanceledException().Message, ex);
            } catch (Exception ex) {
                var message = "Exception in RHost run loop:\n" + ex;
                Log.WriteLine(LogVerbosity.Minimal, MessageCategory.Error, message);
                Debug.Fail(message);
                throw;
            } finally {
                cts.Dispose();

                // Signal cancellation to any callbacks that haven't returned yet.
                _cts.Cancel();

                _requests.Clear();
            }
        }
Esempio n. 9
0
        public async Task <string> EditFileAsync(string content, string fileName, CancellationToken cancellationToken = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            var editor = _coreShell.GetService <IFileEditor>();

            if (!string.IsNullOrEmpty(content))
            {
                return(await editor.EditFileAsync(content, null, cancellationToken));
            }

            if (!string.IsNullOrEmpty(fileName))
            {
                if (_session.IsRemote)
                {
                    using (var dts = new DataTransferSession(_session, _fileSystem)) {
                        // TODO: handle progress for large files
                        try {
                            await dts.FetchFileToLocalTempAsync(fileName.ToRPath(), null, cancellationToken);

                            fileName = _fileSystem.GetDownloadsPath(Path.GetFileName(fileName));
                            return(await editor.EditFileAsync(null, fileName, cancellationToken));
                        } catch (OperationCanceledException) { }
                    }
                }
                return(await editor.EditFileAsync(null, fileName, cancellationToken));
            }
            return(string.Empty);
        }
Esempio n. 10
0
        internal async Task ReapplyBreakpointAsync(CancellationToken cancellationToken = default)
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            await Tracer.Session.ExecuteAsync(GetAddBreakpointExpression(false), cancellationToken);

            // TODO: mark breakpoint as invalid if this fails.
        }
Esempio n. 11
0
        internal async Task SetBreakpointAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            await Session.RSession.EvaluateAsync(GetAddBreakpointExpression(true), REvaluationKind.Mutating, cancellationToken);

            ++UseCount;
        }
Esempio n. 12
0
        public async Task Run(CancellationToken ct = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            if (_runTask != null)
            {
                throw new InvalidOperationException("This host is already running.");
            }

            ct = CancellationTokenSource.CreateLinkedTokenSource(ct, _cts.Token).Token;

            try {
                _runTask = RunWorker(ct);
                await _runTask;
            } catch (OperationCanceledException) when(ct.IsCancellationRequested)
            {
                // Expected cancellation, do not propagate, just exit process
            } catch (MessageTransportException ex) when(ct.IsCancellationRequested)
            {
                // Network errors during cancellation are expected, but should not be exposed to clients.
                throw new OperationCanceledException(new OperationCanceledException().Message, ex);
            } catch (Exception ex) {
                var message = "Exception in RHost run loop:\n" + ex;
                _log.WriteLineAsync(MessageCategory.Error, message).DoNotWait();
                Debug.Fail(message);
                throw;
            } finally {
                _requests.Clear();
            }
        }
Esempio n. 13
0
        private async Task RunWorker(CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            try {
                var message = await ReceiveMessageAsync(ct);

                if (message.Name != "Microsoft.R.Host" || message.RequestId != null)
                {
                    throw ProtocolError($"Microsoft.R.Host handshake expected:", message);
                }

                var protocolVersion = message.GetInt32(0, "protocol_version");
                if (protocolVersion != 1)
                {
                    throw ProtocolError($"Unsupported RHost protocol version:", message);
                }

                var rVersion = message.GetString(1, "R_version");
                await _callbacks.Connected(rVersion);

                message = await RunLoop(ct, allowEval : true);

                if (message != null)
                {
                    throw ProtocolError($"Unexpected host response message:", message);
                }
            } finally {
                await _callbacks.Disconnected();
            }
        }
Esempio n. 14
0
        internal async Task ReapplyBreakpointAsync(CancellationToken cancellationToken = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            await Session.RSession.EvaluateAsync(GetAddBreakpointExpression(false), REvaluationKind.Mutating, cancellationToken);

            // TODO: mark breakpoint as invalid if this fails.
        }
Esempio n. 15
0
        private async Task ReadConsole(Message request, bool allowEval, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            request.ExpectArguments(5);

            var contexts     = GetContexts(request);
            var len          = request.GetInt32(1, "len");
            var addToHistory = request.GetBoolean(2, "addToHistory");
            var retryReason  = request.GetString(3, "retry_reason", allowNull: true);
            var prompt       = request.GetString(4, "prompt", allowNull: true);

            string input;

            try {
                _canEval = allowEval;
                input    = await _callbacks.ReadConsole(contexts, prompt, len, addToHistory, _canEval, ct);
            } finally {
                _canEval = false;
            }

            ct.ThrowIfCancellationRequested();

            input = input.Replace("\r\n", "\n");
            await RespondAsync(request, ct, input);
        }
Esempio n. 16
0
        private async Task <ulong> NotifyAsync(string name, CancellationToken ct, params object[] args)
        {
            Debug.Assert(name.StartsWithOrdinal("!"));
            TaskUtilities.AssertIsOnBackgroundThread();

            var message = CreateMessage(name, 0, new JArray(args));

            await SendAsync(message, ct);

            return(message.Id);
        }
Esempio n. 17
0
        private async Task <ulong> RespondAsync(Message request, CancellationToken ct, params object[] args)
        {
            Debug.Assert(request.Name.StartsWithOrdinal("?"));
            TaskUtilities.AssertIsOnBackgroundThread();

            var message = CreateMessage(":" + request.Name.Substring(1), request.Id, new JArray(args));

            await SendAsync(message, ct);

            return(message.Id);
        }
Esempio n. 18
0
        private async Task <string> RespondAsync(Message request, CancellationToken ct, params object[] args)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            string id;
            var    message = CreateMessage(ct, out id, ":", request.Id, request.Name, args);

            await SendAsync(message, ct);

            return(id);
        }
Esempio n. 19
0
        private async Task ShowDialog(Message request, MessageButtons buttons, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            request.ExpectArguments(2);
            var contexts = GetContexts(request);
            var s        = request.GetString(1, "s", allowNull: true);

            var response = await ShowDialog(contexts, s, buttons, ct);

            await RespondAsync(request, ct, response);
        }
Esempio n. 20
0
        private async Task SendAsync(Message message, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            Log.Request(message.ToString(), _rLoopDepth);

            try {
                await _transport.SendAsync(message, ct);
            } catch (MessageTransportException ex) when(ct.IsCancellationRequested)
            {
                // Network errors during cancellation are expected, but should not be exposed to clients.
                throw new OperationCanceledException(new OperationCanceledException().Message, ex);
            } catch (MessageTransportException ex) {
                throw new RHostDisconnectedException(ex.Message, ex);
            }
        }
Esempio n. 21
0
        private async Task SendAsync(JToken token, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            var json = JsonConvert.SerializeObject(token);

            _log.Request(json, _rLoopDepth);

            try {
                await _transport.SendAsync(json, ct);
            } catch (MessageTransportException ex) when(ct.IsCancellationRequested)
            {
                // Network errors during cancellation are expected, but should not be exposed to clients.
                throw new OperationCanceledException(new OperationCanceledException().Message, ex);
            }
        }
Esempio n. 22
0
        private async Task RunWorker(CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            // Spin until the worker task is registered.
            while (_runTask == null)
            {
                await Task.Yield();
            }

            // Create cancellation tasks before proceeding with anything else, to avoid race conditions in usage of those tasks.
            _cancelEvaluationAfterRunTask      = _runTask.ContinueWith(t => RhostDisconnectedEvaluationResult).Unwrap();
            _cancelCreateBlobAfterRunTask      = _runTask.ContinueWith(t => RhostDisconnectedULongResult).Unwrap();
            _cancelBlobReadAfterRunTask        = _runTask.ContinueWith(t => RhostDisconnectedByteArrayResult).Unwrap();
            _cancelBlobWriteOrSizeAfterRunTask = _runTask.ContinueWith(t => RhostDisconnectedLongResult).Unwrap();

            try {
                var message = await ReceiveMessageAsync(ct);

                if (message == null || !message.IsNotification || message.Name != "!Microsoft.R.Host")
                {
                    throw ProtocolError($"Microsoft.R.Host handshake expected:", message);
                }

                var protocolVersion = message.GetInt32(0, "protocol_version");
                if (protocolVersion != 1)
                {
                    throw ProtocolError($"Unsupported RHost protocol version:", message);
                }

                var rVersion = message.GetString(1, "R_version");
                await _callbacks.Connected(rVersion);

                message = await RunLoop(ct);

                if (message != null)
                {
                    throw ProtocolError($"Unexpected host response message:", message);
                }
            } finally {
                // Signal cancellation to any callbacks that haven't returned yet.
                _cts.Cancel();

                await _callbacks.Disconnected();
            }
        }
Esempio n. 23
0
        private async Task RunWorker(CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            // Spin until the worker task is registered.
            while (_runTask == null)
            {
                await Task.Yield();
            }

            try {
                var message = await ReceiveMessageAsync(ct);

                if (message == null)
                {
                    // Socket is closed before connection is established. Just exit.
                    return;
                }

                if (!message.IsNotification || message.Name != "!Microsoft.R.Host")
                {
                    throw ProtocolError($"Microsoft.R.Host handshake expected:", message);
                }

                var protocolVersion = message.GetInt32(0, "protocol_version");
                if (protocolVersion != 1)
                {
                    throw ProtocolError($"Unsupported RHost protocol version:", message);
                }

                var rVersion = message.GetString(1, "R_version");
                await _callbacks.Connected(rVersion);

                message = await RunLoop(ct);

                if (message != null)
                {
                    throw ProtocolError($"Unexpected host response message:", message);
                }
            } finally {
                // Signal cancellation to any callbacks that haven't returned yet.
                _cts.Cancel();

                await _callbacks.Disconnected();
            }
        }
Esempio n. 24
0
        private async Task ShowDialog(Message request, bool allowEval, MessageButtons buttons, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            request.ExpectArguments(2);
            var contexts = GetContexts(request);
            var s        = request.GetString(1, "s", allowNull: true);

            MessageButtons input;

            try {
                _canEval = allowEval;
                input    = await _callbacks.ShowDialog(contexts, s, _canEval, buttons, ct);
            } finally {
                _canEval = false;
            }

            ct.ThrowIfCancellationRequested();

            string response;

            switch (input)
            {
            case MessageButtons.No:
                response = "N";
                break;

            case MessageButtons.Cancel:
                response = "C";
                break;

            case MessageButtons.Yes:
                response = "Y";
                break;

            default: {
                FormattableString error = $"YesNoCancel: callback returned an invalid value: {input}";
                Trace.Fail(Invariant(error));
                throw new InvalidOperationException(Invariant(error));
            }
            }

            await RespondAsync(request, ct, response);
        }
Esempio n. 25
0
        internal async Task <REvaluationResult> InvokeDebugHelperAsync(string expression, CancellationToken cancellationToken, bool json = false)
        {
            TaskUtilities.AssertIsOnBackgroundThread();
            ThrowIfDisposed();

            REvaluationResult res;

            using (var eval = await RSession.BeginEvaluationAsync(false, cancellationToken)) {
                res = await eval.EvaluateAsync(expression, json?REvaluationKind.Json : REvaluationKind.Normal);

                if (res.ParseStatus != RParseStatus.OK || res.Error != null || (json && res.JsonResult == null))
                {
                    Trace.Fail(Invariant($"Internal debugger evaluation {expression} failed: {res}"));
                    throw new REvaluationException(res);
                }
            }

            return(res);
        }
Esempio n. 26
0
        private async Task StartHostAsyncBackground(RHost host, CancellationToken cancellationToken = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            ResetInitializationTcs();
            ClearPendingRequests(new RHostDisconnectedException());

            Interlocked.Exchange(ref _host, host);
            Interlocked.Exchange(ref _initializedTcs, new TaskCompletionSourceEx <object>());

            var initializationCts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken);
            var hostRunTask       = RunHost(_host, _hostStartedTcs, initializationCts.Token);

            Interlocked.Exchange(ref _hostRunTask, hostRunTask)?.DoNotWait();

            await _hostStartedTcs.Task;
            await _initializedTcs.Task;

            initializationCts.Dispose();
            _stopHostLock.EnqueueReset();
        }
Esempio n. 27
0
        private async Task StartHostAsyncBackground(RHostStartupInfo startupInfo, IRSessionCallback callback, int timeout, CancellationToken cancellationToken)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            _callback    = callback;
            _startupInfo = startupInfo ?? new RHostStartupInfo();
            RHost host;

            try {
                var connectionInfo = new HostConnectionInfo(Name, this, _startupInfo.UseRHostCommandLineArguments, timeout);
                host = await BrokerClient.ConnectAsync(connectionInfo, cancellationToken);
            } catch (OperationCanceledException ex) {
                _hostStartedTcs.TrySetCanceled(ex);
                throw;
            } catch (Exception ex) {
                _hostStartedTcs.TrySetException(ex);
                throw;
            }

            await StartHostAsyncBackground(host, cancellationToken);
        }
Esempio n. 28
0
        private async Task <bool> EvaluateAll(IReadOnlyList <IRContext> contexts, bool mutated, CancellationToken hostCancellationToken)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            try {
                RSessionEvaluationSource source;
                while (!hostCancellationToken.IsCancellationRequested && _pendingEvaluationSources.TryReceive(out source))
                {
                    mutated |= await source.BeginEvaluationAsync(contexts, _host, hostCancellationToken);
                }
            } catch (OperationCanceledException) {
                // Host is being shut down, so there's no point in raising the event anymore.
                mutated = false;
            } finally {
                if (mutated)
                {
                    OnMutated();
                }
            }

            return(mutated);
        }
Esempio n. 29
0
        private Task <IAsyncReaderWriterLockToken> ExclusiveReaderLockAsync(ExclusiveReaderLock erLock, CancellationToken cancellationToken = default(CancellationToken))
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            if (cancellationToken.IsCancellationRequested)
            {
                return(Task.FromCanceled <IAsyncReaderWriterLockToken>(cancellationToken));
            }

            var source = new ExclusiveReaderLockSource(this, erLock);

            _queue.AddExclusiveReader(source, out var isAddedAfterWriterOrExclusiveReader);
            if (isAddedAfterWriterOrExclusiveReader)
            {
                source.RegisterCancellation(cancellationToken);
            }
            else
            {
                source.Release();
            }

            return(source.Task);
        }
Esempio n. 30
0
        private async Task <string> ReadNextRequest(string prompt, int len, CancellationToken ct)
        {
            TaskUtilities.AssertIsOnBackgroundThread();

            var requestSource = await _pendingRequestSources.ReceiveAsync(ct);

            TaskCompletionSource <string> requestTcs = new TaskCompletionSource <string>();

            Interlocked.Exchange(ref _currentRequestSource, requestSource);

            requestSource.Request(_contexts, prompt, len, requestTcs);
            using (ct.Register(() => requestTcs.TrySetCanceled())) {
                var response = await requestTcs.Task;

                Debug.Assert(response.Length < len); // len includes null terminator
                if (response.Length >= len)
                {
                    response = response.Substring(0, len - 1);
                }

                return(response);
            }
        }