Skip to content

Commit

Permalink
Remove all kernel32.dll references and debug breakpoints (#108647)
Browse files Browse the repository at this point in the history
* remove all kernel32.dll and debugbreak references

* log exception if run into oom

* remove some comments

* change debugBreakOnTestHang back to true

* throw timeout exception when DebugBreakOnTestHang is false

* throw exception if fail to write message to log file

* set debugBreakOnTestHang to false by default

* write message to log in timeout scenario

* print out debug break when debugBreakOnTestHang is true

* interrupt if debugbreak is presented, otherwise log and throw exception

* add _debugBreakOnTestHang field and MissingTestException class

* implement DebugBreakOrThrowException method

* implement GenerateExceptionMessageAndHandler method
  • Loading branch information
VincentBu authored Nov 5, 2024
1 parent da78cf7 commit 302e0d4
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 96 deletions.
14 changes: 12 additions & 2 deletions src/tests/GC/Stress/Framework/RFLogging.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,8 +79,13 @@ private void LogWorker()
}
catch (IOException e)
{
ReliabilityFramework.MyDebugBreak(String.Format("LogWorker IOException:{0}", e.ToString()));
//Disk may be full so simply stop logging
ExceptionHandler exceptionHandler = ReliabilityFramework.GenerateExceptionMessageAndHandler(ReliabilityFramework._debugBreakOnTestHang, e);
string msg = exceptionHandler.HandleMessage;
Action handler = exceptionHandler.Handler;

Console.WriteLine(msg);
handler();
}
}

Expand Down Expand Up @@ -120,7 +125,12 @@ private void LogWorker()
}
catch (IOException e)
{
ReliabilityFramework.MyDebugBreak(String.Format("LogWorker IOException:{0}", e.ToString()));
ExceptionHandler exceptionHandler = ReliabilityFramework.GenerateExceptionMessageAndHandler(ReliabilityFramework._debugBreakOnTestHang, e);
string msg = exceptionHandler.HandleMessage;
Action handler = exceptionHandler.Handler;

Console.WriteLine(msg);
handler();
}
}
}
Expand Down
163 changes: 76 additions & 87 deletions src/tests/GC/Stress/Framework/ReliabilityFramework.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,29 @@ public interface ISingleReliabilityTest
bool Run(); // returns true on success, false on failure.
}

public sealed class MissingTestException : Exception
{
public MissingTestException()
{
}

public MissingTestException(string message)
: base(message)
{
}

public MissingTestException(string message, Exception inner)
: base(message, inner)
{
}
}

public sealed class ExceptionHandler
{
public string HandleMessage { get; set; }
public Action Handler { get; set; }
}

public class ReliabilityFramework
{
// instance members
Expand All @@ -102,6 +125,7 @@ public class ReliabilityFramework
private static Random s_randNum = new Random(s_seed);
private static string timeValue = null;
private static bool s_fNoExit = false;
internal static bool _debugBreakOnTestHang = false;
// constants
private const string waitingText = "Waiting for all tests to finish loading, Remaining Tests: ";

Expand Down Expand Up @@ -226,6 +250,19 @@ public static int Main(string[] args)
catch (OutOfMemoryException e)
{
rf.HandleOom(e, "Running tests");
throw e;
}
catch (TimeoutException e)
{
throw e;
}
catch (PathTooLongException e)
{
throw e;
}
catch (MissingTestException e)
{
throw e;
}
catch (Exception e)
{
Expand Down Expand Up @@ -271,25 +308,9 @@ public static int Main(string[] args)

public void HandleOom(Exception e, string message)
{
try
{
_logger.WriteToInstrumentationLog(_curTestSet, LoggingLevels.Tests, String.Format("Exception while running tests: {0}", e));
if (_curTestSet.DebugBreakOnOutOfMemory)
{
OomExceptionCausedDebugBreak();
}
}
catch (OutOfMemoryException)
{
// hang and let someone debug if we can't even break in...
Thread.CurrentThread.Join();
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void OomExceptionCausedDebugBreak()
{
MyDebugBreak("Harness");
_logger.WriteToInstrumentationLog(_curTestSet, LoggingLevels.Tests, String.Format("Exception while running tests: {0}", e));
ExceptionHandler exceptionHandler = GenerateExceptionMessageAndHandler(_curTestSet.DebugBreakOnOutOfMemory, e);
DebugBreakOrThrowException(exceptionHandler);
}

/// <summary>
Expand Down Expand Up @@ -345,6 +366,7 @@ public int RunReliabilityTests(string testConfig, bool doReplay)
_testsRunningCount = 0;
_testsRanCount = 0;
_curTestSet = testSet;
_debugBreakOnTestHang = _curTestSet.DebugBreakOnTestHang;
if (timeValue != null)
_curTestSet.MaximumTime = ReliabilityConfig.ConvertTimeValueToTestRunTime(timeValue);

Expand Down Expand Up @@ -506,14 +528,33 @@ public int RunReliabilityTests(string testConfig, bool doReplay)
return (99);
}

[DllImport("kernel32.dll")]
private extern static void DebugBreak();
public static ExceptionHandler GenerateExceptionMessageAndHandler(bool debugBreak, Exception e)
{
ExceptionHandler exceptionHandler = new ExceptionHandler();

[DllImport("kernel32.dll")]
private extern static bool IsDebuggerPresent();
if (debugBreak)
{
exceptionHandler.HandleMessage = String.Format("Interrupt for exception: {0}", e.Message);
exceptionHandler.Handler = delegate() { Debugger.Break(); };
}
else
{
exceptionHandler.HandleMessage = String.Format("Throw exception: {0}", e.Message);
exceptionHandler.Handler = delegate() { throw e; };
}

[DllImport("kernel32.dll")]
private extern static void OutputDebugString(string debugStr);
return exceptionHandler;
}

private void DebugBreakOrThrowException(ExceptionHandler exceptionHandler)
{
string msg = exceptionHandler.HandleMessage;
Action handler = exceptionHandler.Handler;

Console.WriteLine(msg);
_logger.WriteToInstrumentationLog(_curTestSet, LoggingLevels.Tests, msg);
handler();
}

/// <summary>
/// Checks to see if we should block all execution due to a fatal error
Expand All @@ -533,27 +574,6 @@ private static void NoExitPoll()
}
}
}
internal static void MyDebugBreak(string extraData)
{
if (IsDebuggerPresent())
{
Console.WriteLine(string.Format("DebugBreak: {0}", extraData));
DebugBreak();
}
{
// We need to stop the process now,
// but all the threads are still running
try
{
Console.WriteLine("MyDebugBreak called, stopping process... {0}", extraData);
}
finally
{
s_fNoExit = true;
Thread.CurrentThread.Join();
}
}
}

/// <summary>
/// Calculates the total number of tests to be run based upon the maximum
Expand Down Expand Up @@ -778,9 +798,11 @@ private void TestStarter()
else
{
Thread.Sleep(250); // give the CPU a bit of a rest if we don't need to start a new test.
if (_curTestSet.DebugBreakOnMissingTest && DateTime.Now.Subtract(_startTime) > minTimeToStartTest)
if (DateTime.Now.Subtract(_startTime) > minTimeToStartTest)
{
NewTestsNotStartingDebugBreak();
MissingTestException e = new MissingTestException("New tests not starting");
ExceptionHandler exceptionHandler = GenerateExceptionMessageAndHandler(_curTestSet.DebugBreakOnMissingTest, e);
DebugBreakOrThrowException(exceptionHandler);
}
}
}
Expand All @@ -799,12 +821,6 @@ private void TestStarter()
TestSetShutdown(totalTestsToRun);
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void NewTestsNotStartingDebugBreak()
{
MyDebugBreak("Tests haven't been started in a long time!");
}

/// <summary>
/// Shuts down the current test set, waiting for tests to finish, etc...
/// </summary>
Expand Down Expand Up @@ -880,22 +896,12 @@ private void TestSetShutdown(int totalTestsToRun)
}
}

if (_curTestSet.DebugBreakOnTestHang)
{
TestIsHungDebugBreak();
}
TimeoutException e = new TimeoutException("Time limit reached.");
ExceptionHandler exceptionHandler = GenerateExceptionMessageAndHandler(_curTestSet.DebugBreakOnTestHang, e);
DebugBreakOrThrowException(exceptionHandler);
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void TestIsHungDebugBreak()
{
string msg = String.Format("break");
_logger.WriteToInstrumentationLog(_curTestSet, LoggingLevels.StartupShutdown, msg);

MyDebugBreak("TestHang");
}

/// <summary>
/// Starts the test passed. The test should already be loaded into an app domain.
/// </summary>
Expand Down Expand Up @@ -1046,12 +1052,10 @@ private void StartTestWorker(object test)
}
_logger.WriteToInstrumentationLog(_curTestSet, LoggingLevels.Tests, String.Format("Test {0} has exited with result {1}", daTest.RefOrID, exitCode));
}
catch (PathTooLongException)
catch (PathTooLongException e)
{
if (_curTestSet.DebugBreakOnPathTooLong)
{
MyDebugBreak("Path too long");
}
ExceptionHandler exceptionHandler = GenerateExceptionMessageAndHandler(_curTestSet.DebugBreakOnPathTooLong, e);
DebugBreakOrThrowException(exceptionHandler);
}
catch (OutOfMemoryException e)
{
Expand Down Expand Up @@ -1196,12 +1200,6 @@ private void StartTestWorker(object test)
}
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void UnexpectedThreadAbortDebugBreak()
{
MyDebugBreak("Unexpected Thread Abort");
}

/// <summary>
/// Called after a test has finished executing.
/// </summary>
Expand Down Expand Up @@ -1313,10 +1311,6 @@ private void TestPreLoader(ReliabilityTest test, string[] paths)
_logger.WriteToInstrumentationLog(_curTestSet, LoggingLevels.Tests, msg);
test.ConcurrentCopies = 0;
test.TestLoadFailed = true;
if (_curTestSet.DebugBreakOnBadTest)
{
BadTestDebugBreak(msg);
}

// crash on exceptions when running as a unit test.
if (IsRunningAsUnitTest)
Expand All @@ -1325,11 +1319,6 @@ private void TestPreLoader(ReliabilityTest test, string[] paths)
Interlocked.Decrement(ref LoadingCount);
}

[MethodImpl(MethodImplOptions.NoInlining)]
private void BadTestDebugBreak(string msg)
{
MyDebugBreak(msg);
}

[MethodImpl(MethodImplOptions.NoInlining)]
WeakReference UnloadAssemblyLoadContextInner(ReliabilityTest test)
Expand Down
2 changes: 1 addition & 1 deletion src/tests/GC/Stress/Framework/ReliabilityTestSet.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public class ReliabilityTestSet
private string _friendlyName;
private bool _enablePerfCounters = true, _disableLogging = false, _installDetours = false;
private bool _suppressConsoleOutputFromTests = false;
private bool _debugBreakOnTestHang = true;
private bool _debugBreakOnTestHang = false;
private bool _debugBreakOnBadTest = false;
private bool _debugBreakOnOutOfMemory = false;
private bool _debugBreakOnPathTooLong = false;
Expand Down
3 changes: 1 addition & 2 deletions src/tests/GC/Stress/finalization.config
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
installDetours="false"
minimumTests="0"
minMaxTestUseCPUCount="true"
suppressConsoleOutputFromTests="true"
debugBreakOnTestHang="true">
suppressConsoleOutputFromTests="true">

<Assembly id="GCPerfSim - SOH Allocations Finalizable Objects."
successCode="100"
Expand Down
3 changes: 1 addition & 2 deletions src/tests/GC/Stress/loh.config
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
installDetours="false"
minimumTests="0"
minMaxTestUseCPUCount="true"
suppressConsoleOutputFromTests="true"
debugBreakOnTestHang="true">
suppressConsoleOutputFromTests="true">

<!-- Add GCPerfSim with No live data on the LOH -->
<Assembly id="GCPerfSim - LOH No Live Data."
Expand Down
3 changes: 1 addition & 2 deletions src/tests/GC/Stress/poh.config
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,7 @@
installDetours="false"
minimumTests="0"
minMaxTestUseCPUCount="true"
suppressConsoleOutputFromTests="true"
debugBreakOnTestHang="true">
suppressConsoleOutputFromTests="true">

<!-- Add GCPerfSim with No live data on the POH -->
<Assembly id="GCPerfSim - POH No Live Data."
Expand Down

0 comments on commit 302e0d4

Please sign in to comment.