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 }