Kaynağa Gözat

[threadpool] Fix get min and available threads icalls

Fix bug #36414
Ludovic Henry 10 yıl önce
ebeveyn
işleme
780fbf4a57

+ 97 - 0
mcs/class/corlib/Test/System.Threading/ThreadPoolTest.cs

@@ -35,6 +35,25 @@ namespace MonoTests.System.Threading
 	[TestFixture]
 	public class ThreadPoolTests
 	{
+		int minWorkerThreads;
+		int minCompletionPortThreads;
+		int maxWorkerThreads;
+		int maxCompletionPortThreads;
+
+		[SetUp]
+		public void SetUp ()
+		{
+			ThreadPool.GetMinThreads (out minWorkerThreads, out minCompletionPortThreads);
+			ThreadPool.GetMaxThreads (out maxWorkerThreads, out maxCompletionPortThreads);
+		}
+
+		[TearDown]
+		public void TearDown ()
+		{
+			ThreadPool.SetMinThreads (minWorkerThreads, minCompletionPortThreads);
+			ThreadPool.SetMaxThreads (maxWorkerThreads, maxCompletionPortThreads);
+		}
+
 		[Test]
 		public void RegisterWaitForSingleObject_InvalidArguments ()
 		{
@@ -97,5 +116,83 @@ namespace MonoTests.System.Threading
 			ThreadPool.UnsafeQueueUserWorkItem (e, null);
 			Assert.IsTrue (ev.Wait (3000));
 		}
+
+		[Test]
+		public void SetAndGetMinThreads ()
+		{
+			int workerThreads, completionPortThreads;
+			int workerThreads_new, completionPortThreads_new;
+
+			ThreadPool.GetMinThreads (out workerThreads, out completionPortThreads);
+			Assert.IsTrue (workerThreads > 0, "#1");
+			Assert.IsTrue (completionPortThreads > 0, "#2");
+
+			workerThreads_new = workerThreads == 1 ? 2 : 1;
+			completionPortThreads_new = completionPortThreads == 1 ? 2 : 1;
+
+			ThreadPool.SetMinThreads (workerThreads_new, completionPortThreads_new);
+			ThreadPool.GetMinThreads (out workerThreads, out completionPortThreads);
+			Assert.IsTrue (workerThreads == workerThreads_new, "#3");
+			Assert.IsTrue (completionPortThreads == completionPortThreads_new, "#4");
+		}
+
+		[Test]
+		public void SetAndGetMaxThreads ()
+		{
+			int cpuCount = Environment.ProcessorCount;
+			int workerThreads, completionPortThreads;
+			int workerThreads_new, completionPortThreads_new;
+
+			ThreadPool.GetMaxThreads (out workerThreads, out completionPortThreads);
+			Assert.IsTrue (workerThreads > 0, "#1");
+			Assert.IsTrue (completionPortThreads > 0, "#2");
+
+			workerThreads_new = workerThreads == cpuCount ? cpuCount + 1 : cpuCount;
+			completionPortThreads_new = completionPortThreads == cpuCount ? cpuCount + 1 : cpuCount;
+
+			ThreadPool.SetMaxThreads (workerThreads_new, completionPortThreads_new);
+			ThreadPool.GetMaxThreads (out workerThreads, out completionPortThreads);
+			Assert.IsTrue (workerThreads == workerThreads_new, "#3");
+			Assert.IsTrue (completionPortThreads == completionPortThreads_new, "#4");
+		}
+
+		[Test]
+		public void GetAvailableThreads ()
+		{
+			ManualResetEvent mre = new ManualResetEvent (false);
+			DateTime start = DateTime.Now;
+			int i, workerThreads, completionPortThreads;
+
+			try {
+				while (true) {
+					ThreadPool.GetAvailableThreads (out workerThreads, out completionPortThreads);
+					if (workerThreads == 0)
+						break;
+
+					if ((DateTime.Now - start).TotalSeconds >= 10)
+						Assert.Fail ("did not reach 0 available threads");
+
+					ThreadPool.QueueUserWorkItem (GetAvailableThreads_Callback, mre);
+					Thread.Sleep (1);
+				}
+			} finally {
+				mre.Set ();
+			}
+		}
+
+		void GetAvailableThreads_Callback (object state)
+		{
+			ManualResetEvent mre = (ManualResetEvent) state;
+
+			if (mre.WaitOne (0))
+				return;
+
+			ThreadPool.QueueUserWorkItem (GetAvailableThreads_Callback, mre);
+			ThreadPool.QueueUserWorkItem (GetAvailableThreads_Callback, mre);
+			ThreadPool.QueueUserWorkItem (GetAvailableThreads_Callback, mre);
+			ThreadPool.QueueUserWorkItem (GetAvailableThreads_Callback, mre);
+
+			mre.WaitOne ();
+		}
 	}
 }

+ 7 - 3
mono/metadata/threadpool-ms.c

@@ -1421,12 +1421,16 @@ mono_threadpool_ms_resume (void)
 void
 ves_icall_System_Threading_ThreadPool_GetAvailableThreadsNative (gint32 *worker_threads, gint32 *completion_port_threads)
 {
+	ThreadPoolCounter counter;
+
 	if (!worker_threads || !completion_port_threads)
 		return;
 
 	mono_lazy_initialize (&status, initialize);
 
-	*worker_threads = threadpool->limit_worker_max;
+	counter.as_gint64 = COUNTER_READ ();
+
+	*worker_threads = counter._.max_working - counter._.active;
 	*completion_port_threads = threadpool->limit_io_max;
 }
 
@@ -1464,8 +1468,8 @@ ves_icall_System_Threading_ThreadPool_SetMinThreadsNative (gint32 worker_threads
 	if (completion_port_threads <= 0 || completion_port_threads > threadpool->limit_io_max)
 		return FALSE;
 
-	threadpool->limit_worker_max = worker_threads;
-	threadpool->limit_io_max = completion_port_threads;
+	threadpool->limit_worker_min = worker_threads;
+	threadpool->limit_io_min = completion_port_threads;
 
 	return TRUE;
 }