|Date:||May 3, 2007 / year-entry #156|
|Summary:||Exiting is one of the scariest moments in the lifetime of a process. (Sort of how landing is one of the scariest moments of air travel.) Many of the details of how processes exit are left unspecified in Win32, so different Win32 implementations can follow different mechanisms. For example, Win32s, Windows 95, and Windows NT all shut...|
Exiting is one of the scariest moments in the lifetime of a process. (Sort of how landing is one of the scariest moments of air travel.)
Many of the details of how processes exit are left unspecified in Win32, so different Win32 implementations can follow different mechanisms. For example, Win32s, Windows 95, and Windows NT all shut down processes differently. (I wouldn't be surprised if Windows CE uses yet another different mechanism.) Therefore, bear in mind that what I write in this mini-series is implementation detail and can change at any time without warning. I'm writing about it because these details can highlight bugs lurking in your code. In particular, I'm going to discuss the way processes exit on Windows XP.
I should say up front that I do not agree with many steps in the way processes exit on Windows XP. The purpose of this mini-series is not to justify the way processes exit but merely to fill you in on some of the behind-the-scenes activities so you are better-armed when you have to investigate into a mysterious crash or hang during exit. (Note that I just refer to it as the way processes exit on Windows XP rather than saying that it is how process exit is designed. As one of my colleagues put it, "Using the word design to describe this is like using the term swimming pool to refer to a puddle in your garden.")
When your program calls
Now, we're not talking happy termination like
Well, that was a pretty drastic move, now, wasn't it. And all this after the scary warnings in MSDN that
Wait, it gets worse.
Some of those threads that got forcibly terminated may have owned critical sections, mutexes, home-grown synchronization primitives (such as spin-locks), all those things that the one remaining thread might need access to during its
What about critical sections? There is no "Uh-oh" return value for critical sections;
As for the home-grown stuff, well, you're on your own.
This means that if your code happened to have owned a critical section at the time somebody called
Oh dear, now you have a pretty ugly mess on your hands.
And if your thread was terminated while it owned a spin-lock or some other home-grown synchronization object, your
But wait, it gets worse. That critical section might have been the one that protects the process heap! If one of the threads that got terminated happened to be in the middle of a heap function like
Moral of the story: If you're getting a
Note that if you were a good boy and cleaned up all the threads in the process before calling
Note also that if you're getting a
Hang on, this disaster isn't over yet. Even though the kernel went around terminating all but one thread in the process, that doesn't mean that the creation of new threads is blocked. If somebody calls
(The ability to create threads after process termination has begun is not a mistake; it's intentional and necessary. Thread injection is how the debugger breaks into a process. If thread injection were not permitted, you wouldn't be able to debug process termination!)
Next time, we'll see how the way process termination takes place on Windows XP caused not one but two problems.
†Everybody reading this article should already know how to determine whether this is the case. I'm assuming you're smart. Don't disappoint me.
<-- Back to Old New Thing Archive Index