Корректное особождение ресурсов!

Тема в разделе "WASM.WIN32", создана пользователем LuckyDevil, 8 ноя 2005.

  1. LuckyDevil

    LuckyDevil New Member

    Публикаций:
    0
    Регистрация:
    10 мар 2005
    Сообщения:
    278
    Адрес:
    Uzbekistan
    Всем доброго!

    Вопрос следующего характера.

    Создаю связаный список с помощью LIST_ENTRY, сохраняю в нем указатель на свой объект описатель, структура следующая:
    Код (Text):
    1.  
    2. typedef struct _FILE_ENTRY
    3. {
    4.     ULONG   ID;
    5.     PVOID   Fcb;
    6.     PVOID   Scb;
    7.     ULONG   Counter;
    8.     UNICODE_STRING  FileName;
    9.  
    10. } FILE_ENTRY,* PFILE_ENTRY;
    11.  


    возникают сомнения в следующем:

    поле FileName я заполняю путем RtlCopyUnicodeString(&FileEntry.FileName,&FileObject->FileName);

    вроде как явно я не выделяю память под FileName, но будет ли достаточно простое удаления моего объекта PFILE_ENTRY или предварительно мне еще надо сособождать поле FileName?

    если да, то как правильно это сделать?
     
  2. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    <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):
    1. RtlCopyMemory(
    2.         DestinationString->Buffer,
    3.         SourceString->Buffer,
    4.         min(SourceString->Length, DestinationString->MaximumLength) );
    И перед копированием обе UNICODE_STRING должны быть инициализированы.



    Т.е. UNICODE_STRING - это одна сущность, а буфер, указатель на который в UNICODE_STRING.Buffer - это другая сущность. У тебя дожны быть обе и буфер надо освобождать отдельно.
     
  3. LuckyDevil

    LuckyDevil New Member

    Публикаций:
    0
    Регистрация:
    10 мар 2005
    Сообщения:
    278
    Адрес:
    Uzbekistan


    Я тоже не понимал :), пока не схватил первый BSOD :), теперчи все делаю как надо, выделяю память для FileName и соответсвенно особождаю ее перед удалением моих данных.

    Вроде уяснил :).


    Код (Text):
    1.  Есть, просто не все показал:
    2. typedef struct _FILE_ENTRY
    3. {
    4.     ULONG   ID;
    5.     PVOID   Fcb;
    6.     PVOID   Scb;
    7.     ULONG   Counter;
    8.     UNICODE_STRING  FileName;
    9.  
    10. } FILE_ENTRY,* PFILE_ENTRY;
    11. ...
    12. typedef struct _FS_LIST_ENTRY
    13. {
    14.     ULONG           Sizeof;
    15.     [b]LIST_ENTRY       Link;[/b]
    16.     FILE_ENTRY      FileEntry;
    17.     PVOID DevEx;
    18. } FS_LIST_ENTRY,* PFS_LIST_ENTRY;
    19.  
    20.  
     
  4. LuckyDevil

    LuckyDevil New Member

    Публикаций:
    0
    Регистрация:
    10 мар 2005
    Сообщения:
    278
    Адрес:
    Uzbekistan
    всем доброго!

    опять туплю, подскажите.

    структура из предыдущего поста, добавляю в нее одно поле, чтобы сформировать подсписок пид процессов:
    Код (Text):
    1.  
    2. typedef struct _LIST
    3. {
    4.     LIST_ENTRY ListHead;
    5.     FAST_MUTEX ListLock;
    6. } LIST,* PLIST;
    7.  
    8. typedef struct _PID_ENTRY
    9. {
    10.         LIST_ENTRY LINK;
    11.     ULONG   PID;
    12. }
    13. typedef struct _FILE_ENTRY
    14. {
    15.     ULONG   ID;
    16.     PVOID   Fcb;
    17.     PVOID   Scb;
    18.     ULONG   Counter;
    19.     UNICODE_STRING  FileName;
    20.     <font color="red]LIST    PID;</font><!--color-->
    21. } FILE_ENTRY,* PFILE_ENTRY;
    22.  




    в коде инициализирую так:
    Код (Text):
    1.  
    2. ...
    3. LIST    gGlobalBufferList;
    4. ...
    5. VOID    
    6. InitList(PLIST pl)
    7. {
    8.     //
    9.     //initialize async list head
    10.     //
    11. if(pl->ListHead.Flink == NULL)
    12.     {
    13.         InitializeListHead(&pl->ListHead);            
    14.         ExInitializeFastMutex(&pl->ListLock);
    15.     }
    16. }
    17. ...
    18. // инициализация подсписка;
    19.  
    20. PSF_LIST_ENTRY  newBuffer;
    21. ...
    22. InitList(&newBuffer->FileEntry.PID);
    23.  
    24. InsertTailList(&gGlobalBufferList->ListHead,&newBuffer->Link);
    25.  
    26. ...
    27.  




    и тут возникает вопрос, когда я удаляю данные из глобального писка, правильно ли будет вызывать RemoveHeadList для &newBuffer->FileEntry.PID.ListHead и будет ли это означать что подсписок будет обнулен ?

    .
     
  5. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Посмотри на эту схему.
    Код (Text):
    1. [ H ]<-+
    2.        |
    3.        |                                                
    4.        +->[..]<--------------->[..]
    5.           [..]                 [..]
    6.           [..]<-+              [..]<-+
    7.                 |                    |
    8.                 |                    |
    9.                 +->[]<->[]<->[]      +->[]<->[]<->[]
    Каждая [..] и каждая [] выделяются из пула. [ H ]глобальна. Ты фактически спрашиваешь, если я правильно понял вопрос, - "нужно ли возвращать их обратно?". Ответ очевиден: конечно нужно. Когда ты отстегиваешь [..], то должен явно опустошить весь список [] и возвратить каждую [] обратно в пул. Только после этого можно вернуть в пул отстегнутую [..].


    Код (Text):
    1. if(pl->ListHead.Flink == NULL)
    Это неверно. Двусвязный список является пустым, когда ListHead.Flink указывает сама на себя. См. макрос IsListEmpty:


    Код (Text):
    1. #define IsListEmpty(ListHead) \
    2.     ((ListHead)->Flink == (ListHead))
    Настоятельно рекомендую для всех LIST_ENTRY тупо использовать макрос InitializeListHead (не важно голова это или элемент списка):


    Код (Text):
    1. VOID
    2. FORCEINLINE
    3. InitializeListHead(
    4.     IN PLIST_ENTRY ListHead
    5.     )
    6. {
    7.     ListHead->Flink = ListHead->Blink = ListHead;
    8. }
    Т.е. как только выделил структуру, в составе которой есть LIST_ENTRY, сразу тупо обнуляешь её, а потом также тупо для каждого LIST_ENTRY зовёшь InitializeListHead.



    Когда же список будет опустошён, то он как раз и вернется к состоянию, в котором он был после вызова InitializeListHead. И макрос IsListEmpty вернет TRUE.



    Вот пример:


    Код (Text):
    1. typedef struct _STRUCTURE {
    2.     LIST_ENTRY lh;
    3.     LOCK       Lock;
    4.     . . .
    5. } STRUCTURE , *PSTRUCTURE;
    6.  
    7. typedef struct _SUBSTR {
    8.     LIST_ENTRY le;
    9.     . . .
    10. } SUBSTR, *PSUBSTR;
    11.  
    12.  
    13. pStructure = ExAllocatePool( Pool, sizeof(STRUCTURE) );
    14.  
    15. if ( pStructure ) {
    16.  
    17.     RtlZeroMemory( pStructure, sizeof(STRUCTURE) );
    18.  
    19.     InitializeListHead( &pStructure->lh );
    20.     InitializeLock( &pStructure->Lock );
    21. }
    22.  
    23. . . .
    24.  
    25. pSubstr = ExAllocatePool( Pool, sizeof(SUBSTR) );
    26.  
    27. if ( pSubstr ) {
    28.  
    29.     RtlZeroMemory( pSubstr, sizeof(SUBSTR) );
    30.  
    31.     AcquireLock( &pStructure->Lock );
    32.     InsertTailList( &pStructure->lh, &pSubstr->le );
    33.     ReleaseLock( &pStructure->Lock );
    34. }
    35.  
    36. . . .
    37.  
    38. AcquireLock( &pStructure->Lock );
    39.  
    40. while ( !IsListEmpty( &pStructure->lh ) ) {
    41.  
    42.     ple = RemoveTailList( &pStructure->lh );
    43.  
    44.     pSubstr = CONTAINING_RECORD( ple, SUBSTR, le );
    45.  
    46.     ExFreePool( pSubstr );
    47. }
    48.  
    49. ReleaseLock( &pStructure->Lock );
    Единственное исключение, когда можно не звать InitializeListHead - это если сразу добавляешь элемент в список, как например SUBSTR.



    Единственный гемор в твоём случае - это блокировка. Надо ли её использовать для вложенного списка? Скорее всего нет, ибо ты используешь мьютекс, а не спинлок. Это, как правило, значит, что блокировка не очень критична ко времени. Т.е. если поток попытается схватить занятый мьютекс, то система его усыпит. Сама процедура усыпления/пробуждения относительно долгая. Так что лишние несколько тысячь тактов тут роли не играют, а за это время можно успеть пройтись по вложенному списку и его поклинапить.
     
  6. LuckyDevil

    LuckyDevil New Member

    Публикаций:
    0
    Регистрация:
    10 мар 2005
    Сообщения:
    278
    Адрес:
    Uzbekistan
    Four-F, как всегда полный ответ, спасибо, учитывая что при описании проблемы допустил неточность.

    под обнулением я имел ввиду, ситуацию когда я удаляю все данные свзанного подсписка и тут у меня начались заморочки.

    как я понял из этого:
    Код (Text):
    1. ListHead->Flink = ListHead->Blink = ListHead;
    2.  


    то париться особо не надо, если IsListEmpty вернет TRUE, список пуст и мусора я после себя не оставл в памяти.



    и тут я такого же мнения, просто сомневался вот и впиндюрил туда блокировку.
     
  7. LuckyDevil

    LuckyDevil New Member

    Публикаций:
    0
    Регистрация:
    10 мар 2005
    Сообщения:
    278
    Адрес:
    Uzbekistan
    Four-F, да еще



    верно ли был сделан выбор в пользу мьютекса?

    работа со списком идет в диспечере и "Completion Routines", может стоит комбинировать?
     
  8. Four-F

    Four-F New Member

    Публикаций:
    0
    Регистрация:
    31 авг 2002
    Сообщения:
    1.237
    Вообще то Completion Routines могут вызываться на DISPATH_LEVEL. Если на 100% уверен, что этого не произойдет, то... но я бы поменялся на спинлок.
     
  9. LuckyDevil

    LuckyDevil New Member

    Публикаций:
    0
    Регистрация:
    10 мар 2005
    Сообщения:
    278
    Адрес:
    Uzbekistan
    Four-F, полазил я по различным форумам, все утверждают, что спин-блокировка есть верное решение, что ж возьмеме на вооружение