mirror-ac/driver/list.c

180 lines
4.8 KiB
C
Raw Normal View History

2024-01-15 02:01:14 +01:00
#include "list.h"
#include "imports.h"
#include "driver.h"
/*
* Simple thread safe linked list implementation. All structures should begin
* with a SINGLE_LIST_ENTRY structure provided by the windows API. for example:
*
* typedef struct _LIST_ENTRY_STRUCTURE
* {
* SINGLE_LIST_ENTRY list;
* PVOID address;
* UINT32 data;
* ...
* };
*
* This common structure layout allows us to pass in a callback routine when freeing
* allowing immense flexibility to ensure we can free and/or deference any objects
* that are referenced in said object.
*
* I've opted to use a mutex rather then a spinlock since there are many times we
* enumerate the list for extended periods aswell as queue up many insertions at
* once.
*/
#define LIST_POOL_TAG 'list'
VOID
ListInit(_Inout_ PSINGLE_LIST_ENTRY Head, _Inout_ PKGUARDED_MUTEX Lock)
{
ImpKeInitializeGuardedMutex(Lock);
Head->Next = NULL;
}
VOID
ListInsert(_Inout_ PSINGLE_LIST_ENTRY Head,
_Inout_ PSINGLE_LIST_ENTRY NewEntry,
_In_ PKGUARDED_MUTEX Lock)
{
ImpKeAcquireGuardedMutex(Lock);
PSINGLE_LIST_ENTRY old_entry = Head->Next;
Head->Next = NewEntry;
NewEntry->Next = old_entry;
ImpKeReleaseGuardedMutex(Lock);
}
/*
* Assuming the SINGLE_LIST_ENTRY is the first item in the structure, we
* can pass a callback routine to be called before the free occurs. This
* allows us to dereference/free structure specific items whilst still allowing
* the list to remain flexible.
*/
BOOLEAN
ListFreeFirstEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
_In_ PKGUARDED_MUTEX Lock,
_In_opt_ FREE_LIST_ITEM_CALLBACK CallbackRoutine)
{
BOOLEAN result = FALSE;
ImpKeAcquireGuardedMutex(Lock);
if (Head->Next)
{
PSINGLE_LIST_ENTRY entry = Head->Next;
if (CallbackRoutine)
CallbackRoutine(entry);
Head->Next = Head->Next->Next;
ImpExFreePoolWithTag(entry, POOL_TAG_THREAD_LIST);
result = TRUE;
}
ImpKeReleaseGuardedMutex(Lock);
return result;
}
/*
* If we are removing a specific entry, its assumed we have freed and/or dereferenced
* any fields in the structure.
*/
VOID
ListRemoveEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
_Inout_ PSINGLE_LIST_ENTRY Entry,
_In_ PKGUARDED_MUTEX Lock)
{
ImpKeAcquireGuardedMutex(Lock);
PSINGLE_LIST_ENTRY entry = Head->Next;
if (!entry)
goto unlock;
if (entry == Entry)
{
Head->Next = entry->Next;
ImpExFreePoolWithTag(Entry, POOL_TAG_THREAD_LIST);
goto unlock;
}
while (entry->Next)
{
if (entry->Next == Entry)
{
entry->Next = Entry->Next;
ImpExFreePoolWithTag(Entry, POOL_TAG_THREAD_LIST);
goto unlock;
}
entry = entry->Next;
}
unlock:
ImpKeReleaseGuardedMutex(Lock);
}
VOID
LookasideListRemoveEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
_Inout_ PSINGLE_LIST_ENTRY Entry,
_In_ PKGUARDED_MUTEX Lock)
{
ImpKeAcquireGuardedMutex(Lock);
PTHREAD_LIST_HEAD head = GetThreadList();
PSINGLE_LIST_ENTRY entry = Head->Next;
if (!entry)
goto unlock;
if (entry == Entry)
{
Head->Next = entry->Next;
ExFreeToLookasideListEx(&head->lookaside_list, Entry);
goto unlock;
}
while (entry->Next)
{
if (entry->Next == Entry)
{
entry->Next = Entry->Next;
ExFreeToLookasideListEx(&head->lookaside_list, Entry);
goto unlock;
}
entry = entry->Next;
}
unlock:
ImpKeReleaseGuardedMutex(Lock);
}
BOOLEAN
LookasideListFreeFirstEntry(_Inout_ PSINGLE_LIST_ENTRY Head,
_In_ PKGUARDED_MUTEX Lock,
_In_opt_ FREE_LIST_ITEM_CALLBACK CallbackRoutine)
{
ImpKeAcquireGuardedMutex(Lock);
PTHREAD_LIST_HEAD head = GetThreadList();
BOOLEAN result = FALSE;
if (Head->Next)
{
PSINGLE_LIST_ENTRY entry = Head->Next;
if (CallbackRoutine)
CallbackRoutine(entry);
Head->Next = Head->Next->Next;
ExFreeToLookasideListEx(&head->lookaside_list, entry);
result = TRUE;
}
ImpKeReleaseGuardedMutex(Lock);
return result;
}