AsyncLogTargetWrapper.cs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. using System;
  2. using System.Collections.Concurrent;
  3. using System.Threading;
  4. namespace Ryujinx.Common.Logging
  5. {
  6. public enum AsyncLogTargetOverflowAction
  7. {
  8. /// <summary>
  9. /// Block until there's more room in the queue
  10. /// </summary>
  11. Block = 0,
  12. /// <summary>
  13. /// Discard the overflowing item
  14. /// </summary>
  15. Discard = 1
  16. }
  17. public class AsyncLogTargetWrapper : ILogTarget
  18. {
  19. private ILogTarget _target;
  20. private Thread _messageThread;
  21. private BlockingCollection<LogEventArgs> _messageQueue;
  22. private readonly int _overflowTimeout;
  23. string ILogTarget.Name { get => _target.Name; }
  24. public AsyncLogTargetWrapper(ILogTarget target)
  25. : this(target, -1, AsyncLogTargetOverflowAction.Block)
  26. { }
  27. public AsyncLogTargetWrapper(ILogTarget target, int queueLimit, AsyncLogTargetOverflowAction overflowAction)
  28. {
  29. _target = target;
  30. _messageQueue = new BlockingCollection<LogEventArgs>(queueLimit);
  31. _overflowTimeout = overflowAction == AsyncLogTargetOverflowAction.Block ? -1 : 0;
  32. _messageThread = new Thread(() => {
  33. while (!_messageQueue.IsCompleted)
  34. {
  35. try
  36. {
  37. _target.Log(this, _messageQueue.Take());
  38. }
  39. catch (InvalidOperationException)
  40. {
  41. // IOE means that Take() was called on a completed collection.
  42. // Some other thread can call CompleteAdding after we pass the
  43. // IsCompleted check but before we call Take.
  44. // We can simply catch the exception since the loop will break
  45. // on the next iteration.
  46. }
  47. }
  48. });
  49. _messageThread.IsBackground = true;
  50. _messageThread.Start();
  51. }
  52. public void Log(object sender, LogEventArgs e)
  53. {
  54. if (!_messageQueue.IsAddingCompleted)
  55. {
  56. _messageQueue.TryAdd(e, _overflowTimeout);
  57. }
  58. }
  59. public void Dispose()
  60. {
  61. _messageQueue.CompleteAdding();
  62. _messageThread.Join();
  63. }
  64. }
  65. }