[release/9.0-staging] Fix debugger app hangs related to thread exit by github-actions[bot] · Pull Request #114917 · dotnet/runtime

Backport of #114887 to release/9.0-staging

/cc @tommcdon

Customer Impact

  • Customer reported
  • Found internally

Description

Debugging a .NET 9 application with Visual Studio can randomly end up freezing the debuggee.
See this issue

Reproduction Steps

Debug an application with many threads that exit while trying to step through code.

Expected behavior

Debuggee does not freeze.

Actual behavior

Debuggee gets stuck with the runtime waiting for all threads to synchronize, but one of the threads being waited has exited so it will never complete.

Regression

  • Yes
  • No

Reported on #112747, originally a VS feedback item. No known commit that caused the regression. Technically this issue has existed for all time but something in .NET 9 changed the timing to expose this issue more often.

Testing

How was the fix verified? Customer verified fix on #112747 (comment).

The following will trigger the bug

namespace ConsoleApp2
{
    internal class Program
    {
        static void Main(string[] args)
        {
            int i = 0;
            int j = 0;
            int k = 0;
            while (true)
            {
                if (Console.KeyAvailable && Console.ReadKey(true).Key == ConsoleKey.Escape)
                {
                    break;
                }
                Interlocked.Increment(ref k);
                Thread thread = new Thread(() =>
                {
                    Interlocked.Increment(ref i);
                    Interlocked.Decrement(ref k);
                    Thread.Sleep(20);
                });
                 thread.Start();
                if (j++ == 100)
                {
                    j = 0;
                    Console.WriteLine(i + " " + k);
                    Thread.Sleep(200);
                }
            }
        }
    }
}

How was the issue missed previously? Technically the bug has existed for all time. The scenario requires multiple threads being destroyed while debug events are firing in parallel.

What tests were added? Visual Studio testing

Risk

Low - this covers a missed case in thread destroy that does correct bookkeeping for the debugger during suspension