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