mirror of
https://github.com/donnaskiez/ac.git
synced 2024-11-21 22:24:08 +01:00
180 lines
4.8 KiB
C
180 lines
4.8 KiB
C
|
#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;
|
||
|
}
|