From f1b7be2f5757253147561c2d2439a4649d8e72cb Mon Sep 17 00:00:00 2001 From: Rolf Bjarne Kvinge Date: Tue, 6 Oct 2015 13:47:37 +0200 Subject: [PATCH] Remove Thread.[Abort|Suspend|Resume] from TvOS/WatchOS. In tests replace usages of Thread.Abort with Thread.Interrupt when it looks like it can work, otherwise just disable the complete test. --- external/referencesource | 2 +- mcs/build/profiles/monotouch_tv.make | 3 + mcs/build/profiles/monotouch_watch.make | 3 + mcs/class/System.Web.Services/Makefile | 8 ++ .../SocketResponder.cs | 4 + mcs/class/System/Makefile | 10 +++ .../Test/System.Net/HttpListener2Test.cs | 4 + .../Test/System.Net/HttpWebRequestTest.cs | 4 + .../System/Test/System.Net/SocketResponder.cs | 4 + mcs/class/corlib/Makefile | 12 ++- .../RemotingServices.cs | 4 + mcs/class/corlib/System.Threading/Thread.cs | 2 + .../Test/System.Diagnostics/StackTraceTest.cs | 2 + .../Test/System.Reflection/MethodInfoTest.cs | 2 + .../corlib/Test/System.Threading/MutexTest.cs | 9 ++ .../corlib/Test/System.Threading/ThreadCas.cs | 8 +- .../Test/System.Threading/ThreadTest.cs | 89 ++++++++++++++++++- mcs/mcs/eval.cs | 12 ++- 18 files changed, 177 insertions(+), 5 deletions(-) diff --git a/external/referencesource b/external/referencesource index 8c73c45821d..ceb05825680 160000 --- a/external/referencesource +++ b/external/referencesource @@ -1 +1 @@ -Subproject commit 8c73c45821dfbaf20fb303db1a73f8de96c0a515 +Subproject commit ceb0582568062b7d96f3d98b65453a903fdfa6d2 diff --git a/mcs/build/profiles/monotouch_tv.make b/mcs/build/profiles/monotouch_tv.make index b546e50c167..084af615caa 100644 --- a/mcs/build/profiles/monotouch_tv.make +++ b/mcs/build/profiles/monotouch_tv.make @@ -2,3 +2,6 @@ include $(topdir)/build/profiles/monotouch.make PROFILE_MCS_FLAGS += \ -d:MONOTOUCH_TV + +NO_THREAD_ABORT=1 +NO_THREAD_SUSPEND_RESUME=1 diff --git a/mcs/build/profiles/monotouch_watch.make b/mcs/build/profiles/monotouch_watch.make index eb2880175ad..9a68dcf9eb5 100644 --- a/mcs/build/profiles/monotouch_watch.make +++ b/mcs/build/profiles/monotouch_watch.make @@ -2,3 +2,6 @@ include $(topdir)/build/profiles/monotouch.make PROFILE_MCS_FLAGS += \ -d:MONOTOUCH_WATCH + +NO_THREAD_ABORT=1 +NO_THREAD_SUSPEND_RESUME=1 diff --git a/mcs/class/System.Web.Services/Makefile b/mcs/class/System.Web.Services/Makefile index 235ddbed880..c189f7963eb 100644 --- a/mcs/class/System.Web.Services/Makefile +++ b/mcs/class/System.Web.Services/Makefile @@ -46,6 +46,14 @@ endif TEST_MCS_FLAGS = $(LIB_MCS_FLAGS) -nowarn:618 +ifndef NO_THREAD_ABORT +TEST_MCS_FLAGS += -d:MONO_FEATURE_THREAD_ABORT +endif + +ifndef NO_THREAD_SUSPEND_RESUME +TEST_MCS_FLAGS += -d:MONO_FEATURE_THREAD_SUSPEND_RESUME +endif + EXTRA_DISTFILES = \ System.Web.Services.Description/web-reference.xsd \ System.Web.Services.Description/wsdl-1.1.xsd \ diff --git a/mcs/class/System.Web.Services/Test/System.Web.Services.Protocols/SocketResponder.cs b/mcs/class/System.Web.Services/Test/System.Web.Services.Protocols/SocketResponder.cs index 0682fa90814..2ebe7cf7b8e 100644 --- a/mcs/class/System.Web.Services/Test/System.Web.Services.Protocols/SocketResponder.cs +++ b/mcs/class/System.Web.Services/Test/System.Web.Services.Protocols/SocketResponder.cs @@ -96,7 +96,11 @@ namespace MonoTests.System.Web.Services.Protocols if (tcpListener != null) { tcpListener.Stop (); tcpListener = null; +#if MONO_FEATURE_THREAD_ABORT listenThread.Abort (); +#else + listenThread.Interrupt (); +#endif listenThread.Join (); listenThread = null; } diff --git a/mcs/class/System/Makefile b/mcs/class/System/Makefile index 912ae83bd9d..aef9e5f2b46 100644 --- a/mcs/class/System/Makefile +++ b/mcs/class/System/Makefile @@ -26,6 +26,16 @@ REFERENCE_SOURCES_FLAGS = -d:FEATURE_PAL,SYSTEM_NAMESPACE,MONO,PLATFORM_UNIX LIB_MCS_FLAGS = -nowarn:618 -d:CONFIGURATION_2_0 $(REFERENCE_SOURCES_FLAGS) -unsafe $(RESOURCE_FILES:%=-resource:%) TEST_MCS_FLAGS += -r:System.Configuration +ifndef NO_THREAD_ABORT +REFERENCE_SOURCES_FLAGS += -d:MONO_FEATURE_THREAD_ABORT +TEST_MCS_FLAGS += -d:MONO_FEATURE_THREAD_ABORT +endif + +ifndef NO_THREAD_SUSPEND_RESUME +REFERENCE_SOURCES_FLAGS += -d:MONO_FEATURE_THREAD_SUSPEND_RESUME +TEST_MCS_FLAGS += -d:MONO_FEATURE_THREAD_SUSPEND_RESUME +endif + RESOURCE_STRINGS = ../../../external/referencesource/System/System.txt # diff --git a/mcs/class/System/Test/System.Net/HttpListener2Test.cs b/mcs/class/System/Test/System.Net/HttpListener2Test.cs index ab2901624e4..6e459b9d078 100644 --- a/mcs/class/System/Test/System.Net/HttpListener2Test.cs +++ b/mcs/class/System/Test/System.Net/HttpListener2Test.cs @@ -341,7 +341,11 @@ namespace MonoTests.System.Net { Thread thread = new Thread (ReadToEnd); thread.Start (); if (test_evt.WaitOne (3000, false) == false) { +#if MONO_FEATURE_THREAD_ABORT thread.Abort (); +#else + thread.Interrupt (); +#endif test_evt.Close (); Assert.IsTrue (false, "Timed out"); } diff --git a/mcs/class/System/Test/System.Net/HttpWebRequestTest.cs b/mcs/class/System/Test/System.Net/HttpWebRequestTest.cs index a44034f2675..20ee8020a98 100644 --- a/mcs/class/System/Test/System.Net/HttpWebRequestTest.cs +++ b/mcs/class/System/Test/System.Net/HttpWebRequestTest.cs @@ -1468,7 +1468,11 @@ namespace MonoTests.System.Net Thread.Sleep (three_seconds_in_milliseconds * 3); if (timeoutWorker.End == null) { +#if MONO_FEATURE_THREAD_ABORT thread.Abort (); +#else + thread.Interrupt (); +#endif Assert.Fail ("Thread finished after triple the timeout specified has passed"); } diff --git a/mcs/class/System/Test/System.Net/SocketResponder.cs b/mcs/class/System/Test/System.Net/SocketResponder.cs index 98035f55db7..daa183afa06 100644 --- a/mcs/class/System/Test/System.Net/SocketResponder.cs +++ b/mcs/class/System/Test/System.Net/SocketResponder.cs @@ -105,7 +105,11 @@ namespace MonoTests.System.Net tcpListener = null; if (listenSocket != null) listenSocket.Close (); +#if MONO_FEATURE_THREAD_ABORT listenThread.Abort (); +#else + listenThread.Interrupt (); +#endif listenThread.Join (); listenThread = null; Thread.Sleep (50); diff --git a/mcs/class/corlib/Makefile b/mcs/class/corlib/Makefile index 89222691f7e..1162bf54f78 100644 --- a/mcs/class/corlib/Makefile +++ b/mcs/class/corlib/Makefile @@ -41,12 +41,22 @@ ifndef MOBILE_STATIC REFERENCE_SOURCES_FLAGS += -d:FEATURE_REMOTING,MONO_COM,FEATURE_COMINTEROP,FEATURE_ROLE_BASED_SECURITY endif +ifndef NO_THREAD_ABORT +REFERENCE_SOURCES_FLAGS += -d:MONO_FEATURE_THREAD_ABORT +TEST_MCS_FLAGS += -d:MONO_FEATURE_THREAD_ABORT +endif + +ifndef NO_THREAD_SUSPEND_RESUME +REFERENCE_SOURCES_FLAGS += -d:MONO_FEATURE_THREAD_SUSPEND_RESUME +TEST_MCS_FLAGS += -d:MONO_FEATURE_THREAD_SUSPEND_RESUME +endif + WARNING_ABOUT_DISABLED_WARNING=1635 LOCAL_MCS_FLAGS = -unsafe -nostdlib -nowarn:612,618,$(WARNING_ABOUT_DISABLED_WARNING) -d:INSIDE_CORLIB,MONO_CULTURE_DATA -d:LIBC $(REFERENCE_SOURCES_FLAGS) DEFAULT_REFERENCES = # System.IO/DirectoryInfoTest.cs needs Mono.Posix -TEST_MCS_FLAGS = -debug -nowarn:168,219,618,672 -unsafe -r:Mono.Posix.dll -r:System.Core.dll \ +TEST_MCS_FLAGS += -debug -nowarn:168,219,618,672 -unsafe -r:Mono.Posix.dll -r:System.Core.dll \ -define:MONO_DATACONVERTER_STATIC_METHODS $(TEST_RESX_RESOURCES:%=-resource:%) EXTRA_DISTFILES = \ diff --git a/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs b/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs index c0015138cd3..bc424ce5e2d 100644 --- a/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs +++ b/mcs/class/corlib/System.Runtime.Remoting/RemotingServices.cs @@ -819,7 +819,9 @@ namespace System.Runtime.Remoting } catch (Exception e) { if (e is ThreadAbortException) { +#if MONO_FEATURE_THREAD_ABORT Thread.ResetAbort (); +#endif retry = 5; ex = e; } @@ -840,7 +842,9 @@ namespace System.Runtime.Remoting catch (Exception tex) { byte[] data = SerializeExceptionData (tex); +#if MONO_FEATURE_THREAD_ABORT Thread.ResetAbort (); +#endif return data; } } diff --git a/mcs/class/corlib/System.Threading/Thread.cs b/mcs/class/corlib/System.Threading/Thread.cs index 23d6bb7286b..a2e3f5b685d 100644 --- a/mcs/class/corlib/System.Threading/Thread.cs +++ b/mcs/class/corlib/System.Threading/Thread.cs @@ -461,6 +461,7 @@ namespace System.Threading { } } +#if MONO_FEATURE_THREAD_ABORT [MethodImplAttribute(MethodImplOptions.InternalCall)] private extern static void Abort_internal (InternalThread thread, object stateInfo); @@ -488,6 +489,7 @@ namespace System.Threading { void ClearAbortReason () { } +#endif // MONO_FEATURE_THREAD_ABORT [MethodImplAttribute (MethodImplOptions.InternalCall)] private extern static void SpinWait_nop (); diff --git a/mcs/class/corlib/Test/System.Diagnostics/StackTraceTest.cs b/mcs/class/corlib/Test/System.Diagnostics/StackTraceTest.cs index f2665988d52..4aa89c03720 100644 --- a/mcs/class/corlib/Test/System.Diagnostics/StackTraceTest.cs +++ b/mcs/class/corlib/Test/System.Diagnostics/StackTraceTest.cs @@ -142,6 +142,7 @@ namespace MonoTests.System.Diagnostics { new StackTrace (t, true); } +#if MONO_FEATURE_THREAD_SUSPEND_RESUME [Test] [Ignore ("Not supported in Mono")] public void StackTrace_Thread_Suspended () @@ -151,6 +152,7 @@ namespace MonoTests.System.Diagnostics { t.Suspend (); new StackTrace (t, true); } +#endif [Test] public void FrameCount () diff --git a/mcs/class/corlib/Test/System.Reflection/MethodInfoTest.cs b/mcs/class/corlib/Test/System.Reflection/MethodInfoTest.cs index 3c6e3da2ffb..b8a9de2b3c5 100644 --- a/mcs/class/corlib/Test/System.Reflection/MethodInfoTest.cs +++ b/mcs/class/corlib/Test/System.Reflection/MethodInfoTest.cs @@ -205,6 +205,7 @@ namespace MonoTests.System.Reflection return (int*) 0; } +#if MONO_FEATURE_THREAD_ABORT [Test] // bug #81538 public void InvokeThreadAbort () { @@ -223,6 +224,7 @@ namespace MonoTests.System.Reflection { Thread.CurrentThread.Abort (); } +#endif [Test] // bug #76541 public void ToStringByRef () diff --git a/mcs/class/corlib/Test/System.Threading/MutexTest.cs b/mcs/class/corlib/Test/System.Threading/MutexTest.cs index a4669029b88..5149ece6900 100644 --- a/mcs/class/corlib/Test/System.Threading/MutexTest.cs +++ b/mcs/class/corlib/Test/System.Threading/MutexTest.cs @@ -128,7 +128,11 @@ namespace MonoTests.System.Threading TestUtil.WaitForNotAlive (thread1, ""); Assert.AreEqual (100, class1.marker); } finally { +#if MONO_FEATURE_THREAD_ABORT thread1.Abort (); +#else + thread1.Interrupt (); +#endif } } @@ -150,8 +154,13 @@ namespace MonoTests.System.Threading Assert.AreEqual (class2.id, class2.marker); } finally { +#if MONO_FEATURE_THREAD_ABORT thread1.Abort (); thread2.Abort (); +#else + thread1.Interrupt (); + thread2.Interrupt (); +#endif } } diff --git a/mcs/class/corlib/Test/System.Threading/ThreadCas.cs b/mcs/class/corlib/Test/System.Threading/ThreadCas.cs index 57c1ca4dea4..b222d5bcab1 100644 --- a/mcs/class/corlib/Test/System.Threading/ThreadCas.cs +++ b/mcs/class/corlib/Test/System.Threading/ThreadCas.cs @@ -69,6 +69,7 @@ namespace MonoCasTests.System.Threading { // test Demand by denying the caller of the required privileges +#if MONO_FEATURE_THREAD_ABORT [Test] [SecurityPermission (SecurityAction.Deny, ControlThread = true)] [ExpectedException (typeof (SecurityException))] @@ -84,7 +85,8 @@ namespace MonoCasTests.System.Threading { { Thread.CurrentThread.Abort (new object [0]); } - +#endif + [Test] [SecurityPermission (SecurityAction.Deny, ControlThread = true)] [ExpectedException (typeof (SecurityException))] @@ -101,6 +103,7 @@ namespace MonoCasTests.System.Threading { Thread.CurrentThread.Interrupt (); } +#if MONO_FEATURE_THREAD_ABORT [Test] [SecurityPermission (SecurityAction.Deny, ControlThread = true)] [ExpectedException (typeof (SecurityException))] @@ -108,7 +111,9 @@ namespace MonoCasTests.System.Threading { { Thread.ResetAbort (); } +#endif +#if MONO_FEATURE_THREAD_SUSPEND_RESUME [Test] [SecurityPermission (SecurityAction.Deny, ControlThread = true)] [ExpectedException (typeof (SecurityException))] @@ -124,6 +129,7 @@ namespace MonoCasTests.System.Threading { { Thread.CurrentThread.Suspend (); } +#endif // we use reflection to call Mutex as it's named constructors are protected by // a LinkDemand (which will be converted into full demand, i.e. a stack walk) diff --git a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs index 39b303f4736..b49fba552fa 100644 --- a/mcs/class/corlib/Test/System.Threading/ThreadTest.cs +++ b/mcs/class/corlib/Test/System.Threading/ThreadTest.cs @@ -184,7 +184,11 @@ namespace MonoTests.System.Threading { sub_thread.Start(); Thread.Sleep (100); +#if MONO_FEATURE_THREAD_ABORT sub_thread.Abort(); +#else + sub_thread.Interrupt (); +#endif } } @@ -215,10 +219,18 @@ namespace MonoTests.System.Threading thread2.Start(); TestUtil.WaitForAlive (thread2, "wait2"); T2ON = true; +#if MONO_FEATURE_THREAD_ABORT thread1.Abort(); +#else + thread1.Interrupt (); +#endif TestUtil.WaitForNotAlive (thread1, "wait3"); T1ON = false; +#if MONO_FEATURE_THREAD_ABORT thread2.Abort(); +#else + thread2.Interrupt (); +#endif TestUtil.WaitForNotAlive (thread2, "wait4"); T2ON = false; } @@ -328,7 +340,11 @@ namespace MonoTests.System.Threading C2Test test1 = new C2Test(); Thread TestThread = new Thread(new ThreadStart(test1.TestMethod)); TestThread.Start(); +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif try { TestThread.Start(); Assert.Fail ("#2"); @@ -343,7 +359,11 @@ namespace MonoTests.System.Threading } bool started = (TestThread.ThreadState == ThreadState.Running); Assert.AreEqual (started, test1.run, "#15 Thread Is not in the correct state: "); +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } } @@ -359,7 +379,11 @@ namespace MonoTests.System.Threading TestThread.Start(); TestUtil.WaitForAlive (TestThread, "wait5"); Assert.AreEqual (ApartmentState.MTA, TestThread.ApartmentState, "#2"); +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } [Test] @@ -378,10 +402,15 @@ namespace MonoTests.System.Threading ThreadPriority before = TestThread.Priority; Assert.AreEqual (before, after, "#41 Unexpected Priority Change: "); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } } +#if MONO_FEATURE_THREAD_ABORT [Test] [Category ("NotDotNet")] // on MS, Thread is still in AbortRequested state when Start is invoked public void AbortUnstarted () @@ -391,6 +420,7 @@ namespace MonoTests.System.Threading th.Abort (); th.Start (); } +#endif [Test] [Category ("NotDotNet")] // on MS, ThreadState is immediately Stopped after Abort @@ -405,7 +435,11 @@ namespace MonoTests.System.Threading TestUtil.WaitForAliveOrStop (TestThread, "wait8"); Assert.AreEqual (ThreadPriority.Normal, TestThread.Priority, "#43 Incorrect Priority in Started thread: "); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } Assert.AreEqual (ThreadPriority.Normal, TestThread.Priority, "#44 Incorrect Priority in Aborted thread: "); } @@ -430,7 +464,11 @@ namespace MonoTests.System.Threading Assert.AreEqual (ThreadPriority.Highest, TestThread.Priority, "#45E Incorrect Priority:"); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } } @@ -458,7 +496,11 @@ namespace MonoTests.System.Threading bool state = TestThread.IsBackground; Assert.IsFalse (state, "#51 IsBackground not set at the default state: "); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } } @@ -471,7 +513,11 @@ namespace MonoTests.System.Threading try { TestThread.Start(); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } if (TestThread.IsAlive) { @@ -500,7 +546,11 @@ namespace MonoTests.System.Threading TestThread.Name = newname; Assert.AreEqual (newname, TestThread.Name, "#62 Name not set when must be set: "); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } } @@ -562,7 +612,11 @@ namespace MonoTests.System.Threading TestThread.Start(); TestUtil.WaitForAlive (TestThread, "wait11"); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } } @@ -574,7 +628,11 @@ namespace MonoTests.System.Threading try { TestThread.Start(); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } } @@ -590,8 +648,13 @@ namespace MonoTests.System.Threading thread2.Start(); thread2.Join(); } finally { +#if MONO_FEATURE_THREAD_ABORT thread1.Abort(); thread2.Abort(); +#else + thread1.Interrupt (); + thread2.Interrupt (); +#endif } } @@ -676,7 +739,11 @@ namespace MonoTests.System.Threading Assert.IsTrue (TestThread.ThreadState == ThreadState.Running || (TestThread.ThreadState & ThreadState.Unstarted) != 0, "#102 Wrong Thread State: " + TestThread.ThreadState.ToString ()); } finally { +#if MONO_FEATURE_THREAD_ABORT TestThread.Abort(); +#else + TestThread.Interrupt (); +#endif } TestUtil.WaitForNotAlive (TestThread, "wait12"); @@ -696,7 +763,11 @@ namespace MonoTests.System.Threading t.Start (); t.Join (); } catch { +#if MONO_FEATURE_THREAD_ABORT t.Abort (); +#else + t.Interrupt (); +#endif } } @@ -711,7 +782,11 @@ namespace MonoTests.System.Threading t.Start (); t.Join (); } catch { +#if MONO_FEATURE_THREAD_ABORT t.Abort (); +#else + t.Interrupt (); +#endif } } @@ -725,7 +800,11 @@ namespace MonoTests.System.Threading t.Start (); t.Join (); } catch { +#if MONO_FEATURE_THREAD_ABORT t.Abort (); +#else + t.Interrupt (); +#endif } } @@ -739,12 +818,17 @@ namespace MonoTests.System.Threading t.Start (); t.Join (); } catch { +#if MONO_FEATURE_THREAD_ABORT t.Abort (); +#else + t.Interrupt (); +#endif } } int counter = 0; +#if MONO_FEATURE_THREAD_SUSPEND_RESUME [Test] public void TestSuspend () { @@ -768,7 +852,9 @@ namespace MonoTests.System.Threading TestUtil.WaitForNotAlive (t, "wait13"); CheckIsNotRunning ("t6", t); } - +#endif + +#if MONO_FEATURE_THREAD_SUSPEND_RESUME && MONO_FEATURE_THREAD_ABORT [Test] [Category("NotDotNet")] // On MS, ThreadStateException is thrown on Abort: "Thread is suspended; attempting to abort" public void TestSuspendAbort () @@ -799,6 +885,7 @@ namespace MonoTests.System.Threading CheckIsNotRunning ("t6", t); } +#endif [Test] public void Test_Interrupt () diff --git a/mcs/mcs/eval.cs b/mcs/mcs/eval.cs index 50f15489e3a..62c02b1fd56 100644 --- a/mcs/mcs/eval.cs +++ b/mcs/mcs/eval.cs @@ -192,8 +192,13 @@ namespace Mono.CSharp if (!inited || !invoking) return; - if (invoke_thread != null) + if (invoke_thread != null) { +#if MONO_FEATURE_THREAD_ABORT invoke_thread.Abort (); +#else + invoke_thread.Interrupt (); +#endif + } } /// @@ -367,9 +372,14 @@ namespace Mono.CSharp invoke_thread = System.Threading.Thread.CurrentThread; invoking = true; compiled (ref retval); +#if MONO_FEATURE_THREAD_ABORT } catch (ThreadAbortException e){ Thread.ResetAbort (); Console.WriteLine ("Interrupted!\n{0}", e); +#else + } catch (ThreadInterruptedException e) { + Console.WriteLine ("Interrupted!\n{0}", e); +#endif } finally { invoking = false; -- 2.25.1