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);
            }
        }
示例#2
0
        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);
                }
            }
        }
示例#3
0
        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);
        }
示例#4
0
        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");
 }