async Task <DeserializerState> CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) { ConsumedCapability cap; try { cap = await _capTask; } catch { args.Dispose(); throw; } if (cancellationToken.IsCancellationRequested) { args.Dispose(); cancellationToken.ThrowIfCancellationRequested(); } using var proxy = new Proxy(cap); var call = proxy.Call(interfaceId, methodId, args, default); var whenReturned = call.WhenReturned; using (var registration = cancellationToken.Register(call.Dispose)) { return(await whenReturned); } }
internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) { lock (_question.ReentrancyBlocker) { if (!_question.StateFlags.HasFlag(PendingQuestion.State.TailCall) && _question.StateFlags.HasFlag(PendingQuestion.State.Returned)) { return(CallOnResolution(interfaceId, methodId, args)); } else { #if DebugEmbargos Logger.LogDebug("Call by proxy"); #endif if (_question.StateFlags.HasFlag(PendingQuestion.State.CanceledByDispose) || _question.StateFlags.HasFlag(PendingQuestion.State.FinishRequested)) { args.Dispose(); throw new ObjectDisposedException(nameof(PendingQuestion)); } _question.DisallowFinish(); ++_pendingCallsOnPromise; var promisedAnswer = base.DoCall(interfaceId, methodId, args); ReAllowFinishWhenDone(promisedAnswer.WhenReturned); async void DecrementPendingCallsOnPromiseWhenReturned() { try { await promisedAnswer.WhenReturned; } catch { } finally { lock (_question.ReentrancyBlocker) { --_pendingCallsOnPromise; } } } DecrementPendingCallsOnPromiseWhenReturned(); return(promisedAnswer); } } }
async Task <DeserializerState> CallImpl(ulong interfaceId, ushort methodId, DynamicSerializerState args, CancellationToken cancellationToken) { var proxy = await _whenResolvedProxy; cancellationToken.ThrowIfCancellationRequested(); if (proxy.IsNull) { args.Dispose(); throw new RpcException("Broken capability"); } var call = proxy.Call(interfaceId, methodId, args, default); var whenReturned = call.WhenReturned; using var registration = cancellationToken.Register(() => call.Dispose()); return(await whenReturned); }
protected IPromisedAnswer CallOnResolution(ulong interfaceId, ushort methodId, DynamicSerializerState args) { var resolvedCap = ResolvedCap !; try { if (resolvedCap is NullCapability || // Must not request disembargo on null cap resolvedCap is RemoteCapability || //# Note that in the case where Carol actually lives in Vat B (i.e., the same vat that the promise //# already pointed at), no embargo is needed, because the pipelined calls are delivered over the //# same path as the later direct calls. (_disembargo == null && _pendingCallsOnPromise == 0) || // No embargo is needed since all outstanding replies have returned _disembargo?.IsCompleted == true // Disembargo has returned ) { #if DebugEmbargos Logger.LogDebug("Direct call"); #endif using var proxy = new Proxy(resolvedCap); return(proxy.Call(interfaceId, methodId, args, default)); } else { if (_disembargo == null) { #if DebugEmbargos Logger.LogDebug("Requesting disembargo"); #endif _disembargo = _ep.RequestSenderLoopback(GetMessageTarget).EnforceAwaitOrder(); } else { #if DebugEmbargos Logger.LogDebug("Waiting for requested disembargo"); #endif } var cancellationTokenSource = new CancellationTokenSource(); async Task <DeserializerState> AwaitAnswer() { await _disembargo !; // Two reasons for ignoring exceptions on the previous task (i.e. not _.Wait()ing): // 1. A faulting predecessor, especially due to cancellation, must not have any impact on this one. // 2. A faulting disembargo request would imply that the other side cannot send pending requests anyway. if (cancellationTokenSource.Token.IsCancellationRequested) { args.Dispose(); cancellationTokenSource.Token.ThrowIfCancellationRequested(); } using var proxy = new Proxy(resolvedCap); var promisedAnswer = proxy.Call(interfaceId, methodId, args, default); using (cancellationTokenSource.Token.Register(promisedAnswer.Dispose)) { return(await promisedAnswer.WhenReturned); } } return(new LocalAnswer(cancellationTokenSource, AwaitAnswer())); } } catch (System.Exception exception) { // Wrap exception into local answer, since otherwise we'd get an AggregateException (which we don't want). return(new LocalAnswer( new CancellationTokenSource(), Task.FromException <DeserializerState>(exception))); } }
internal override IPromisedAnswer DoCall(ulong interfaceId, ushort methodId, DynamicSerializerState args) { args.Dispose(); throw new InvalidOperationException("Cannot call null capability"); }