I have a problem that may be fairly unique. I have an application that runs on a headless box for long hours when I am not present, but is not critical. I would like to be able to debug this application remotely using Visual Studio. In order to do so, I have code that looks like this:
// Suspend all other threads to prevent loss
// of state while we investigate the issue.
SuspendAllButCurrentThread();
var remoteDebuggerProcess = new Process
{
StartInfo =
{
UseShellExecute = true,
FileName = MsVsMonPath;
}
};
// Exception handling and early return removed here for brevity.
remoteDebuggerProcess.Start();
// Wait for a debugger attach.
while (!Debugger.IsAttached)
{
Thread.Sleep(500);
}
Debugger.Break();
// Once we get here, we've hit continue in the debugger. Restore all of our threads,
// then get rid of the remote debugging tools.
ResumeAllButCurrentThread();
remoteDebuggerProcess.CloseMainWindow();
remoteDebuggerProcess.WaitForExit();
The idea being that this way, I hit an error while I am away, and the application effectively pauses itself and waits for a remote debugger attach, which after the first continue automatically gets the right context thanks to the Debugger.Break
call.
Here is the problem: Implementing SuspendAllButCurrentThread
turns out to be nontrivial. Thread.Suspend
is deprecated, and I can't P/Invoke down to SuspendThread
because there's no one-to-one mapping between managed threads and native threads (since I need to keep the current thread alive). I don't want to install Visual Studio on the machine in question if it can possibly be avoided. How can I make this work?
C is a powerful general-purpose programming language. It can be used to develop software like operating systems, databases, compilers, and so on.
In the real sense it has no meaning or full form. It was developed by Dennis Ritchie and Ken Thompson at AT&T bell Lab. First, they used to call it as B language then later they made some improvement into it and renamed it as C and its superscript as C++ which was invented by Dr.
Quote from wikipedia: "A successor to the programming language B, C was originally developed at Bell Labs by Dennis Ritchie between 1972 and 1973 to construct utilities running on Unix." The creators want that everyone "see" his language. So he named it "C".
I can't P/Invoke down to SuspendThread because there's no one-to-one mapping between managed threads and native threads
You can't enumerate managed threads either, only unmanaged threads. There actually is a one-to-one mapping between them, they just made it hard to find it. The original intent was to allow creating a custom CLR host that didn't use operating system threads to implement Thread, a request by the SQL Server group that wanted to use fibers instead. That never worked out, they could not get it reliable enough. No actual CLR host exists that doesn't use real operating system threads.
So you can actually use Process.GetCurrentProcess().Threads to enumerate all your threads. And avoid suspending your own by pinvoking GetCurrentThreadId(), comparing it to ProcessThread.Id
How reliable that's going to be is a guess, don't try to do anything drastic like sending an alert to remind you that it is time to attach the debugger. You may have well suspended a thread that was executing code inside Windows and acquired a global lock. As well as a CLR worker thread, like the finalizer thread or the background GC thread.
The better approach is to use a separate guard process that does all this, just like a debugger will. Use a named EventWaitHandle that you create in the guard program and OpenExisting() in your main program. The guard program needs to WaitAny() on that wait handle as well as the process. Your main program can now simply call Set() to wake up the guard program. Which can now safely suspend all threads.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With