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