/// <summary> /// Logs all the messages that the tool wrote to either stderr or stdout. /// The messages are read out of the given data queue. This method is a /// helper for the <see cref="LogMessagesFromStandardError"/>() and <see /// cref="LogMessagesFromStandardOutput"/>() methods. /// </summary> /// <param name="dataQueue"></param> /// <param name="dataAvailableSignal"></param> /// <param name="messageImportance"></param> /// <param name="queueType"></param> private static void LogMessagesFromStandardErrorOrOutput ( Queue dataQueue, ManualResetEvent dataAvailableSignal, //MessageImportance messageImportance, StandardOutputOrErrorQueueType queueType ) { //ErrorUtilities.VerifyThrow(dataQueue != null, // "The data queue must be available."); // synchronize access to the queue -- this is a producer-consumer problem // NOTE: the synchronization problem here is actually not about the queue // at all -- if we only cared about reading from and writing to the queue, // we could use a synchronized wrapper around the queue, and things would // work perfectly; the synchronization problem here is actually around the // ManualResetEvent -- while a ManualResetEvent itself is a thread-safe // type, the information we infer from the state of a ManualResetEvent is // not thread-safe; because a ManualResetEvent does not have a ref count, // we cannot safely set (or reset) it outside of a synchronization block; // therefore instead of using synchronized queue wrappers, we just lock the // entire queue, empty it, and reset the ManualResetEvent before releasing // the lock; this also allows proper alternation between the stderr and // stdout queues -- otherwise we would continuously read from one queue and // starve the other; locking out the producer allows the consumer to // alternate between the queues lock (dataQueue.SyncRoot) { while (dataQueue.Count > 0) { string errorOrOutMessage = dataQueue.Dequeue() as String; Console.WriteLine(errorOrOutMessage); //if (!LogStandardErrorAsError || queueType == StandardOutputOrErrorQueueType.StandardOutput) //{ // this.LogEventsFromTextOutput(errorOrOutMessage, messageImportance); //} //else if (LogStandardErrorAsError && queueType == StandardOutputOrErrorQueueType.StandardError) //{ // Log.LogError(errorOrOutMessage); //} } //ErrorUtilities.VerifyThrow(dataAvailableSignal != null, // "The signalling event must be available."); // the queue is empty, so reset the notification // NOTE: intentionally, do the reset inside the lock, because // ManualResetEvents don't have ref counts, and we want to make // sure we don't reset the notification just after the producer // signals it dataAvailableSignal.Reset(); } }
/// <summary> /// Logs all the messages that the tool wrote to either stderr or stdout. /// The messages are read out of the given data queue. This method is a /// helper for the <see cref="LogMessagesFromStandardError"/>() and <see /// cref="LogMessagesFromStandardOutput"/>() methods. /// </summary> /// <param name="dataQueue"></param> /// <param name="dataAvailableSignal"></param> /// <param name="messageImportance"></param> private void LogMessagesFromStandardErrorOrOutput ( Queue dataQueue, ManualResetEvent dataAvailableSignal, MessageImportance messageImportance, StandardOutputOrErrorQueueType queueType ) { ErrorUtilities.VerifyThrow(dataQueue != null, "The data queue must be available."); // synchronize access to the queue -- this is a producer-consumer problem // NOTE: the synchronization problem here is actually not about the queue // at all -- if we only cared about reading from and writing to the queue, // we could use a synchronized wrapper around the queue, and things would // work perfectly; the synchronization problem here is actually around the // ManualResetEvent -- while a ManualResetEvent itself is a thread-safe // type, the information we infer from the state of a ManualResetEvent is // not thread-safe; because a ManualResetEvent does not have a ref count, // we cannot safely set (or reset) it outside of a synchronization block; // therefore instead of using synchronized queue wrappers, we just lock the // entire queue, empty it, and reset the ManualResetEvent before releasing // the lock; this also allows proper alternation between the stderr and // stdout queues -- otherwise we would continuously read from one queue and // starve the other; locking out the producer allows the consumer to // alternate between the queues lock (dataQueue.SyncRoot) { while (dataQueue.Count > 0) { string errorOrOutMessage = dataQueue.Dequeue() as String; if (!LogStandardErrorAsError || queueType == StandardOutputOrErrorQueueType.StandardOutput) { this.LogEventsFromTextOutput(errorOrOutMessage, messageImportance); } else if (LogStandardErrorAsError && queueType == StandardOutputOrErrorQueueType.StandardError) { Log.LogError(errorOrOutMessage); } } ErrorUtilities.VerifyThrow(dataAvailableSignal != null, "The signalling event must be available."); // the queue is empty, so reset the notification // NOTE: intentionally, do the reset inside the lock, because // ManualResetEvents don't have ref counts, and we want to make // sure we don't reset the notification just after the producer // signals it dataAvailableSignal.Reset(); } }
private void LogMessagesFromStandardErrorOrOutput(Queue dataQueue, ManualResetEvent dataAvailableSignal, MessageImportance messageImportance, StandardOutputOrErrorQueueType queueType) { ErrorUtilities.VerifyThrow(dataQueue != null, "The data queue must be available."); lock (dataQueue.SyncRoot) { while (dataQueue.Count > 0) { string singleLine = dataQueue.Dequeue() as string; if (!this.LogStandardErrorAsError || (queueType == StandardOutputOrErrorQueueType.StandardOutput)) { this.LogEventsFromTextOutput(singleLine, messageImportance); } else if (this.LogStandardErrorAsError && (queueType == StandardOutputOrErrorQueueType.StandardError)) { base.Log.LogError(singleLine, new object[0]); } } ErrorUtilities.VerifyThrow(dataAvailableSignal != null, "The signalling event must be available."); dataAvailableSignal.Reset(); } }