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
\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
/// 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
--- /dev/null
+// ****************************************************************
+// 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() { }
+ }
+}