Showing posts with label nt. Show all posts
Showing posts with label nt. Show all posts

Thursday, November 5, 2015

oh my god! they killed LastAccessTime

Сабж случился 9 лет назад вместе с выходом Windows Vista и остался незаметным для широких масс пользователей программистов до сих пор:

http://blogs.technet.com/b/filecab/archive/2006/11/07/disabling-last-access-time-in-windows-vista-to-improve-ntfs-performance.aspx
https://technet.microsoft.com/en-us/library/cc959914.aspx

Итого, из пяти параметров FILE_BASIC_INFORMATION осталось три полезных, своего рода рекорд.

Tuesday, August 17, 2010

DLL_PROCESS_DETACH и С++

При разработке dll приходится мириться с тем фактом, что как правило программы прекращают свое существование, используя для этого вызов функции ExitProcess. Причем многие из них могут вызывать эту функцию в тот момент, когда ваша dll еще загружена.

Функция ExitProcess, в свою очередь, известна тем, что сначала останавливает все потоки, кроме вызывающего (используя NtTerminateProcess), а потом вызывает EntryPoint для всех dll с флагом DLL_PROCESS_DETACH. В С++ обычно точка входа называется DllMainCRTStartup. DllMainCRTStartup вызывает функцию DllMain и после нее все деструкторы глобальных объектов, расположенных в DLL.

Разумеется, что после удаления некоторого количества потоков, отличного от нуля, выполнение любого кода становится чрезвычайно опасным мероприятием, чреватым дедлоками и крешами. Некоторые комрады также утверждают, что после вызова ExitProcess перестают работать критические секции, и случаются многие другие Ужасные Вещи.

Поэтому, популярный паттерн использования DLL_PROCESS_DETACH выглядит так:
BOOL WINAPI DllMain(
IN HINSTANCE hinstDll,
IN DWORDfdwReason,
LPVOID lpvReserved
)
{
....

case DLL_PROCESS_DETACH:

if( lpvReserved == NULL )
{
// FreeLibrary is called and it is safe to free resources
// All critical sections and other primitives should work fine
FreeResources1();
FreeResources2();
...
FreeResourcesN();
}
// else { ExitProcess is called, process is terminating, so do nothing }
break;
}
_Winnie C++ Colorizer

Параметр lpvReserved описан в MSDN следующим образом:
If fdwReason is DLL_PROCESS_DETACH, lpvReserved is NULL if FreeLibrary has been called or the DLL load failed and non-NULL if the process is terminating.
(с) MSDN


В случае использования С++, код нашей идеальной Dll должен выглядеть так:
static std::auto_ptr<CMyDll> g_myDll;

BOOL WINAPI DllMain(
IN HINSTANCE hinstDll,
IN DWORD fdwReason,
LPVOID lpvReserved
)
{
....

case DLL_PROCESS_DETACH:

if( lpvReserved == NULL )
{
g_myDll.reset(0);
}
g_myDll.release();
break;
}
_Winnie C++ Colorizer

В приведенном коде нет особых проблем, но нельзя упускать тот факт, что наша идеальная dll может подключать и, как правило, подключает множество статических библиотек. Которые вполне могут содержать глобальные переменные-объекты.

Выводы крайне тривиальны: использование глобальных переменных-объектов - есть зло, особенно в статических библиотеках. Но если вы уже разрабатываете статическую библиотеку на С++ с глобальными переменными внутри, стоит предоставить функцию для их корректного фатального освобождения, с семантикой, аналогичной g_myDll.release().