internal async Task SetBreakpointAsync(CancellationToken cancellationToken = default(CancellationToken)) { TaskUtilities.AssertIsOnBackgroundThread(); await Session.InvokeDebugHelperAsync(GetAddBreakpointExpression(true), cancellationToken); ++UseCount; }
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); }
internal async Task SetBreakpointAsync(CancellationToken cancellationToken = default(CancellationToken)) { TaskUtilities.AssertIsOnBackgroundThread(); await Tracer.Session.ExecuteAsync(GetAddBreakpointExpression(true), cancellationToken); ++UseCount; }
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; } }
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); }
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; } } }
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); }
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(); } }
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); }
internal async Task ReapplyBreakpointAsync(CancellationToken cancellationToken = default) { TaskUtilities.AssertIsOnBackgroundThread(); await Tracer.Session.ExecuteAsync(GetAddBreakpointExpression(false), cancellationToken); // TODO: mark breakpoint as invalid if this fails. }
internal async Task SetBreakpointAsync(CancellationToken cancellationToken = default(CancellationToken)) { TaskUtilities.AssertIsOnBackgroundThread(); await Session.RSession.EvaluateAsync(GetAddBreakpointExpression(true), REvaluationKind.Mutating, cancellationToken); ++UseCount; }
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(); } }
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(); } }
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. }
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); }
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); }
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); }
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); }
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); }
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); } }
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); } }
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(); } }
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(); } }
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); }
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); }
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(); }
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); }
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); }
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); }
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); } }