public async ValueTask <IncomingResponseFrame> SendRequestAsync( OutgoingRequestFrame outgoingRequest, bool oneway, bool synchronous, IInvocationObserver?observer, IProgress <bool> progress, CancellationToken cancel) { cancel.ThrowIfCancellationRequested(); IChildInvocationObserver?childObserver = null; int requestId = 0; // The CollocatedRequestHandler is an internal object so it's safe to lock (this) as long as our // code doesn't use the collocated request handler as a lock. The lock here is useful to ensure // the protocol trace and observer call is output or called in the same order as the request ID // is allocated. lock (_mutex) { if (!oneway) { requestId = ++_requestId; } if (observer != null) { childObserver = observer.GetCollocatedObserver(_adapter, requestId, outgoingRequest.Size); childObserver?.Attach(); } if (_adapter.Communicator.TraceLevels.Protocol >= 1) { ProtocolTrace.TraceCollocatedFrame(_adapter.Communicator, (byte)Ice1Definitions.FrameType.Request, requestId, outgoingRequest); } } Task <OutgoingResponseFrame> task; if (_adapter.TaskScheduler != null || !synchronous || oneway || _reference.InvocationTimeout > 0) { // Don't invoke from the user thread if async or invocation timeout is set. We also don't dispatch // oneway from the user thread to match the non-collocated behavior where the oneway synchronous // request returns as soon as it's sent over the transport. task = Task.Factory.StartNew(() => { progress.Report(false); return(DispatchAsync(outgoingRequest, requestId, cancel)); }, cancel, TaskCreationOptions.None, _adapter.TaskScheduler ?? TaskScheduler.Default).Unwrap(); if (oneway) { childObserver?.Detach(); return(IncomingResponseFrame.WithVoidReturnValue(outgoingRequest.Protocol, outgoingRequest.Encoding)); } } else // Optimization: directly call DispatchAsync { Debug.Assert(!oneway); progress.Report(false); task = DispatchAsync(outgoingRequest, requestId, cancel); } try { OutgoingResponseFrame outgoingResponseFrame = await task.WaitAsync(cancel).ConfigureAwait(false); var incomingResponseFrame = new IncomingResponseFrame( outgoingRequest.Protocol, VectoredBufferExtensions.ToArray(outgoingResponseFrame.Data), _adapter.IncomingFrameSizeMax); if (_adapter.Communicator.TraceLevels.Protocol >= 1) { ProtocolTrace.TraceCollocatedFrame(_adapter.Communicator, (byte)Ice1Definitions.FrameType.Reply, requestId, incomingResponseFrame); } childObserver?.Reply(incomingResponseFrame.Size); return(incomingResponseFrame); } catch (Exception ex) { childObserver?.Failed(ex.GetType().FullName ?? "System.Exception"); throw; } finally { childObserver?.Detach(); } }
// TODO avoid copy payload (ToArray) creates a copy, that should be possible when // the frame has a single segment. internal IncomingRequestFrame(OutgoingRequestFrame frame) : this(frame.Protocol, VectoredBufferExtensions.ToArray(frame.Data)) { }
// TODO avoid copy payload (ToArray) creates a copy, that should be possible when // the frame has a single segment. internal IncomingRequestFrame(Communicator communicator, OutgoingRequestFrame frame) : this(communicator, VectoredBufferExtensions.ToArray(frame.Data)) { }