[threadpool] Fix hang on domain unloading (#3904)
authorLudovic Henry <ludovic@xamarin.com>
Mon, 7 Nov 2016 20:11:22 +0000 (15:11 -0500)
committerGitHub <noreply@github.com>
Mon, 7 Nov 2016 20:11:22 +0000 (15:11 -0500)
Because we wouldn't return the correct ThreadPoolDomain for the requested domain, we would simply wait on the last inserted MonoDomain. This would lead to a hang when unloading the domain, as we wouldn't wait on the correct domain.

mono/metadata/threadpool-ms.c
mono/tests/Makefile.am
mono/tests/appdomain-threadpool-unload.cs [new file with mode: 0644]

index d22470415e84e1891759e5a31df748eacde76531..afd2bcc9e366b4b188cc4321437877f69327b172 100644 (file)
@@ -424,18 +424,20 @@ domain_remove (ThreadPoolDomain *tpdomain)
 static ThreadPoolDomain *
 domain_get (MonoDomain *domain, gboolean create)
 {
-       ThreadPoolDomain *tpdomain = NULL;
        guint i;
 
        g_assert (domain);
 
        for (i = 0; i < threadpool->domains->len; ++i) {
+               ThreadPoolDomain *tpdomain;
+
                tpdomain = (ThreadPoolDomain *)g_ptr_array_index (threadpool->domains, i);
                if (tpdomain->domain == domain)
                        return tpdomain;
        }
 
        if (create) {
+               ThreadPoolDomain *tpdomain;
                ThreadPoolDomainCleanupSemaphore *cleanup_semaphore;
                cleanup_semaphore = g_new0 (ThreadPoolDomainCleanupSemaphore, 1);
                cleanup_semaphore->ref = 2;
@@ -447,9 +449,11 @@ domain_get (MonoDomain *domain, gboolean create)
                tpdomain = g_new0 (ThreadPoolDomain, 1);
                tpdomain->domain = domain;
                domain_add (tpdomain);
+
+               return tpdomain;
        }
 
-       return tpdomain;
+       return NULL;
 }
 
 static void
index bdfafd99dab4f0179068c5c072064e628e46fd9b..92276ab63b24fd4b96fd54bca9a14515e31ee814 100644 (file)
@@ -141,7 +141,8 @@ BASE_TEST_MOBILE_STATIC_NOT_SUPPORTED= \
        cross-domain.cs \
        generic-unloading.2.cs  \
        namedmutex-destroy-race.cs      \
-       thread6.cs
+       thread6.cs      \
+       appdomain-threadpool-unload.cs
 
 # Disabled until ?mcs is fixed
 #      bug-331958.cs
diff --git a/mono/tests/appdomain-threadpool-unload.cs b/mono/tests/appdomain-threadpool-unload.cs
new file mode 100644 (file)
index 0000000..d8a7049
--- /dev/null
@@ -0,0 +1,52 @@
+
+using System;
+using System.Linq;
+using System.Threading;
+
+class Driver
+{
+       class ThreadPoolLauncherObject
+       {
+               public volatile int i = 0;
+
+               public ThreadPoolLauncherObject ()
+               {
+                       ThreadPool.QueueUserWorkItem (_ => { for (int i = 0; i < 10 * 1000 * 1000; ++i); }, null);
+               }
+       }
+
+       public static void Main ()
+       {
+               int count = 0;
+               object o = new object ();
+
+               foreach (var i in
+                       Enumerable.Range (0, 100)
+                               .AsParallel ().WithDegreeOfParallelism (Environment.ProcessorCount)
+                               .Select (i => {
+                                       AppDomain ad;
+
+                                       ad = AppDomain.CreateDomain ("testdomain" + i);
+                                       ad.CreateInstance (typeof (ThreadPoolLauncherObject).Assembly.FullName, typeof (ThreadPoolLauncherObject).FullName);
+
+                                       Thread.Sleep (10);
+
+                                       AppDomain.Unload (ad);
+
+                                       return i;
+                               })
+                               .Select (i => {
+                                       lock (o) {
+                                               count += 1;
+
+                                               Console.Write (".");
+                                               if (count % 25 == 0)
+                                                       Console.WriteLine ();
+                                       }
+
+                                       return i;
+                               })
+               ) {
+               }
+       }
+}