Browse Source

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
shortcuts
David Srbecký 18 years ago
parent
commit
10c2f3348e
  1. 19
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs
  2. 45
      src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs
  3. 1
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj
  4. 142
      src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/MainThreadExit.cs

19
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Process-StateControl.cs

@ -238,11 +238,24 @@ namespace Debugger
this.NotifyHasExpired(); this.NotifyHasExpired();
} }
internal void SelectMostRecentStackFrameWithLoadedSymbols() void SelectSomeThread()
{ {
if (this.SelectedThread == null && this.Threads.Count > 0) { if (this.SelectedThread != null && !this.SelectedThread.IsInValidState) {
this.SelectedThread = this.Threads[0]; 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) { if (this.SelectedThread != null) {
this.SelectedThread.SelectedStackFrame = this.SelectedThread.MostRecentStackFrameWithLoadedSymbols; this.SelectedThread.SelectedStackFrame = this.SelectedThread.MostRecentStackFrameWithLoadedSymbols;
} }

45
src/AddIns/Misc/Debugger/Debugger.Core/Project/Src/Control/Thread.cs

@ -72,9 +72,34 @@ namespace Debugger
} }
} }
/// <summary> If the thread is not at safe point, it is not posible to evaluate
/// on it </summary>
/// <remarks> Returns false is the thread is in invalid state </remarks>
public bool IsAtSafePoint { public bool IsAtSafePoint {
get { get {
return CorThread.UserState != CorDebugUserState.USER_UNSAFE_POINT; if (IsInValidState) {
return CorThread.UserState != CorDebugUserState.USER_UNSAFE_POINT;
} else {
return false;
}
}
}
/// <summary>
/// From time to time the thread may be in invalid state.
/// </summary>
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 { public Value RuntimeValue {
get { get {
// TODO: It may have started - rework
if (!HasBeenLoaded) throw new DebuggerException("Thread has not started jet"); if (!HasBeenLoaded) throw new DebuggerException("Thread has not started jet");
process.AssertPaused(); process.AssertPaused();
@ -255,12 +281,11 @@ namespace Debugger
public override string ToString() 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);
} }
/// <summary> /// <summary> Gets the whole callstack of the Thread. </summary>
/// Gets the whole callstack of the Thread. /// <remarks> If the thread is in invalid state returns empty array </remarks>
/// </summary>
public StackFrame[] GetCallstack() public StackFrame[] GetCallstack()
{ {
return new List<StackFrame>(CallstackEnum).ToArray(); return new List<StackFrame>(CallstackEnum).ToArray();
@ -281,6 +306,10 @@ namespace Debugger
get { get {
process.AssertPaused(); process.AssertPaused();
if (!IsInValidState) {
yield break;
}
int depth = 0; int depth = 0;
foreach(ICorDebugChain corChain in CorThread.EnumerateChains().Enumerator) { foreach(ICorDebugChain corChain in CorThread.EnumerateChains().Enumerator) {
if (corChain.IsManaged == 0) continue; // Only managed ones if (corChain.IsManaged == 0) continue; // Only managed ones
@ -380,7 +409,11 @@ namespace Debugger
public bool IsMostRecentStackFrameNative { public bool IsMostRecentStackFrameNative {
get { get {
process.AssertPaused(); process.AssertPaused();
return corThread.ActiveChain.IsManaged == 0; if (this.IsInValidState) {
return corThread.ActiveChain.IsManaged == 0;
} else {
return false;
}
} }
} }
} }

1
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Debugger.Tests.csproj

@ -58,6 +58,7 @@
<Compile Include="Src\TestPrograms\GenericDictionary.cs" /> <Compile Include="Src\TestPrograms\GenericDictionary.cs" />
<Compile Include="Src\TestPrograms\Generics.cs" /> <Compile Include="Src\TestPrograms\Generics.cs" />
<Compile Include="Src\TestPrograms\HelloWorld.cs" /> <Compile Include="Src\TestPrograms\HelloWorld.cs" />
<Compile Include="Src\TestPrograms\MainThreadExit.cs" />
<Compile Include="Src\TestPrograms\MetadataIdentity.cs" /> <Compile Include="Src\TestPrograms\MetadataIdentity.cs" />
<Compile Include="Src\TestPrograms\ObjectValue.cs" /> <Compile Include="Src\TestPrograms\ObjectValue.cs" />
<Compile Include="Src\TestPrograms\PrimitiveValue.cs" /> <Compile Include="Src\TestPrograms\PrimitiveValue.cs" />

142
src/AddIns/Misc/Debugger/Debugger.Tests/Project/Src/TestPrograms/MainThreadExit.cs

@ -0,0 +1,142 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="David Srbecký" email="dsrbecky@gmail.com"/>
// <version>$Revision$</version>
// </file>
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
<?xml version="1.0" encoding="utf-8"?>
<DebuggerTests>
<Test name="MainThreadExit.cs">
<ProcessStarted />
<ModuleLoaded symbols="False">mscorlib.dll</ModuleLoaded>
<ModuleLoaded symbols="True">MainThreadExit.exe</ModuleLoaded>
<DebuggingPaused>Break</DebuggingPaused>
<ThreadsBeforeExit Type="ReadOnlyCollection`1" ToString="System.Collections.ObjectModel.ReadOnlyCollection`1[Debugger.Thread]">
<Count>2</Count>
<Item Type="Thread" ToString="Thread Name = Suspended = False">
<CurrentException>null</CurrentException>
<CurrentExceptionIsUnhandled>False</CurrentExceptionIsUnhandled>
<CurrentExceptionType>0</CurrentExceptionType>
<HasExpired>False</HasExpired>
<IsAtSafePoint>True</IsAtSafePoint>
<IsInValidState>True</IsInValidState>
<IsMostRecentStackFrameNative>False</IsMostRecentStackFrameNative>
<MostRecentStackFrame>Debugger.Tests.TestPrograms.MainThreadExit.Main</MostRecentStackFrame>
<MostRecentStackFrameWithLoadedSymbols>Debugger.Tests.TestPrograms.MainThreadExit.Main</MostRecentStackFrameWithLoadedSymbols>
<Name>
</Name>
<OldestStackFrame>Debugger.Tests.TestPrograms.MainThreadExit.Main</OldestStackFrame>
<Priority>Normal</Priority>
<RuntimeValue exception="Thread has not started jet" />
<SelectedStackFrame>Debugger.Tests.TestPrograms.MainThreadExit.Main</SelectedStackFrame>
<Suspended>False</Suspended>
</Item>
<Item Type="Thread" ToString="Thread Name = Suspended = False">
<CurrentException>null</CurrentException>
<CurrentExceptionIsUnhandled>False</CurrentExceptionIsUnhandled>
<CurrentExceptionType>0</CurrentExceptionType>
<HasExpired>False</HasExpired>
<IsAtSafePoint>False</IsAtSafePoint>
<IsInValidState>True</IsInValidState>
<IsMostRecentStackFrameNative>False</IsMostRecentStackFrameNative>
<MostRecentStackFrame>System.Threading.ThreadHelper.ThreadStart</MostRecentStackFrame>
<MostRecentStackFrameWithLoadedSymbols>null</MostRecentStackFrameWithLoadedSymbols>
<Name>
</Name>
<OldestStackFrame>System.Threading.ThreadHelper.ThreadStart</OldestStackFrame>
<Priority>Normal</Priority>
<RuntimeValue exception="Thread has not started jet" />
<SelectedStackFrame>null</SelectedStackFrame>
<Suspended>False</Suspended>
</Item>
</ThreadsBeforeExit>
<DebuggingPaused>ForcedBreak</DebuggingPaused>
<ThreadsAfterExit Type="ReadOnlyCollection`1" ToString="System.Collections.ObjectModel.ReadOnlyCollection`1[Debugger.Thread]">
<Count>2</Count>
<Item Type="Thread" ToString="Thread Name = Suspended = False">
<CurrentException>null</CurrentException>
<CurrentExceptionIsUnhandled>False</CurrentExceptionIsUnhandled>
<CurrentExceptionType>0</CurrentExceptionType>
<HasExpired>False</HasExpired>
<IsAtSafePoint>False</IsAtSafePoint>
<IsInValidState>False</IsInValidState>
<IsMostRecentStackFrameNative>False</IsMostRecentStackFrameNative>
<MostRecentStackFrame>null</MostRecentStackFrame>
<MostRecentStackFrameWithLoadedSymbols>null</MostRecentStackFrameWithLoadedSymbols>
<Name>
</Name>
<OldestStackFrame>null</OldestStackFrame>
<Priority>Normal</Priority>
<RuntimeValue exception="Thread has not started jet" />
<SelectedStackFrame>null</SelectedStackFrame>
<Suspended>False</Suspended>
</Item>
<Item Type="Thread" ToString="Thread Name = Suspended = False">
<CurrentException>null</CurrentException>
<CurrentExceptionIsUnhandled>False</CurrentExceptionIsUnhandled>
<CurrentExceptionType>0</CurrentExceptionType>
<HasExpired>False</HasExpired>
<IsAtSafePoint>True</IsAtSafePoint>
<IsInValidState>True</IsInValidState>
<IsMostRecentStackFrameNative>False</IsMostRecentStackFrameNative>
<MostRecentStackFrame>System.Threading.WaitHandle.WaitOne</MostRecentStackFrame>
<MostRecentStackFrameWithLoadedSymbols>Debugger.Tests.TestPrograms.MainThreadExit.WaitForALongTime</MostRecentStackFrameWithLoadedSymbols>
<Name>
</Name>
<OldestStackFrame>System.Threading.ThreadHelper.ThreadStart</OldestStackFrame>
<Priority>Normal</Priority>
<RuntimeValue exception="Thread has not started jet" />
<SelectedStackFrame>Debugger.Tests.TestPrograms.MainThreadExit.WaitForALongTime</SelectedStackFrame>
<Suspended>False</Suspended>
</Item>
</ThreadsAfterExit>
<ProcessExited />
</Test>
</DebuggerTests>
#endif // EXPECTED_OUTPUT
Loading…
Cancel
Save