Thursday, April 29, 2010

What happens to the contents of a memory-mapped file when a process is terminated abnormally?

Bart wonders what happens to the dirty contents of a memory-mapped file when an application is terminated abnormally.
From the kernel's point of view, there isn't much difference between a normal and an abnormal termination. In fact, the last thing that Exit­Process does is Terminate­Process(Get­Current­Process(), Exit­Code), so in a very real sense the two operations are identical from the kernel's point of view. The only difference is that in a controlled termination, DLLs get their DLL_PROCESS_DETACH notifications, whereas in an abnormal termination, they don't. But given that the advice for DLLs is to do as little as possible during process termination (including suppressing normal cleanup), the difference even there is negligible.

Therefore, the real question is What happens to the dirty contents of a memory-mapped file when an application exits without closing the handle?

If a process exits without closing all its handles, the kernel will close them on the process's behalf. Now, in theory, the kernel could change its behavior depending on why a handle is closed—skipping some steps if the handle is being closed as part of cleanup and performing additional ones if it came from an explicit Close­Handle call. So it's theoretically possible that the unwritten memory-mapped data may be treated differently. (Although it does violate the principle of not keeping track of information you don't need. But as we've seen, sometimes you have to violate a principle.)

But there's also the guarantee that multiple memory-mapped views of the same local file are coherent; that is, that changes made to one view are immediately reflected in other views. Therefore, if there were another view of that memory-mapped file which you neglected to close manually, any changes you had made to that view would still be visible in other views, so the contents were not lost. It's not like the kernel is going to fire up its time machine and say, "Okay, those writes to the memory-mapped file which this terminated application made, I'm going to go back and undo them even though I had already shown them to other applications."

In other words, in the case where the memory-mapped view is to a local file, and there happens to be another view on the file, then the changes are not discarded, since they are being kept alive by that other view.

Therefore, if the kernel were to discard unflushed changes to the memory-mapped view, it would have to have not one but two special-cases. One for the "this handle is being closed implicitly due to an application exiting without closing all its handles" case and another for the "this handle being closed implicitly due to an application exiting without closing all its handles when the total number of active views is less than two."

I don't know what the final answer is, but if the behavior were any different from the process closing the handle explicitly, it would require two special-case behaviors in the kernel. I personally consider this unlikely. Certainly if I were writing an operating system, I wouldn't bother writing these two special cases.

Read more: The old new thing

Posted via email from jasper22's posterous