Всем доброго! Вопрос следующего характера. Создаю связаный список с помощью LIST_ENTRY, сохраняю в нем указатель на свой объект описатель, структура следующая: Код (Text): typedef struct _FILE_ENTRY { ULONG ID; PVOID Fcb; PVOID Scb; ULONG Counter; UNICODE_STRING FileName; } FILE_ENTRY,* PFILE_ENTRY; возникают сомнения в следующем: поле FileName я заполняю путем RtlCopyUnicodeString(&FileEntry.FileName,&FileObject->FileName); вроде как явно я не выделяю память под FileName, но будет ли достаточно простое удаления моего объекта PFILE_ENTRY или предварительно мне еще надо сособождать поле FileName? если да, то как правильно это сделать?
<font color="gray][ LuckyDevil</font><!--color--><font color="gray]: Создаю связаный список с помощью LIST_ENTRY... ]</font><!--color--> А как же ты структуры к списку цепляешь, если у тя в структуре нет LIST_ENTRY? <font color="gray][ LuckyDevil</font><!--color--><font color="gray]: я не выделяю память под FileName ]</font><!--color--> А зря Тогда непонятно как это вообще у тебя работает. RtlCopyUnicodeString, грубо говоря, делает это: Код (Text): RtlCopyMemory( DestinationString->Buffer, SourceString->Buffer, min(SourceString->Length, DestinationString->MaximumLength) ); И перед копированием обе UNICODE_STRING должны быть инициализированы. Т.е. UNICODE_STRING - это одна сущность, а буфер, указатель на который в UNICODE_STRING.Buffer - это другая сущность. У тебя дожны быть обе и буфер надо освобождать отдельно.
Я тоже не понимал , пока не схватил первый BSOD , теперчи все делаю как надо, выделяю память для FileName и соответсвенно особождаю ее перед удалением моих данных. Вроде уяснил . Код (Text): Есть, просто не все показал: typedef struct _FILE_ENTRY { ULONG ID; PVOID Fcb; PVOID Scb; ULONG Counter; UNICODE_STRING FileName; } FILE_ENTRY,* PFILE_ENTRY; ... typedef struct _FS_LIST_ENTRY { ULONG Sizeof; [b]LIST_ENTRY Link;[/b] FILE_ENTRY FileEntry; PVOID DevEx; } FS_LIST_ENTRY,* PFS_LIST_ENTRY;
всем доброго! опять туплю, подскажите. структура из предыдущего поста, добавляю в нее одно поле, чтобы сформировать подсписок пид процессов: Код (Text): typedef struct _LIST { LIST_ENTRY ListHead; FAST_MUTEX ListLock; } LIST,* PLIST; typedef struct _PID_ENTRY { LIST_ENTRY LINK; ULONG PID; } typedef struct _FILE_ENTRY { ULONG ID; PVOID Fcb; PVOID Scb; ULONG Counter; UNICODE_STRING FileName; <font color="red]LIST PID;</font><!--color--> } FILE_ENTRY,* PFILE_ENTRY; в коде инициализирую так: Код (Text): ... LIST gGlobalBufferList; ... VOID InitList(PLIST pl) { // //initialize async list head // if(pl->ListHead.Flink == NULL) { InitializeListHead(&pl->ListHead); ExInitializeFastMutex(&pl->ListLock); } } ... // инициализация подсписка; PSF_LIST_ENTRY newBuffer; ... InitList(&newBuffer->FileEntry.PID); InsertTailList(&gGlobalBufferList->ListHead,&newBuffer->Link); ... и тут возникает вопрос, когда я удаляю данные из глобального писка, правильно ли будет вызывать RemoveHeadList для &newBuffer->FileEntry.PID.ListHead и будет ли это означать что подсписок будет обнулен ? .
Посмотри на эту схему. Код (Text): [ H ]<-+ | | +->[..]<--------------->[..] [..] [..] [..]<-+ [..]<-+ | | | | +->[]<->[]<->[] +->[]<->[]<->[] Каждая [..] и каждая [] выделяются из пула. [ H ]глобальна. Ты фактически спрашиваешь, если я правильно понял вопрос, - "нужно ли возвращать их обратно?". Ответ очевиден: конечно нужно. Когда ты отстегиваешь [..], то должен явно опустошить весь список [] и возвратить каждую [] обратно в пул. Только после этого можно вернуть в пул отстегнутую [..]. Код (Text): if(pl->ListHead.Flink == NULL) Это неверно. Двусвязный список является пустым, когда ListHead.Flink указывает сама на себя. См. макрос IsListEmpty: Код (Text): #define IsListEmpty(ListHead) \ ((ListHead)->Flink == (ListHead)) Настоятельно рекомендую для всех LIST_ENTRY тупо использовать макрос InitializeListHead (не важно голова это или элемент списка): Код (Text): VOID FORCEINLINE InitializeListHead( IN PLIST_ENTRY ListHead ) { ListHead->Flink = ListHead->Blink = ListHead; } Т.е. как только выделил структуру, в составе которой есть LIST_ENTRY, сразу тупо обнуляешь её, а потом также тупо для каждого LIST_ENTRY зовёшь InitializeListHead. Когда же список будет опустошён, то он как раз и вернется к состоянию, в котором он был после вызова InitializeListHead. И макрос IsListEmpty вернет TRUE. Вот пример: Код (Text): typedef struct _STRUCTURE { LIST_ENTRY lh; LOCK Lock; . . . } STRUCTURE , *PSTRUCTURE; typedef struct _SUBSTR { LIST_ENTRY le; . . . } SUBSTR, *PSUBSTR; pStructure = ExAllocatePool( Pool, sizeof(STRUCTURE) ); if ( pStructure ) { RtlZeroMemory( pStructure, sizeof(STRUCTURE) ); InitializeListHead( &pStructure->lh ); InitializeLock( &pStructure->Lock ); } . . . pSubstr = ExAllocatePool( Pool, sizeof(SUBSTR) ); if ( pSubstr ) { RtlZeroMemory( pSubstr, sizeof(SUBSTR) ); AcquireLock( &pStructure->Lock ); InsertTailList( &pStructure->lh, &pSubstr->le ); ReleaseLock( &pStructure->Lock ); } . . . AcquireLock( &pStructure->Lock ); while ( !IsListEmpty( &pStructure->lh ) ) { ple = RemoveTailList( &pStructure->lh ); pSubstr = CONTAINING_RECORD( ple, SUBSTR, le ); ExFreePool( pSubstr ); } ReleaseLock( &pStructure->Lock ); Единственное исключение, когда можно не звать InitializeListHead - это если сразу добавляешь элемент в список, как например SUBSTR. Единственный гемор в твоём случае - это блокировка. Надо ли её использовать для вложенного списка? Скорее всего нет, ибо ты используешь мьютекс, а не спинлок. Это, как правило, значит, что блокировка не очень критична ко времени. Т.е. если поток попытается схватить занятый мьютекс, то система его усыпит. Сама процедура усыпления/пробуждения относительно долгая. Так что лишние несколько тысячь тактов тут роли не играют, а за это время можно успеть пройтись по вложенному списку и его поклинапить.
Four-F, как всегда полный ответ, спасибо, учитывая что при описании проблемы допустил неточность. под обнулением я имел ввиду, ситуацию когда я удаляю все данные свзанного подсписка и тут у меня начались заморочки. как я понял из этого: Код (Text): ListHead->Flink = ListHead->Blink = ListHead; то париться особо не надо, если IsListEmpty вернет TRUE, список пуст и мусора я после себя не оставл в памяти. и тут я такого же мнения, просто сомневался вот и впиндюрил туда блокировку.
Four-F, да еще верно ли был сделан выбор в пользу мьютекса? работа со списком идет в диспечере и "Completion Routines", может стоит комбинировать?
Вообще то Completion Routines могут вызываться на DISPATH_LEVEL. Если на 100% уверен, что этого не произойдет, то... но я бы поменялся на спинлок.
Four-F, полазил я по различным форумам, все утверждают, что спин-блокировка есть верное решение, что ж возьмеме на вооружение