Backport some changes from nunit/nunitv2 that hopefully fix some test agent hangs.
authorAlex Rønne Petersen <alexrp@xamarin.com>
Tue, 29 Apr 2014 18:23:19 +0000 (20:23 +0200)
committerAlex Rønne Petersen <alexrp@xamarin.com>
Tue, 29 Apr 2014 22:02:52 +0000 (00:02 +0200)
mcs/nunit24/ClientUtilities/util/Services/DomainManager.cs
mcs/nunit24/NUnitCore/core/.gitattributes
mcs/nunit24/NUnitCore/core/TestRunnerThread.cs
mcs/nunit24/NUnitCore/core/ThreadUtility.cs [new file with mode: 0644]
mcs/nunit24/NUnitCore/core/nunit.core.build
mcs/nunit24/NUnitCore/core/nunit.core.dll.csproj
mcs/nunit24/NUnitCore/core/nunit.core.dll.sources
mcs/nunit24/NUnitCore/core/nunit.core.dll_VS2005.csproj

index 481579d6ee99b454be3de78f7a5894d622cdb190..ac1601ba5f2457b5864addfd98802e5c0e53085e 100644 (file)
@@ -8,6 +8,7 @@ using System;
 using System.IO;\r
 using System.Collections;\r
 using System.Text;\r
+using System.Threading;\r
 using System.Configuration;\r
 using System.Diagnostics;\r
 using System.Security.Policy;\r
@@ -121,27 +122,56 @@ namespace NUnit.Util
 \r
                public void Unload( AppDomain domain )\r
                {\r
-                       bool shadowCopy = domain.ShadowCopyFiles;\r
-                       string cachePath = domain.SetupInformation.CachePath;\r
-                       string domainName = domain.FriendlyName;\r
-\r
-            try\r
-            {\r
-                AppDomain.Unload(domain);\r
-            }\r
-            catch (Exception ex)\r
-            {\r
-                // We assume that the tests did something bad and just leave\r
-                // the orphaned AppDomain "out there". \r
-                // TODO: Something useful.\r
-                Trace.WriteLine("Unable to unload AppDomain {0}", domainName);\r
-                Trace.WriteLine(ex.ToString());\r
-            }\r
-            finally\r
-            {\r
-                if (shadowCopy)\r
-                    DeleteCacheDir(new DirectoryInfo(cachePath));\r
-            }\r
+                       new DomainUnloader(domain).Unload();\r
+               }\r
+               #endregion\r
+\r
+               #region Nested DomainUnloader Class\r
+               class DomainUnloader\r
+               {\r
+                       private Thread thread;\r
+                       private AppDomain domain;\r
+\r
+                       public DomainUnloader(AppDomain domain)\r
+                       {\r
+                               this.domain = domain;\r
+                       }\r
+\r
+                       public void Unload()\r
+                       {\r
+                               thread = new Thread(new ThreadStart(UnloadOnThread));\r
+                               thread.Start();\r
+                               if (!thread.Join(20000))\r
+                               {\r
+                                       Trace.WriteLine("Unable to unload AppDomain {0}", domain.FriendlyName);\r
+                                       Trace.WriteLine("Unload thread timed out");\r
+                               }\r
+                       }\r
+\r
+                       private void UnloadOnThread()\r
+                       {\r
+                               bool shadowCopy = domain.ShadowCopyFiles;\r
+                               string cachePath = domain.SetupInformation.CachePath;\r
+                               string domainName = domain.FriendlyName;\r
+\r
+               try\r
+                   {\r
+                       AppDomain.Unload(domain);\r
+               }\r
+                   catch (Exception ex)\r
+               {\r
+                       // We assume that the tests did something bad and just leave\r
+                   // the orphaned AppDomain "out there". \r
+                       // TODO: Something useful.\r
+                       Trace.WriteLine("Unable to unload AppDomain {0}", domainName);\r
+                   Trace.WriteLine(ex.ToString());\r
+                   }\r
+               finally\r
+                   {\r
+                   if (shadowCopy)\r
+                           DeleteCacheDir(new DirectoryInfo(cachePath));\r
+               }\r
+                       }\r
                }\r
                #endregion\r
 \r
@@ -179,7 +209,7 @@ namespace NUnit.Util
                /// TODO: This entire method is problematic. Should we be doing it?\r
                /// </summary>\r
                /// <param name="cacheDir"></param>\r
-               private void DeleteCacheDir( DirectoryInfo cacheDir )\r
+               private static void DeleteCacheDir( DirectoryInfo cacheDir )\r
                {\r
                        //                      Debug.WriteLine( "Modules:");\r
                        //                      foreach( ProcessModule module in Process.GetCurrentProcess().Modules )\r
index 5671627c7fec8fe5e85bb7dc0902b39a772c230f..b089852ea8794d45e63a6927074a468114b544b1 100644 (file)
@@ -51,5 +51,6 @@
 /TestSuite.cs -crlf
 /TestSuiteBuilder.cs -crlf
 /TextCapture.cs -crlf
+/ThreadUtility.cs -crlf
 /ThreadedTestRunner.cs -crlf
 /nunit.core.build -crlf
index 6c4ebfa4319b6db452a57919e96e422d0ad06523..26f46b5b98fe3df20a88e9a4be24f0537541ad98 100644 (file)
@@ -120,11 +120,7 @@ namespace NUnit.Core
 \r
                public void Cancel()\r
                {\r
-                       this.thread.Abort(); // Request abort first\r
-\r
-                       // Wake up the thread if necessary\r
-                       if ( ( this.thread.ThreadState & ThreadState.WaitSleepJoin ) != 0 )\r
-                               this.thread.Interrupt();\r
+                       ThreadUtility.Kill(this.thread);\r
                }\r
 \r
                public void StartRun( EventListener listener )\r
diff --git a/mcs/nunit24/NUnitCore/core/ThreadUtility.cs b/mcs/nunit24/NUnitCore/core/ThreadUtility.cs
new file mode 100644 (file)
index 0000000..f0662f0
--- /dev/null
@@ -0,0 +1,52 @@
+// ****************************************************************
+// Copyright 2007, Charlie Poole
+// This is free software licensed under the NUnit license. You may
+// obtain a copy of the license at http://nunit.org.
+// ****************************************************************
+
+using System;
+using System.Threading;
+
+namespace NUnit.Core
+{
+    public class ThreadUtility
+    {
+        /// <summary>
+        /// Do our best to Kill a thread
+        /// </summary>
+        /// <param name="thread">The thread to kill</param>
+        public static void Kill(Thread thread)
+        {
+            Kill(thread, null);
+        }
+
+        /// <summary>
+        /// Do our best to kill a thread, passing state info
+        /// </summary>
+        /// <param name="thread">The thread to kill</param>
+        /// <param name="stateInfo">Info for the ThreadAbortException handler</param>
+        public static void Kill(Thread thread, object stateInfo)
+        {
+            try
+            {
+                if (stateInfo == null)
+                    thread.Abort();
+                else
+                    thread.Abort(stateInfo);
+            }
+            catch (ThreadStateException)
+            {
+                // This is deprecated but still needed in this case
+                // in order to kill the thread. The warning can't
+                // be disabled because the #pragma directive is not
+                // recognized by the .NET 1.1 compiler.
+                thread.Resume();
+            }
+
+            if ( (thread.ThreadState & ThreadState.WaitSleepJoin) != 0 )
+                thread.Interrupt();
+        }
+
+        private ThreadUtility() { }
+    }
+}
index 1565628e88f250c7ff51c8571b908f2d7a42614b..49712e32fd825a536a6f5806a26e0b0e4fa70e53 100644 (file)
@@ -56,6 +56,7 @@
         <include name="TestSuite.cs"/>\r
         <include name="TestSuiteBuilder.cs"/>\r
         <include name="TextCapture.cs"/>\r
+        <include name="ThreadUtility.cs"/>\r
         <include name="ThreadedTestRunner.cs"/>\r
         <include name="Builders/AbstractFixtureBuilder.cs"/>\r
         <include name="Builders/AbstractTestCaseBuilder.cs"/>\r
@@ -86,4 +87,4 @@
     </copy>\r
   </target>\r
 \r
-</project>
\ No newline at end of file
+</project>\r
index 8b5adaac357ddfb27dd70cf3377cc7c466f1f4d0..8502368a78ab6ebceef866c901f50bff31a7864d 100644 (file)
                     SubType = "Code"\r
                     BuildAction = "Compile"\r
                 />\r
+                <File\r
+                    RelPath = "ThreadUtility.cs"\r
+                    SubType = "Code"\r
+                    BuildAction = "Compile"\r
+                />\r
                 <File\r
                     RelPath = "ThreadedTestRunner.cs"\r
                     SubType = "Code"\r
index d5389b72b6ebaf027ae197f9da96a34829d33dfa..0efe3c0fd64e6e0462604acae3a2986b8aad444f 100644 (file)
@@ -61,4 +61,5 @@ TestRunnerThread.cs
 TestSuite.cs
 TestSuiteBuilder.cs
 TextCapture.cs
+ThreadUtility.cs
 ThreadedTestRunner.cs
index eee7a8c3e1852fe07594aa65c637117ae6905d6c..00e25771939c690585b0eb11c255fac31d695413 100644 (file)
       <SubType>Code</SubType>\r
     </Compile>\r
     <Compile Include="TextCapture.cs" />\r
+    <Compile Include="ThreadUtility.cs" />\r
     <Compile Include="ThreadedTestRunner.cs" />\r
     <Compile Include="Builders\AbstractFixtureBuilder.cs">\r
       <SubType>Code</SubType>\r
     <PostBuildEvent>\r
     </PostBuildEvent>\r
   </PropertyGroup>\r
-</Project>
\ No newline at end of file
+</Project>\r