/// <summary> /// Shuts the processing pipeline down (base class specific part). /// This method must not throw exceptions. /// </summary> internal override void OnShutdownBase() { // tell the processing thread to terminate // (it will try to process the last messages and exit) mTerminateProcessingTask = true; mAsyncProcessingCancellationTokenSource?.CancelAfter(mShutdownTimeout); mTriggerAsyncProcessingEvent?.Set(); mAsyncProcessingTask?.Wait(); // the processing task should have completed its work Debug.Assert(mAsyncProcessingTask == null || mAsyncProcessingTask.IsCompleted); // the stack should be empty now... Debug.Assert(mAsyncProcessingMessageStack == null || mAsyncProcessingMessageStack.UsedItemCount == 0); // clean up processing thread related stuff mAsyncContextThread?.Join(); mAsyncProcessingCancellationTokenSource?.Dispose(); mAsyncContextThread = null; mAsyncProcessingTask = null; mAsyncProcessingCancellationTokenSource = null; mAsyncProcessingMessageStack = null; // perform pipeline stage specific cleanup try { OnShutdown(); } catch (Exception ex) { // swallow exception to avoid crashing the application, if the exception is not handled properly Debug.Fail("The pipeline stage failed shutting down.", ex.ToString()); } }
/// <summary> /// Initializes the processing pipeline stage (base class specific part). /// </summary> internal override void OnInitializeBase() { try { // set up asynchronous processing mAsyncProcessingMessageStack = new LocklessStack <LocalLogMessage>(mMessageQueueSize, false); mTriggerAsyncProcessingEvent = new AsyncAutoResetEvent(false); mAsyncProcessingCancellationTokenSource = new CancellationTokenSource(); mTerminateProcessingTask = false; mAsyncContextThread = new AsyncContextThread(); mAsyncProcessingTask = mAsyncContextThread.Factory.Run(ProcessingTask); // Perform pipeline stage specific initialization OnInitialize(); } catch (Exception) { Shutdown(); throw; } }