private async Task ZBackgroundSendAsync(cTrace.cContext pParentContext) { var lContext = pParentContext.NewRootMethod(true, nameof(cCommandPipeline), nameof(ZBackgroundSendAsync)); mBackgroundSendBuffer.SetTracing(lContext); if (mCurrentCommand != null) { await ZBackgroundSendAppendDataAndMoveNextAsync(lContext).ConfigureAwait(false); } while (true) { if (mCurrentCommand == null) { ZBackgroundSendDequeueAndAppendTag(lContext); if (mCurrentCommand == null) { break; } if (mCurrentCommand.IsAuthentication) { await ZBackgroundSendAppendAllTextPartsAsync(lContext).ConfigureAwait(false); mCurrentCommand.WaitingForContinuationRequest = true; break; } } if (mCurrentCommand.State == eCommandState.current) { if (ZBackgroundSendAppendLiteralHeader()) { mCurrentCommand.WaitingForContinuationRequest = true; break; } await ZBackgroundSendAppendDataAndMoveNextAsync(lContext).ConfigureAwait(false); } else { ZBackgroundSendTerminateCommand(lContext); } } await mBackgroundSendBuffer.WriteAsync(lContext).ConfigureAwait(false); }
private async Task ZBackgroundTaskAsync(cTrace.cContext pParentContext) { var lContext = pParentContext.NewRootMethod(nameof(cCallbackSynchroniser), nameof(ZBackgroundTaskAsync)); while (true) { lContext.TraceVerbose("waiting"); await mBackgroundReleaser.GetAwaitReleaseTask(lContext).ConfigureAwait(false); mBackgroundReleaser.Reset(lContext); var lSynchronizationContext = SynchronizationContext; if (lSynchronizationContext == null || ReferenceEquals(SynchronizationContext.Current, lSynchronizationContext)) { lContext.TraceVerbose("on the correct sc"); ZInvokeWorker(lContext); } else { if (mOutstandingPost) { lContext.TraceVerbose("not on the correct sc: but there is an outstanding post"); } else { lContext.TraceVerbose("not on the correct sc: posting an invoke to the correct one"); mOutstandingPost = true; // this is the reason the background task exists: if the SC doesn't implement an async post method then this could block lSynchronizationContext.Post( (p) => { mOutstandingPost = false; ZInvokeWorker(lContext); }, null); } } } }
private async Task ZBackgroundTaskAsync(cTrace.cContext pParentContext) { var lContext = pParentContext.NewRootMethod(nameof(cCommandPipeline), nameof(ZBackgroundTaskAsync)); Task lBackgroundSendTask = null; try { while (true) { mBackgroundReleaser.Reset(lContext); if (lBackgroundSendTask != null && lBackgroundSendTask.IsCompleted) { lContext.TraceVerbose("send is complete"); lBackgroundSendTask.Wait(); // will throw if there was an error lBackgroundSendTask.Dispose(); lBackgroundSendTask = null; } if (lBackgroundSendTask == null && ((mCurrentCommand == null && mQueuedCommands.Count > 0) || (mCurrentCommand != null && !mCurrentCommand.IsAuthentication && !mCurrentCommand.WaitingForContinuationRequest) ) ) { lBackgroundSendTask = ZBackgroundSendAsync(lContext); } if (lBackgroundSendTask == null && mCurrentCommand == null && mActiveCommands.Count == 0) { var lIdleConfiguration = mIdleConfiguration; cExclusiveAccess.cBlock lIdleBlockBlock = null; if (mState == eState.enabled && lIdleConfiguration != null) { lIdleBlockBlock = mIdleBlock.TryGetBlock(lContext); } if (lIdleBlockBlock != null) { await ZIdleAsync(lIdleConfiguration, lContext).ConfigureAwait(false); lIdleBlockBlock.Dispose(); } else { lContext.TraceVerbose("there is nothing to do, waiting for something to change"); await mBackgroundReleaser.GetAwaitReleaseTask(lContext).ConfigureAwait(false); } } else { Task lBuildResponseTask = mConnection.GetBuildResponseTask(lContext); Task lBackgroundReleaserTask = mBackgroundReleaser.GetAwaitReleaseTask(lContext); Task lCompleted = await mBackgroundAwaiter.AwaitAny(lBuildResponseTask, lBackgroundReleaserTask, lBackgroundSendTask).ConfigureAwait(false); if (ReferenceEquals(lCompleted, lBuildResponseTask)) { await ZBackgroundTaskProcessResponseAsync(lContext).ConfigureAwait(false); // this check here to make sure logoff is handled correctly if (mBackgroundCancellationTokenSource.IsCancellationRequested) { lContext.TraceInformation("the pipeline is stopping as requested"); mBackgroundTaskException = new cPipelineStoppedException(); break; } } } } } catch (cUnilateralByeException e) { lContext.TraceInformation("the pipeline is stopping due to a unilateral bye"); mBackgroundTaskException = e; } catch (OperationCanceledException) when(mBackgroundCancellationTokenSource.IsCancellationRequested) { lContext.TraceInformation("the pipeline is stopping as requested"); mBackgroundTaskException = new cPipelineStoppedException(); } catch (AggregateException e) { lContext.TraceException("the pipeline is stopping due to an unexpected exception", e); var lException = e.Flatten(); if (lException.InnerExceptions.Count == 1) { mBackgroundTaskException = new cPipelineStoppedException(lException.InnerExceptions[0], lContext); } else { mBackgroundTaskException = new cPipelineStoppedException(e, lContext); } } catch (Exception e) { lContext.TraceException("the pipeline is stopping due to an unexpected exception", e); mBackgroundTaskException = new cPipelineStoppedException(e, lContext); } // if the send is still going this will kill it mConnection.Disconnect(lContext); if (lBackgroundSendTask != null) { lContext.TraceVerbose("waiting for send to complete"); try { await lBackgroundSendTask.ConfigureAwait(false); } catch (Exception e) { lContext.TraceException("send reported an exception at pipeline stop", e); } lBackgroundSendTask.Dispose(); } lock (mPipelineLock) { mState = eState.stopped; } foreach (var lCommand in mActiveCommands) { lCommand.SetException(mBackgroundTaskException, lContext); } if (mCurrentCommand != null) { mCurrentCommand.SetException(mBackgroundTaskException, lContext); } foreach (var lCommand in mQueuedCommands) { lCommand.SetException(mBackgroundTaskException, lContext); } mDisconnected(lContext); }