From 10c2f3348e1d678ac4d42cc9e883fcc34ca3bb3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Thu, 19 Jun 2008 17:37:47 +0000 Subject: [PATCH] Fixed SD2-1423: Thread state is invalid exception when breaking into application after main thread finished; Including test git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@3115 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61 --- .../Src/Control/Process-StateControl.cs | 19 ++- .../Project/Src/Control/Thread.cs | 45 +++++- .../Project/Debugger.Tests.csproj | 1 + .../Src/TestPrograms/MainThreadExit.cs | 142 ++++++++++++++++++ 4 files changed, 198 insertions(+), 9 deletions(-) create mode 100644 src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/MainThreadExit.cs diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs index 6d473f8e08..691269cf09 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs @@ -238,11 +238,24 @@ namespace Debugger this.NotifyHasExpired(); } - internal void SelectMostRecentStackFrameWithLoadedSymbols() + void SelectSomeThread() { - if (this.SelectedThread == null && this.Threads.Count > 0) { - this.SelectedThread = this.Threads[0]; + if (this.SelectedThread != null && !this.SelectedThread.IsInValidState) { + this.SelectedThread = null; + } + if (this.SelectedThread == null) { + foreach(Thread thread in this.Threads) { + if (thread.IsInValidState) { + this.SelectedThread = thread; + break; + } + } } + } + + internal void SelectMostRecentStackFrameWithLoadedSymbols() + { + SelectSomeThread(); if (this.SelectedThread != null) { this.SelectedThread.SelectedStackFrame = this.SelectedThread.MostRecentStackFrameWithLoadedSymbols; } diff --git a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs index 8701068746..5a31b39bd2 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs +++ b/src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs @@ -72,9 +72,34 @@ namespace Debugger } } + /// If the thread is not at safe point, it is not posible to evaluate + /// on it + /// Returns false is the thread is in invalid state public bool IsAtSafePoint { get { - return CorThread.UserState != CorDebugUserState.USER_UNSAFE_POINT; + if (IsInValidState) { + return CorThread.UserState != CorDebugUserState.USER_UNSAFE_POINT; + } else { + return false; + } + } + } + + /// + /// From time to time the thread may be in invalid state. + /// + public bool IsInValidState { + get { + try { + CorThread.UserState.ToString(); + return true; + } catch (COMException e) { + // The state of the thread is invalid. + if ((uint)e.ErrorCode == 0x8013132D) { + return false; + } + throw; + } } } @@ -154,6 +179,7 @@ namespace Debugger public Value RuntimeValue { get { + // TODO: It may have started - rework if (!HasBeenLoaded) throw new DebuggerException("Thread has not started jet"); process.AssertPaused(); @@ -255,12 +281,11 @@ namespace Debugger public override string ToString() { - return String.Format("ID = {0,-10} Name = {1,-20} Suspended = {2,-8}", ID, Name, Suspended); + return String.Format("Thread Name = {1} Suspended = {2}", ID, Name, Suspended); } - /// - /// Gets the whole callstack of the Thread. - /// + /// Gets the whole callstack of the Thread. + /// If the thread is in invalid state returns empty array public StackFrame[] GetCallstack() { return new List(CallstackEnum).ToArray(); @@ -281,6 +306,10 @@ namespace Debugger get { process.AssertPaused(); + if (!IsInValidState) { + yield break; + } + int depth = 0; foreach(ICorDebugChain corChain in CorThread.EnumerateChains().Enumerator) { if (corChain.IsManaged == 0) continue; // Only managed ones @@ -380,7 +409,11 @@ namespace Debugger public bool IsMostRecentStackFrameNative { get { process.AssertPaused(); - return corThread.ActiveChain.IsManaged == 0; + if (this.IsInValidState) { + return corThread.ActiveChain.IsManaged == 0; + } else { + return false; + } } } } diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj index 235b8967d2..e68ed363dc 100644 --- a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj @@ -58,6 +58,7 @@ + diff --git a/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/MainThreadExit.cs b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/MainThreadExit.cs new file mode 100644 index 0000000000..e3030afce0 --- /dev/null +++ b/src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/MainThreadExit.cs @@ -0,0 +1,142 @@ +// +// +// +// +// $Revision$ +// + +using System; +using System.Threading; + +namespace Debugger.Tests.TestPrograms +{ + public class MainThreadExit + { + static ManualResetEvent doSomething = new ManualResetEvent(false); + + public static void Main() + { + System.Threading.Thread t = new System.Threading.Thread(WaitForALongTime); + t.Name = "Worker thread"; + t.Start(); + System.Diagnostics.Debugger.Break(); + } + + static void WaitForALongTime() + { + doSomething.WaitOne(); + } + } +} + +#if TEST_CODE +namespace Debugger.Tests { + public partial class DebuggerTests + { + [NUnit.Framework.Test] + public void MainThreadExit() + { + StartTest("MainThreadExit.cs"); + ObjectDump("ThreadsBeforeExit", process.Threads); + process.AsyncContinue(); + System.Threading.Thread.Sleep(250); + process.Break(); + ObjectDump("ThreadsAfterExit", process.Threads); + process.Terminate(); + EndTest(); + } + } +} +#endif + +#if EXPECTED_OUTPUT + + + + + mscorlib.dll + MainThreadExit.exe + Break + + 2 + + null + False + 0 + False + True + True + False + Debugger.Tests.TestPrograms.MainThreadExit.Main + Debugger.Tests.TestPrograms.MainThreadExit.Main + + + Debugger.Tests.TestPrograms.MainThreadExit.Main + Normal + + Debugger.Tests.TestPrograms.MainThreadExit.Main + False + + + null + False + 0 + False + False + True + False + System.Threading.ThreadHelper.ThreadStart + null + + + System.Threading.ThreadHelper.ThreadStart + Normal + + null + False + + + ForcedBreak + + 2 + + null + False + 0 + False + False + False + False + null + null + + + null + Normal + + null + False + + + null + False + 0 + False + True + True + False + System.Threading.WaitHandle.WaitOne + Debugger.Tests.TestPrograms.MainThreadExit.WaitForALongTime + + + System.Threading.ThreadHelper.ThreadStart + Normal + + Debugger.Tests.TestPrograms.MainThreadExit.WaitForALongTime + False + + + + + +#endif // EXPECTED_OUTPUT \ No newline at end of file