mirror-ac/driver/map.c

244 lines
6.5 KiB
C
Raw Normal View History

#include "map.h"
2024-06-11 13:41:55 +02:00
VOID
RtlHashmapDelete(_In_ PRTL_HASHMAP Hashmap)
{
ExFreePoolWithTag(Hashmap->buckets, POOL_TAG_HASHMAP);
ExDeleteLookasideListEx(&Hashmap->pool);
}
NTSTATUS
2024-06-11 13:41:55 +02:00
RtlHashmapCreate(_In_ UINT32 BucketCount,
_In_ UINT32 EntryObjectSize,
_In_ HASH_FUNCTION HashFunction,
_In_ COMPARE_FUNCTION CompareFunction,
2024-06-11 13:41:55 +02:00
_In_opt_ PVOID Context,
_Out_ PRTL_HASHMAP Hashmap)
{
NTSTATUS status = STATUS_UNSUCCESSFUL;
UINT32 entry_size = sizeof(RTL_HASHMAP_ENTRY) + EntryObjectSize;
PRTL_HASHMAP_ENTRY entry = NULL;
2024-06-11 13:41:55 +02:00
if (!CompareFunction || !HashFunction)
return STATUS_INVALID_PARAMETER;
Hashmap->buckets = ExAllocatePool2(
POOL_FLAG_NON_PAGED, BucketCount * entry_size, POOL_TAG_HASHMAP);
if (!Hashmap->buckets)
return STATUS_INSUFFICIENT_RESOURCES;
for (UINT32 index = 0; index < BucketCount; index++) {
entry = &Hashmap->buckets[index];
entry->in_use = FALSE;
InitializeListHead(&entry->entry);
}
KeInitializeGuardedMutex(&Hashmap->lock);
2024-06-11 13:41:55 +02:00
status = ExInitializeLookasideListEx(&Hashmap->pool,
NULL,
NULL,
NonPagedPoolNx,
0,
entry_size,
POOL_TAG_HASHMAP,
0);
if (!NT_SUCCESS(status)) {
DEBUG_ERROR("ExInitializeLookasideListEx: %x", status);
ExFreePoolWithTag(Hashmap->buckets, POOL_TAG_HASHMAP);
return status;
}
Hashmap->bucket_count = BucketCount;
Hashmap->hash_function = HashFunction;
Hashmap->compare_function = CompareFunction;
Hashmap->object_size = EntryObjectSize;
Hashmap->active = TRUE;
Hashmap->context = Context;
return STATUS_SUCCESS;
}
FORCEINLINE
STATIC
PRTL_HASHMAP_ENTRY
2024-06-11 13:51:47 +02:00
RtlpHashmapFindUnusedEntry(_In_ PLIST_ENTRY Head)
{
2024-06-11 13:41:55 +02:00
PRTL_HASHMAP_ENTRY entry = NULL;
PLIST_ENTRY list_entry = Head->Flink;
2024-06-11 13:41:55 +02:00
while (list_entry != Head) {
entry = CONTAINING_RECORD(list_entry, RTL_HASHMAP_ENTRY, entry);
if (entry->in_use == FALSE) {
entry->in_use = TRUE;
return entry;
2024-06-11 13:41:55 +02:00
}
2024-06-11 13:41:55 +02:00
list_entry = list_entry->Flink;
}
return NULL;
}
FORCEINLINE
STATIC
PRTL_HASHMAP_ENTRY
2024-06-11 13:51:47 +02:00
RtlpHashmapAllocateBucketEntry(_In_ PRTL_HASHMAP Hashmap)
{
2024-06-11 13:41:55 +02:00
PRTL_HASHMAP_ENTRY entry = ExAllocateFromLookasideListEx(&Hashmap->pool);
if (!entry)
return NULL;
entry->in_use = TRUE;
return entry;
}
FORCEINLINE
STATIC
BOOLEAN
2024-06-11 13:51:47 +02:00
RtlpHashmapIsIndexInRange(_In_ PRTL_HASHMAP Hashmap, _In_ UINT32 Index)
{
return Index < Hashmap->bucket_count ? TRUE : FALSE;
}
/* assumes map lock is held */
PVOID
2024-06-11 13:41:55 +02:00
RtlHashmapEntryInsert(_In_ PRTL_HASHMAP Hashmap, _In_ UINT64 Key)
{
2024-06-11 13:41:55 +02:00
UINT32 index = 0;
PLIST_ENTRY list_head = NULL;
PRTL_HASHMAP_ENTRY entry = NULL;
PRTL_HASHMAP_ENTRY new_entry = NULL;
index = Hashmap->hash_function(Key);
2024-06-11 13:51:47 +02:00
if (!RtlpHashmapIsIndexInRange(Hashmap, index)) {
DEBUG_ERROR("Key is not in range of buckets");
return NULL;
}
2024-06-11 13:41:55 +02:00
list_head = &(&Hashmap->buckets[index])->entry;
2024-06-11 13:51:47 +02:00
entry = RtlpHashmapFindUnusedEntry(list_head);
2024-06-11 13:41:55 +02:00
if (entry)
return entry;
2024-06-11 13:51:47 +02:00
new_entry = RtlpHashmapAllocateBucketEntry(Hashmap);
if (!new_entry) {
DEBUG_ERROR("Failed to allocate new entry");
return NULL;
}
InsertHeadList(list_head, &new_entry->entry);
return new_entry->object;
}
/* Returns a pointer to the start of the entries caller defined data. i.e
* &PRTL_HASHMAP_ENTRY->Object
*
* Also assumes lock is held.
*/
PVOID
2024-06-11 13:41:55 +02:00
RtlHashmapEntryLookup(_In_ PRTL_HASHMAP Hashmap,
_In_ UINT64 Key,
_In_ PVOID Compare)
{
UINT32 index = 0;
PRTL_HASHMAP_ENTRY entry = NULL;
index = Hashmap->hash_function(Key);
2024-06-11 13:51:47 +02:00
if (!RtlpHashmapIsIndexInRange(Hashmap, index)) {
DEBUG_ERROR("Key is not in range of buckets");
return NULL;
}
entry = &Hashmap->buckets[index];
while (entry) {
if (entry->in_use == FALSE)
goto increment;
if (Hashmap->compare_function(entry->object, Compare))
return entry->object;
increment:
entry = CONTAINING_RECORD(entry->entry.Flink, RTL_HASHMAP_ENTRY, entry);
}
DEBUG_ERROR("Unable to find entry in hashmap.");
return NULL;
}
/* Assumes lock is held */
BOOLEAN
2024-06-11 13:41:55 +02:00
RtlHashmapEntryDelete(_Inout_ PRTL_HASHMAP Hashmap,
_In_ UINT64 Key,
_In_ PVOID Compare)
{
2024-06-11 13:41:55 +02:00
UINT32 index = 0;
PLIST_ENTRY list_head = NULL;
PLIST_ENTRY list_entry = NULL;
PRTL_HASHMAP_ENTRY entry = NULL;
index = Hashmap->hash_function(Key);
2024-06-11 13:51:47 +02:00
if (!RtlpHashmapIsIndexInRange(Hashmap, index)) {
DEBUG_ERROR("Key is not in range of buckets");
return FALSE;
}
2024-06-11 13:41:55 +02:00
list_head = &(&Hashmap->buckets[index])->entry;
list_entry = list_head->Flink;
2024-06-11 13:41:55 +02:00
while (list_entry != list_head) {
entry = CONTAINING_RECORD(list_entry, RTL_HASHMAP_ENTRY, entry);
2024-06-11 13:41:55 +02:00
if (entry->in_use &&
Hashmap->compare_function(entry->object, Compare)) {
if (entry == list_head) {
entry->in_use = FALSE;
}
else {
RemoveEntryList(&entry->entry);
2024-06-11 13:41:55 +02:00
ExFreeToLookasideListEx(&Hashmap->pool, entry);
}
return TRUE;
}
2024-06-11 13:41:55 +02:00
list_entry = list_entry->Flink;
}
return FALSE;
}
2024-06-11 13:51:47 +02:00
/* assumes lock is held */
VOID
2024-06-11 13:41:55 +02:00
RtlHashmapEnumerate(_In_ PRTL_HASHMAP Hashmap,
_In_ ENUMERATE_HASHMAP EnumerationCallback,
_In_opt_ PVOID Context)
{
2024-06-11 13:41:55 +02:00
PLIST_ENTRY list_head = NULL;
PLIST_ENTRY list_entry = NULL;
PRTL_HASHMAP_ENTRY entry = NULL;
for (UINT32 index = 0; index < Hashmap->bucket_count; index++) {
2024-06-11 13:41:55 +02:00
list_head = &Hashmap->buckets[index];
list_entry = list_head->Flink;
while (list_entry != list_head) {
entry = CONTAINING_RECORD(list_entry, RTL_HASHMAP_ENTRY, entry);
2024-06-11 13:41:55 +02:00
if (entry->in_use == TRUE)
EnumerationCallback(entry->object, Context);
list_entry = list_entry->Flink;
}
}
}