Double linked list

Hi,

I have read the article of the NT Insider about the windows double linked list. So far it is clear for me, but now I want to use one I have some questions:
1 When I want to insert an Entry to the list with InsertListHead/InsertListTail do I have to get memory for that Entry first?(Entry is an struct of LIST_ENTRY and some vars)
2 In addition to the above do I have to free the memory for an Entry when I remove one?
3 When I want to remove 1 Entry what is the easiest way to find the correct Entry? do have to store an pointer when I insert an Entry? Can i find this pointer back in the list?

Thanks Peter

I’ve been doing a lot of work with Doubly linked lists recently so it is fresh in my mind. This is a good thing to get your head around using as they crop up everywhere in driver development.

Taking your questions in order

“When I want to insert an Entry to the list with InsertListHead/InsertListTail do I have to get memory for that Entry first?”

Yes. Firstly you would create the Linked list in DriverEntry using InitialiseListHead, and this list would be stored on the global heap. You would also create a spinlock on the global heap. Spinlocks are used for synchronising access to the list, as this is most likely running on a multiple cpu system.

InitializeListHead(&gMyList);   
KeInitializeSpinLock(&gMyListLock);   

Your list entry struct would look like

typedef struct my_list_entry{
int var1;
int var2;
LIST ENTRY listentry;
}my_list_entry

So to add an item to the list

Acquire the spinlock

KLOCK_QUEUE_HANDLE myListLockHandle;  
KeAcquireInStackQueuedSpinLock( &gMyListLock, &myListLockHandle );  

Allocate memory to your list entry

My_List_Entry \* yourNewListEntry;   
yourNewListEntry = ExAllocatePoolWithTag(My_List_Entry,'sgaT');  
InsertTailList(gList,yourNewListEntry-\>listEntry);  
yourNewListEntry=NULL; //Change ownership  

Release the spinlock

KeAcquireInStackQueuedSpinLock( &gMyListLock, &myListLockHandle );  

“2 In addition to the above do I have to free the memory for an Entry when I remove one?”

Yes, otherwise you will leak memory.

Once again

Acquire the spinlock
Remove the entry from the list
Release the spinlock
Release the memory … ExFreeTagWithPool

KeAcquireInStackQueuedSpinLock( &gMyListLock, &myListLockHandle );  
myListEntry = gMyList.Flink;//This gets a pointer to the first item in the list  
myListEntry = CONTAINING_RECORD(MY_LIST_ENTRY,,MY_LIST_ENTRY);  
RemoveEntryList(myListEntry);  
KeReleaseInStackQueuedSpinLock( &gMyListLock, &myListLockHandle );  
ExFreePoolWithTag(myListEntry,'sgaT');  

“3 When I want to remove 1 Entry what is the easiest way to find the correct Entry? do have to store an pointer when I insert an Entry? Can i find this pointer back in the list?”

You can iterate through the list.

Acquire spinlock

Check list is not empty

For loop

Check each entry using CONTAINING_RECORD as above

If you find the entry you want to remove then use RemoveEntryList.

HTH, any questions just holler.

Yes of course you need to allocate the object you put on a list from
somewhere and just as obviously whatever you allocate you must also free.
When you remove an object from a list you either already have a pointer to
that object, in which case you can use RemoveEntryList directly, or you have
to search the list from one end to the other looking for the entry you need
to remove. CONTAINING_RECORD is very useful for converting from a LIST_ENTRY
value to the object containing that LIST_ENTRY.

On Thu, Nov 13, 2008 at 4:26 AM, wrote:

> Hi,
>
> I have read the article of the NT Insider about the windows double linked
> list. So far it is clear for me, but now I want to use one I have some
> questions:
> 1 When I want to insert an Entry to the list with
> InsertListHead/InsertListTail do I have to get memory for that Entry
> first?(Entry is an struct of LIST_ENTRY and some vars)
> 2 In addition to the above do I have to free the memory for an Entry when I
> remove one?
> 3 When I want to remove 1 Entry what is the easiest way to find the
> correct Entry? do have to store an pointer when I insert an Entry? Can i
> find this pointer back in the list?
>
> Thanks Peter
>
> —
> NTDEV is sponsored by OSR
>
> For our schedule of WDF, WDM, debugging and other seminars visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>


Mark Roddy

Thanks,

This will help me. Next week I will go on with this case. if I have any questions then I will post them.

Thanks for help so far

Peter

Quoting xxxxx@yahoo.co.uk:

Your list entry struct would look like

typedef struct my_list_entry{
int var1;
int var2;
LIST ENTRY listentry;
}my_list_entry

There are advantages to re-arranging the structure

typedef struct my_list_entry{
LIST ENTRY listentry;
int var1;
int var2;
}My_list_entry, *PMy_list_entry;

Allocate memory to your list entry

My_List_Entry \* yourNewListEntry;   
yourNewListEntry = ExAllocatePoolWithTag(My_List_Entry,'sgaT');  
InsertTailList(gList,yourNewListEntry-\>listEntry);  
yourNewListEntry=NULL; //Change ownership  

It is usually better to use lookaside lists particularly when enqueing passing buffers.

PMy_List_Entry yourNewListEntry;
yourNewListEntry = ExAllocateFromPagedLookasideList(yourLookasideList);
InsertTailList(gList, (PMy_list_entry)yourNewListEntry);


Visit Pipex Business: The homepage for UK Small Businesses

Go to http://www.pipex.co.uk/business-services

There is no advantage to putting the LIST_ENTRY as the first field in the structure. Even worse, with your change

InsertTailList(gList, (PMy_list_entry)yourNewListEntry);

It is
a) not type safe
b) now assumes that the LIST_ENTRY will be the first field.

You should always use the field name when adding it to the list and CONTAINING_RECORD when removing it from the list, regardless of the position of LIST_ENTRY in the struct. What happens if the code stays the way you have it and someone accidentally adds a field before the LIST_ENTRY? You will get random corruption and things breaking all over the place.

As for the originally posted code to remove any item

KeAcquireInStackQueuedSpinLock( &gMyListLock, &myListLockHandle );  
myListEntry = gMyList.Flink;//This gets a pointer to the first \> item in the list  
myListEntry = CONTAINING_RECORD(MY_LIST_ENTRY,,MY_LIST_ENTRY);  
RemoveEntryList(myListEntry);  
KeReleaseInStackQueuedSpinLock( &gMyListLock, &myListLockHandle ); ExFreePoolWithTag(myListEntry,'sgaT');  

This can be much simpler

myListEntry = NULL;

KeAcquireInStackQueuedSpinLock( &gMyListLock, &myListLockHandle );
if (IsListEmpty(&gMyList) == FALSE) {
//This gets a pointer to the first > item in the list
myListEntry = CONTAINING_RECORD(RemoveHeadList(&gMyList), my_list_entry, listentry);
}
KeReleaseInStackQueuedSpinLock( &gMyListLock, &myListLockHandle );

ExFreePoolWithTag(myListEntry,‘sgaT’);

-----Original Message-----
From: xxxxx@lists.osr.com [mailto:xxxxx@lists.osr.com] On Behalf Of xxxxx@dsl.pipex.com
Sent: Thursday, November 13, 2008 8:05 AM
To: Windows System Software Devs Interest List
Subject: RE:[ntdev] Double linked list

Quoting xxxxx@yahoo.co.uk:

Your list entry struct would look like

typedef struct my_list_entry{
int var1;
int var2;
LIST ENTRY listentry;
}my_list_entry

There are advantages to re-arranging the structure

typedef struct my_list_entry{
LIST ENTRY listentry;
int var1;
int var2;
}My_list_entry, *PMy_list_entry;

Allocate memory to your list entry

My_List_Entry \* yourNewListEntry;  
yourNewListEntry = ExAllocatePoolWithTag(My_List_Entry,'sgaT');  
InsertTailList(gList,yourNewListEntry-\>listEntry);  
yourNewListEntry=NULL; //Change ownership  

It is usually better to use lookaside lists particularly when enqueing passing buffers.

PMy_List_Entry yourNewListEntry;
yourNewListEntry = ExAllocateFromPagedLookasideList(yourLookasideList);
InsertTailList(gList, (PMy_list_entry)yourNewListEntry);


Visit Pipex Business: The homepage for UK Small Businesses

Go to http://www.pipex.co.uk/business-services


NTDEV is sponsored by OSR

For our schedule of WDF, WDM, debugging and other seminars visit:
http://www.osr.com/seminars

To unsubscribe, visit the List Server section of OSR Online at http://www.osronline.com/page.cfm?name=ListServer