From ee1825219b8ccca13df7198d4e9ffb966e44c883 Mon Sep 17 00:00:00 2001
From: FICTURE7 <FICTURE7@gmail.com>
Date: Fri, 9 Sep 2022 03:14:08 +0400
Subject: Clean up rejit queue (#2751)

---
 ARMeilleure/Translation/TranslatorQueue.cs | 121 +++++++++++++++++++++++++++++
 1 file changed, 121 insertions(+)
 create mode 100644 ARMeilleure/Translation/TranslatorQueue.cs

(limited to 'ARMeilleure/Translation/TranslatorQueue.cs')

diff --git a/ARMeilleure/Translation/TranslatorQueue.cs b/ARMeilleure/Translation/TranslatorQueue.cs
new file mode 100644
index 00000000..fc0aa64f
--- /dev/null
+++ b/ARMeilleure/Translation/TranslatorQueue.cs
@@ -0,0 +1,121 @@
+using ARMeilleure.Diagnostics;
+using ARMeilleure.State;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace ARMeilleure.Translation
+{
+    /// <summary>
+    /// Represents a queue of <see cref="RejitRequest"/>.
+    /// </summary>
+    /// <remarks>
+    /// This does not necessarily behave like a queue, i.e: a FIFO collection.
+    /// </remarks>
+    sealed class TranslatorQueue : IDisposable
+    {
+        private bool _disposed;
+        private readonly Stack<RejitRequest> _requests;
+        private readonly HashSet<ulong> _requestAddresses;
+
+        /// <summary>
+        /// Gets the object used to synchronize access to the <see cref="TranslatorQueue"/>.
+        /// </summary>
+        public object Sync { get; }
+
+        /// <summary>
+        /// Gets the number of requests in the <see cref="TranslatorQueue"/>.
+        /// </summary>
+        public int Count => _requests.Count;
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="TranslatorQueue"/> class.
+        /// </summary>
+        public TranslatorQueue()
+        {
+            Sync = new object();
+
+            _requests = new Stack<RejitRequest>();
+            _requestAddresses = new HashSet<ulong>();
+        }
+
+        /// <summary>
+        /// Enqueues a request with the specified <paramref name="address"/> and <paramref name="mode"/>.
+        /// </summary>
+        /// <param name="address">Address of request</param>
+        /// <param name="mode"><see cref="ExecutionMode"/> of request</param>
+        public void Enqueue(ulong address, ExecutionMode mode)
+        {
+            lock (Sync)
+            {
+                if (_requestAddresses.Add(address))
+                {
+                    _requests.Push(new RejitRequest(address, mode));
+
+                    TranslatorEventSource.Log.RejitQueueAdd(1);
+
+                    Monitor.Pulse(Sync);
+                }
+            }
+        }
+
+        /// <summary>
+        /// Tries to dequeue a <see cref="RejitRequest"/>. This will block the thread until a <see cref="RejitRequest"/>
+        /// is enqueued or the <see cref="TranslatorQueue"/> is disposed.
+        /// </summary>
+        /// <param name="result"><see cref="RejitRequest"/> dequeued</param>
+        /// <returns><see langword="true"/> on success; otherwise <see langword="false"/></returns>
+        public bool TryDequeue(out RejitRequest result)
+        {
+            while (!_disposed)
+            {
+                lock (Sync)
+                {
+                    if (_requests.TryPop(out result))
+                    {
+                        _requestAddresses.Remove(result.Address);
+
+                        TranslatorEventSource.Log.RejitQueueAdd(-1);
+
+                        return true;
+                    }
+
+                    Monitor.Wait(Sync);
+                }
+            }
+
+            result = default;
+
+            return false;
+        }
+
+        /// <summary>
+        /// Clears the <see cref="TranslatorQueue"/>.
+        /// </summary>
+        public void Clear()
+        {
+            lock (Sync)
+            {
+                TranslatorEventSource.Log.RejitQueueAdd(-_requests.Count);
+
+                _requests.Clear();
+                _requestAddresses.Clear();
+
+                Monitor.PulseAll(Sync);
+            }
+        }
+
+        /// <summary>
+        /// Releases all resources used by the <see cref="TranslatorQueue"/> instance.
+        /// </summary>
+        public void Dispose()
+        {
+            if (!_disposed)
+            {
+                _disposed = true;
+
+                Clear();
+            }
+        }
+    }
+}
-- 
cgit v1.2.3-70-g09d2