Постепенно начинает проясняться) Такой еще вопрос: KeAcquireSpinLock и KeReleaseSpinLock когда надо юзать? Как я понял, при добавлении в лист элементов, удаления из него?
Делаю так: Код (Text): POBJECTSLIST TempList; KIRQL oldKIRQL; DPRINT ("Adding item....%S\n",ObjectData.DirPath); KeAcquireSpinLock (&ListSpinLock, &oldKIRQL); TempList = ExAllocatePool (NonPagedPool,sizeof(POBJECTSLIST)); if (!TempList) { KeReleaseSpinLock (&ListSpinLock, oldKIRQL); DPRINT ("Can't allocate memory for TempList!"); return; } TempList->bod = ObjectData; ExInterlockedInsertTailList(&ListHead, &TempList->ListEntry, &ListSpinLock); KeReleaseSpinLock (&ListSpinLock, oldKIRQL); Копм виснет. Если убрать KeAcquireSpinLock и KeReleaseSpinLock, все нормально работает, если добавлять элементы редко (1-2 раза в секунду). Если чаще, то тоже виснет (что в приципе понятно). Почему не работает связка KeAcquireSpinLock и KeReleaseSpinLock? З.Ы. KeInitializeSpinLock (&ListSpinLock); сделал в DriverEntry. З.З.Ы. Надо ли здесь освобождать TempList?
Вот это совершенно лишняя команда. Либо блокаешь вручную KeAcquireSpinLock/KeReleaseSpinLock. Либо за тебя всё сделает ExInterlockedInsertTailList. Нет.
Как лишняя?? Это же вставка нового элемента в лист. Или я что-то не так понял? Может надо юзать InsertHeadList? Как вручную? Вряд ли, если оставить все без KeAcquireSpinLock и KeReleaseSpinLock, то копм виснет, т.е. как я понимаю, блокировка не происходит.
Тебе что конкретно надо от синхронизации? Обеспечить корректную работу в МП системе? Или дать только одному потоку доступ к списку в однопроцессорной системе? В кратце: она вставляет элемент в двусвязный список. Нужна для синхронизации в мультипроцессорной среде(HT, 2-4ядерники, SMP). Если ты не хочешь париться с МП, то лучше юзай мьютексы. Они как раз и предназначены предоставлять доступ к ресурсу только одному потоку в промежуток времени. То есть "одновременно" не может быть такого, что один поток читает из памяти, а другой пишет туда.
OK, мне надо реализовать следующее. У меня есть список файлов, к которым доступ запрещен. Я перехватываю API функцию (допустим NtOpenFile). Получаю имя открываемого файла. Теперь мне надо вызвать что-то типа IsAdded (...). Если этот файл в списке, то вернуть STATUS_ACCESS_DENIDED. Если не в списке, то вызвать оригинальню функцию. Так вот, вызов NtopenFile в системе происходит очень часто, поэтому может получиться так, что одна IsAdded еще не выполнилась, а ее вызывают еще раз. Что произойдет в этом случае? Ситуация еще хуже, если у компа 2 проца/1 проц, но 2-х ядерный. Собственно вопрос: как избежать зависания/падения системы в этом случае
Чтобы проблема была совсем понятной, привожу куски кода, которые мне необходимо написать. Что в них неправильно? Добавление в лист: Код (Text): void AddItem(LIST_ENTRY ListHeadToChange,PWSTR FileName) { POBJECTSLIST TempList; DPRINT ("Adding item....%S\n",FileName); TempList = ExAllocatePool (NonPagedPool,sizeof(POBJECTSLIST)); if (!TempList) { DPRINT ("Can't allocate memory for TempList! on AddItem"); return; } TempList->FileName = FileName; InsertHeadList (&ListHead,&TempList->ListEntry); } Проверка на существование элемента: Код (Text): BOOLEAN IsAdded(PWSTR FileName) { POBJECTSLIST TempList; PWSTR FirstString; PWSTR NextString = NULL; TempList = ExAllocatePool (NonPagedPool,sizeof(POBJECTSLIST)); if (!TempList) { DPRINT ("Can't allocate memory for TempList on IsAdded!"); return FALSE; } __try { TempList->ListEntry = ListHead; FirstString = TempList->FileName; DPRINT ("FirstString = %S", FirstString); while (NextString != FirstString) { NextString = TempList->FileName; DPRINT ("NextString = %S", NextString); if (pos (FileName,NextString)) { return TRUE; } TempList->ListEntry = *ListHead.Flink; NextString = TempList->bod.DirPath; } } __except (EXCEPTION_EXECUTE_HANDLER) { DPRINT ("Exception on searching the same string\n"); return FALSE; } return FALSE; } В отладчик выводится "Exception on searching the same string". "FirstString = ......" не выводится
Я думал раз ты спрашивал про добавление элементов, то тебе надо будет и запись синхронизировать. sizeof(POBJECTSLIST) == sizeof(void *), то есть ты выделяешь память размером 4/8 байт. А тебе надо размер твоей структуры, а не указателя на неё. IsAdded: Зачем? У тебя же уже есть список элементов, пробегаешь по нему и всё. в общем исходник IsAdded абсолютно лишён смысла. Советую вначале прочитать про двусвязные списки.
А как мне узнать какое количество элементов мне надо пробегать? Насколько я понял, элемент FLink структуры LIST_ENTRY указывает на следующий элемент, а последний FLink указывает на первый элемент (т.е. как бы по кругу).
DoZENT да. тебе придется где-то сохранить первый указатель и выходить из этого круга, когда очередной указатель совпал с сохраненным первым.
В общем не знаю даже, неделю с этими списками разираюсь(( Вот что сейчас наработал: AddItem: Код (Text): void AddItem(LIST_ENTRY ListHeadToChange,blockedObjectData ObjectData) { PDEVICE_EXTENSION TempList; DPRINT ("Adding item....%S\n",ObjectData.DirPath); TempList = ExAllocatePool (NonPagedPool,sizeof(DEVICE_EXTENSION)); if (!TempList) { DPRINT ("Can't allocate memory for TempList! on AddItem"); return; } TempList->str = ObjectData.DirPath; InsertHeadList (&pdx->ListHead,&TempList->ListHead); } AddItem вроде работает... IsAdded: Код (Text): BOOLEAN IsAdded(blockedObjectData bod) { PDEVICE_EXTENSION TempList; DPRINT ("Checking item....%S\n",bod.DirPath); TempList = ExAllocatePool (NonPagedPool,sizeof(DEVICE_EXTENSION)); if (!TempList) { DPRINT ("Can't allocate memory for TempList! on AddItem"); return FALSE; } //TempList - самый первый элемент TempList->ListHead = pdx->ListHead; if (!IsListEmpty (&TempList->ListHead)) { __try { DPRINT ("%S\n", TempList->str); DPRINT ("Trying to free TempList..."); RemoveHeadList (&TempList->ListHead); //KeReleaseSpinLock () DPRINT ("ok\n"); } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; DPRINT ("\n"); DPRINT ("Exception on deleting TempList (in IsAdded)\n"); } } else { DPRINT ("TempList is empty, nothing to free\n"); } return FALSE; } А вот IsAdded на строке DPRINT ("%S\n", TempList->str); выдает ???????. Такая же фигня, если вместо текстовой переменной сделать int. Тогда выдает 0.
Ну а ты че хотел. Выделяешь память ExAllocatePool'ом, а потом сразу выводишь её на экран. Ты ожидаешь чего-то другого, кроме нуля?
Если ее не выделять, то вываливается exception на TempList->ListHead = pdx->ListHead; Код (Text): BOOLEAN IsAdded(blockedObjectData bod) { PDEVICE_EXTENSION TempList = NULL; DPRINT ("Checking item....%S\n",bod.DirPath); //TempList - самый первый элемент TempList->ListHead = pdx->ListHead; if (!IsListEmpty (&TempList->ListHead)) { __try { DPRINT ("%S\n", TempList->str); DPRINT ("Trying to free TempList..."); RemoveHeadList (&TempList->ListHead); //KeReleaseSpinLock () DPRINT ("ok\n"); } __except (EXCEPTION_EXECUTE_HANDLER) { return FALSE; DPRINT ("\n"); DPRINT ("Exception on deleting TempList (in IsAdded)\n"); } } else { DPRINT ("TempList is empty, nothing to free\n"); } return FALSE; } да, я и не отрицаю, я не понял их устройства. Очень стараюсь понять, но пока безрезультатно. В сети/DDK/книгах море теории по этой теме, но практических примеров нигде не видел (кроме добавления/удаления элементов). Сделал так, как по моему мнению должно было работать. Не работает. Из-за этого встал весь проект. P.S. Заметьте, не прошу написать за меня эти функции, просто скажите, что в них неправильно?
рекомендую выползти обратно в ринг3 на время и на простых программах разобраться со списками. Это очень важная информационная структура, с которой придется не раз встречаться еще. Чем раньше разберешься, тем лучше