Performance Tips for DllMains – contd.
Continuing our series on DLLs and their optional entry point DllMain, this is going to be a simple tip which allows your process to exit quickly without doing unnecessary work. When a process is cleanly exiting, each DLL loaded in the process memory receives a DLL_PROCESS_DETACH callout. This callout is also sent to a DLL when that DLL is being freed (either by FreeLibrary or it’s a dependency of a DLL which is being freed and no other DLL references it).
So how does a programmer distinguish between being because the process is exiting or because the DLL is being freed? Actually before we go there, does it even matter to distinguish between these two cases? The answer is yes, it matters a whole lot. When the process is exiting and your DLL receives the DLL_PROCESS_DETACH callout, the other threads in the process might have already exited, so if you try to do some synchronization here that might not work. Or think of the situation where you have created a ginormous memory block in your DLL_PROCESS_ATTACH and free it in your DETACH callout. The process is already exiting; technically you don’t need to clean up your resources because the OS will do it for you, so why do unnecessary work? Note: Heap operations are considered suspect in DllMains because of the process-wide LoaderLock around DllMains.
With that said going back to the original question, how do you distinguish between process exit and FreeLibrary? This is mentioned in the DllMain documentation but its not very prominent so I am including the relevant parts here:
From MSDN: https://msdn.microsoft.com/en-us/library/ms682583(VS.85).aspx
When handling DLL_PROCESS_DETACH, a DLL should free resources such as heap memory only if the DLL is being unloaded dynamically (the lpReserved parameter is NULL). If the process is terminating (the lpvReserved parameter is non-NULL), all threads in the process except the current thread either have exited already or have been explicitly terminated by a call to the ExitProcess function, which might leave some process resources such as heaps in an inconsistent state. In this case, it is not safe for the DLL to clean up the resources. Instead, the DLL should allow the operating system to reclaim the memory.
Example Usage:
BOOL WINAPI
DllMain(HINSTANCE hinst, DWORD reason, VOID *reserved)
{
switch (reason)
{
case DLL_PROCESS_DETACH:
{
if (reserved != NULL)
{
// Process Exiting – Do Nothing
return false;
}
// FreeLibrary Case
}
// Other code
} // End of DllMain
And that’s how easy it is to detect the process is exiting in your DllMain. Now if you ever close a process and you see that Windows is taking some time to close it, you know what the DLLs in the process are not doing.