TranslatorQueue.cs 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. using ARMeilleure.Diagnostics;
  2. using ARMeilleure.State;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.Threading;
  6. namespace ARMeilleure.Translation
  7. {
  8. /// <summary>
  9. /// Represents a queue of <see cref="RejitRequest"/>.
  10. /// </summary>
  11. /// <remarks>
  12. /// This does not necessarily behave like a queue, i.e: a FIFO collection.
  13. /// </remarks>
  14. sealed class TranslatorQueue : IDisposable
  15. {
  16. private bool _disposed;
  17. private readonly Stack<RejitRequest> _requests;
  18. private readonly HashSet<ulong> _requestAddresses;
  19. /// <summary>
  20. /// Gets the object used to synchronize access to the <see cref="TranslatorQueue"/>.
  21. /// </summary>
  22. public object Sync { get; }
  23. /// <summary>
  24. /// Gets the number of requests in the <see cref="TranslatorQueue"/>.
  25. /// </summary>
  26. public int Count => _requests.Count;
  27. /// <summary>
  28. /// Initializes a new instance of the <see cref="TranslatorQueue"/> class.
  29. /// </summary>
  30. public TranslatorQueue()
  31. {
  32. Sync = new object();
  33. _requests = new Stack<RejitRequest>();
  34. _requestAddresses = new HashSet<ulong>();
  35. }
  36. /// <summary>
  37. /// Enqueues a request with the specified <paramref name="address"/> and <paramref name="mode"/>.
  38. /// </summary>
  39. /// <param name="address">Address of request</param>
  40. /// <param name="mode"><see cref="ExecutionMode"/> of request</param>
  41. public void Enqueue(ulong address, ExecutionMode mode)
  42. {
  43. lock (Sync)
  44. {
  45. if (_requestAddresses.Add(address))
  46. {
  47. _requests.Push(new RejitRequest(address, mode));
  48. TranslatorEventSource.Log.RejitQueueAdd(1);
  49. Monitor.Pulse(Sync);
  50. }
  51. }
  52. }
  53. /// <summary>
  54. /// Tries to dequeue a <see cref="RejitRequest"/>. This will block the thread until a <see cref="RejitRequest"/>
  55. /// is enqueued or the <see cref="TranslatorQueue"/> is disposed.
  56. /// </summary>
  57. /// <param name="result"><see cref="RejitRequest"/> dequeued</param>
  58. /// <returns><see langword="true"/> on success; otherwise <see langword="false"/></returns>
  59. public bool TryDequeue(out RejitRequest result)
  60. {
  61. while (!_disposed)
  62. {
  63. lock (Sync)
  64. {
  65. if (_requests.TryPop(out result))
  66. {
  67. _requestAddresses.Remove(result.Address);
  68. TranslatorEventSource.Log.RejitQueueAdd(-1);
  69. return true;
  70. }
  71. Monitor.Wait(Sync);
  72. }
  73. }
  74. result = default;
  75. return false;
  76. }
  77. /// <summary>
  78. /// Clears the <see cref="TranslatorQueue"/>.
  79. /// </summary>
  80. public void Clear()
  81. {
  82. lock (Sync)
  83. {
  84. TranslatorEventSource.Log.RejitQueueAdd(-_requests.Count);
  85. _requests.Clear();
  86. _requestAddresses.Clear();
  87. Monitor.PulseAll(Sync);
  88. }
  89. }
  90. /// <summary>
  91. /// Releases all resources used by the <see cref="TranslatorQueue"/> instance.
  92. /// </summary>
  93. public void Dispose()
  94. {
  95. if (!_disposed)
  96. {
  97. _disposed = true;
  98. Clear();
  99. }
  100. }
  101. }
  102. }