Tuesday 3 May 2016

Suspend Process

Probably you already know that the almighty ProcessExplorer allows you to suspend and resume a Windows process. As I needed to use this feature the other day, I wondered how it would be implemented. Some googling brought some interesting information.

First, there is neither a .Net Process.Suspend (or Resume) method (but you have Process.Start and Process.Kill) nor a Win32 SuspendProcess function (but you have CreateProcess and TerminateProcess). So what? The solution that I have found here and here is suspending all the threads in the process. Makes sense, windows schedules at the thread level, so if you suspend all the threads in the process, the whole process is suspended. From the code in both links you can see that we have to resort to PInvoke, because we can not suspend threads in another process directly from .Net. This brings to mind one thing, if you have ever been tempted to use the Thread.Suspend .Net method you'll have noticed that it's deprecated and discouraged. The reason for this is that if you suspend a thread that holds some resources that another thread is waiting for, you have a deadlock. Rather than this you need to use something more cooperative. Notice also that though Thread.Abort is not deprecated it's also discouraged for the same reason.

The difference is that suspending and resuming all threads in one process is one exception to that rule. As all threads get suspended there's not problem with one of them waiting forever for something hold by another, cause all of them are waiting. If then you resume them all, there's no problem. I have read some comments on stackoverflow against this technique because of the possibility of deadlocks, but as some replies say, there's no reason for that. This question mentions that, and also mentions an undocumented function that can be used to suspend a process directly (NtSuspendProcess in ntdll.dll). Seems to be used by ProcessExplorer, but being undocumented (and hence prone to change in a new OS version) I would try to avoid it.

One fundamental point to operate on threads belonging to another process is that Thread Ids are unique at the machine level (though they get reused over time), not just at the process level (you can confirm it here

No comments:

Post a Comment