mirror of
https://github.com/reactos/reactos.git
synced 2025-05-31 06:58:10 +00:00
Alex Ionescu <ionucu@videotron.ca>
- Fix implementation of NT Profile Objects. Structures are guesses, but seem pretty close to the NT ones... a lot of stuff based on David Welch's old implementation, but simplified the way profiles are managed extensively, and also using the same buckethash mechanism as NT, this is required for compatibility with Nt Native APIs that use Profile Objects. - Removed KDBG internal profile management and associated files. I will re-write the Profiler to use NT Profile Objects, which will allow us more extensibilty while profiling and also greater compatibility with NT. svn path=/trunk/; revision=14022
This commit is contained in:
parent
b607cb6445
commit
b1ce653a14
14 changed files with 738 additions and 3513 deletions
|
@ -33,7 +33,7 @@ else
|
|||
OBJECTS_KDBG :=
|
||||
endif
|
||||
ifeq ($(DBG_OR_KDBG), 1)
|
||||
OBJECTS_KDBG := $(OBJECTS_KDBG) dbg/kdb_symbols.o dbg/profile.o
|
||||
OBJECTS_KDBG := $(OBJECTS_KDBG) dbg/kdb_symbols.o
|
||||
endif
|
||||
|
||||
TARGET_ASFLAGS = -I./include
|
||||
|
@ -233,14 +233,12 @@ OBJECTS_PS = \
|
|||
|
||||
# Executive Subsystem (Ex)
|
||||
OBJECTS_EX = \
|
||||
ex/btree.o \
|
||||
ex/callback.o \
|
||||
ex/error.o \
|
||||
ex/event.o \
|
||||
ex/evtpair.o \
|
||||
ex/fmutex.o \
|
||||
ex/handle.o \
|
||||
ex/hashtab.o \
|
||||
ex/init.o \
|
||||
ex/interlck.o \
|
||||
ex/list.o \
|
||||
|
@ -250,7 +248,6 @@ OBJECTS_EX = \
|
|||
ex/profile.o \
|
||||
ex/resource.o \
|
||||
ex/rundown.o \
|
||||
ex/stree.o \
|
||||
ex/sem.o \
|
||||
ex/synch.o \
|
||||
ex/sysinfo.o \
|
||||
|
|
|
@ -255,19 +255,6 @@ BOOLEAN
|
|||
KdbpAttachToProcess(
|
||||
PVOID ProcessId);
|
||||
|
||||
/* from profile.c */
|
||||
|
||||
VOID
|
||||
KdbInitProfiling();
|
||||
VOID
|
||||
KdbInitProfiling2();
|
||||
VOID
|
||||
KdbDisableProfiling();
|
||||
VOID
|
||||
KdbEnableProfiling();
|
||||
VOID
|
||||
KdbProfileInterrupt(ULONG_PTR Eip);
|
||||
|
||||
/* other functions */
|
||||
|
||||
#define KdbpSafeReadMemory(dst, src, size) MmSafeCopyFromUser(dst, src, size)
|
||||
|
|
|
@ -1,478 +0,0 @@
|
|||
/* $Id$
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/dbg/profile.c
|
||||
* PURPOSE: Kernel profiling
|
||||
*
|
||||
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#include "kdb.h"
|
||||
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
#define PROFILE_SESSION_LENGTH 30 /* Session length in seconds */
|
||||
|
||||
typedef struct _PROFILE_DATABASE_ENTRY
|
||||
{
|
||||
ULONG_PTR Address;
|
||||
} PROFILE_DATABASE_ENTRY, *PPROFILE_DATABASE_ENTRY;
|
||||
|
||||
#define PDE_BLOCK_ENTRIES ((PAGE_SIZE - (sizeof(LIST_ENTRY) + sizeof(ULONG))) / sizeof(PROFILE_DATABASE_ENTRY))
|
||||
|
||||
typedef struct _PROFILE_DATABASE_BLOCK
|
||||
{
|
||||
LIST_ENTRY ListEntry;
|
||||
ULONG UsedEntries;
|
||||
PROFILE_DATABASE_ENTRY Entries[PDE_BLOCK_ENTRIES];
|
||||
} PROFILE_DATABASE_BLOCK, *PPROFILE_DATABASE_BLOCK;
|
||||
|
||||
typedef struct _PROFILE_DATABASE
|
||||
{
|
||||
LIST_ENTRY ListHead;
|
||||
} PROFILE_DATABASE, *PPROFILE_DATABASE;
|
||||
|
||||
typedef struct _SAMPLE_GROUP_INFO
|
||||
{
|
||||
ULONG_PTR Address;
|
||||
ULONG Count;
|
||||
CHAR Description[128];
|
||||
LIST_ENTRY ListEntry;
|
||||
} SAMPLE_GROUP_INFO, *PSAMPLE_GROUP_INFO;
|
||||
|
||||
static volatile BOOLEAN KdbProfilingInitialized = FALSE;
|
||||
static volatile BOOLEAN KdbProfilingEnabled = FALSE;
|
||||
static volatile BOOLEAN KdbProfilingSuspended = FALSE;
|
||||
static PPROFILE_DATABASE KdbProfileDatabase = NULL;
|
||||
static KDPC KdbProfilerCollectorDpc;
|
||||
static HANDLE KdbProfilerThreadHandle;
|
||||
static CLIENT_ID KdbProfilerThreadCid;
|
||||
static HANDLE KdbProfilerLogFile;
|
||||
static KTIMER KdbProfilerTimer;
|
||||
static KMUTEX KdbProfilerLock;
|
||||
static BOOLEAN KdbEnableProfiler = FALSE;
|
||||
|
||||
VOID
|
||||
KdbDeleteProfileDatabase(PPROFILE_DATABASE ProfileDatabase)
|
||||
{
|
||||
PLIST_ENTRY current = NULL;
|
||||
|
||||
current = RemoveHeadList(&ProfileDatabase->ListHead);
|
||||
while (current != &ProfileDatabase->ListHead)
|
||||
{
|
||||
PPROFILE_DATABASE_BLOCK block = CONTAINING_RECORD(
|
||||
current, PROFILE_DATABASE_BLOCK, ListEntry);
|
||||
ExFreePool(block);
|
||||
current = RemoveHeadList(&ProfileDatabase->ListHead);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
KdbAddEntryToProfileDatabase(PPROFILE_DATABASE ProfileDatabase, ULONG_PTR Address)
|
||||
{
|
||||
PPROFILE_DATABASE_BLOCK block;
|
||||
|
||||
if (IsListEmpty(&ProfileDatabase->ListHead))
|
||||
{
|
||||
block = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE_BLOCK));
|
||||
ASSERT(block);
|
||||
block->UsedEntries = 0;
|
||||
InsertTailList(&ProfileDatabase->ListHead, &block->ListEntry);
|
||||
block->Entries[block->UsedEntries++].Address = Address;
|
||||
return;
|
||||
}
|
||||
|
||||
block = CONTAINING_RECORD(ProfileDatabase->ListHead.Blink, PROFILE_DATABASE_BLOCK, ListEntry);
|
||||
if (block->UsedEntries >= PDE_BLOCK_ENTRIES)
|
||||
{
|
||||
block = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE_BLOCK));
|
||||
ASSERT(block);
|
||||
block->UsedEntries = 0;
|
||||
InsertTailList(&ProfileDatabase->ListHead, &block->ListEntry);
|
||||
}
|
||||
block->Entries[block->UsedEntries++].Address = Address;
|
||||
}
|
||||
|
||||
VOID INIT_FUNCTION
|
||||
KdbInitProfiling()
|
||||
{
|
||||
KdbEnableProfiler = TRUE;
|
||||
}
|
||||
|
||||
VOID INIT_FUNCTION
|
||||
KdbInitProfiling2()
|
||||
{
|
||||
if (KdbEnableProfiler)
|
||||
{
|
||||
KdbEnableProfiling();
|
||||
KdbProfilingInitialized = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
KdbSuspendProfiling()
|
||||
{
|
||||
KdbProfilingSuspended = TRUE;
|
||||
}
|
||||
|
||||
VOID
|
||||
KdbResumeProfiling()
|
||||
{
|
||||
KdbProfilingSuspended = FALSE;
|
||||
}
|
||||
|
||||
BOOLEAN
|
||||
KdbProfilerGetSymbolInfo(PVOID address, OUT PCH NameBuffer)
|
||||
{
|
||||
PLIST_ENTRY current_entry;
|
||||
MODULE_TEXT_SECTION* current;
|
||||
extern LIST_ENTRY ModuleTextListHead;
|
||||
ULONG_PTR RelativeAddress;
|
||||
NTSTATUS Status;
|
||||
CHAR FileName[256];
|
||||
CHAR FunctionName[256];
|
||||
|
||||
current_entry = ModuleTextListHead.Flink;
|
||||
|
||||
while (current_entry != &ModuleTextListHead &&
|
||||
current_entry != NULL)
|
||||
{
|
||||
current =
|
||||
CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
|
||||
|
||||
if (address >= (PVOID)current->Base &&
|
||||
address < (PVOID)(current->Base + current->Length))
|
||||
{
|
||||
RelativeAddress = (ULONG_PTR) address - current->Base;
|
||||
Status = KdbSymGetAddressInformation(current->RosSymInfo,
|
||||
RelativeAddress,
|
||||
NULL,
|
||||
FileName,
|
||||
FunctionName);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
sprintf(NameBuffer, "%s (%s)", FunctionName, FileName);
|
||||
return(TRUE);
|
||||
}
|
||||
return(TRUE);
|
||||
}
|
||||
current_entry = current_entry->Flink;
|
||||
}
|
||||
return(FALSE);
|
||||
}
|
||||
|
||||
PLIST_ENTRY
|
||||
KdbProfilerLargestSampleGroup(PLIST_ENTRY SamplesListHead)
|
||||
{
|
||||
PLIST_ENTRY current;
|
||||
PLIST_ENTRY largest;
|
||||
ULONG count;
|
||||
|
||||
count = 0;
|
||||
largest = SamplesListHead->Flink;
|
||||
current = SamplesListHead->Flink;
|
||||
while (current != SamplesListHead)
|
||||
{
|
||||
PSAMPLE_GROUP_INFO sgi = CONTAINING_RECORD(
|
||||
current, SAMPLE_GROUP_INFO, ListEntry);
|
||||
|
||||
if (sgi->Count > count)
|
||||
{
|
||||
largest = current;
|
||||
count = sgi->Count;
|
||||
}
|
||||
|
||||
current = current->Flink;
|
||||
}
|
||||
if (count == 0)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
return largest;
|
||||
}
|
||||
|
||||
VOID
|
||||
KdbProfilerWriteString(PCH String)
|
||||
{
|
||||
IO_STATUS_BLOCK Iosb;
|
||||
NTSTATUS Status;
|
||||
ULONG Length;
|
||||
|
||||
Length = strlen(String);
|
||||
Status = NtWriteFile(KdbProfilerLogFile,
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
&Iosb,
|
||||
String,
|
||||
Length,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtWriteFile() failed with status 0x%.08x\n", Status);
|
||||
}
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
KdbProfilerWriteSampleGroups(PLIST_ENTRY SamplesListHead)
|
||||
{
|
||||
CHAR Buffer[256];
|
||||
PLIST_ENTRY current = NULL;
|
||||
PLIST_ENTRY Largest;
|
||||
|
||||
KdbProfilerWriteString("\r\n\r\n");
|
||||
KdbProfilerWriteString("Count Symbol\r\n");
|
||||
KdbProfilerWriteString("--------------------------------------------------\r\n");
|
||||
|
||||
current = SamplesListHead->Flink;
|
||||
while (current != SamplesListHead)
|
||||
{
|
||||
Largest = KdbProfilerLargestSampleGroup(SamplesListHead);
|
||||
if (Largest != NULL)
|
||||
{
|
||||
PSAMPLE_GROUP_INFO sgi = CONTAINING_RECORD(
|
||||
Largest, SAMPLE_GROUP_INFO, ListEntry);
|
||||
|
||||
//DbgPrint("%.08lu %s\n", sgi->Count, sgi->Description);
|
||||
|
||||
sprintf(Buffer, "%.08lu %s\r\n", sgi->Count, sgi->Description);
|
||||
KdbProfilerWriteString(Buffer);
|
||||
|
||||
RemoveEntryList(Largest);
|
||||
ExFreePool(sgi);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
current = SamplesListHead->Flink;
|
||||
}
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
LONG STDCALL
|
||||
KdbProfilerKeyCompare(IN PVOID Key1,
|
||||
IN PVOID Key2)
|
||||
{
|
||||
int value = strcmp(Key1, Key2);
|
||||
|
||||
if (value == 0)
|
||||
return 0;
|
||||
|
||||
return (value < 0) ? -1 : 1;
|
||||
}
|
||||
|
||||
|
||||
NTSTATUS
|
||||
KdbProfilerAnalyzeSamples()
|
||||
{
|
||||
CHAR NameBuffer[512];
|
||||
ULONG KeyLength;
|
||||
PLIST_ENTRY current = NULL;
|
||||
HASH_TABLE Hashtable;
|
||||
LIST_ENTRY SamplesListHead;
|
||||
ULONG Index;
|
||||
ULONG_PTR Address;
|
||||
|
||||
if (!ExInitializeHashTable(&Hashtable, 12, KdbProfilerKeyCompare, TRUE))
|
||||
{
|
||||
DPRINT1("ExInitializeHashTable() failed.");
|
||||
KEBUGCHECK(0);
|
||||
}
|
||||
|
||||
InitializeListHead(&SamplesListHead);
|
||||
|
||||
current = RemoveHeadList(&KdbProfileDatabase->ListHead);
|
||||
while (current != &KdbProfileDatabase->ListHead)
|
||||
{
|
||||
PPROFILE_DATABASE_BLOCK block;
|
||||
|
||||
block = CONTAINING_RECORD(current, PROFILE_DATABASE_BLOCK, ListEntry);
|
||||
|
||||
for (Index = 0; Index < block->UsedEntries; Index++)
|
||||
{
|
||||
PSAMPLE_GROUP_INFO sgi;
|
||||
Address = block->Entries[Index].Address;
|
||||
if (KdbProfilerGetSymbolInfo((PVOID) Address, (PCH) &NameBuffer))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
sprintf(NameBuffer, "(0x%.08lx)", (ULONG) Address);
|
||||
}
|
||||
|
||||
KeyLength = strlen(NameBuffer);
|
||||
if (!ExSearchHashTable(&Hashtable, (PVOID) NameBuffer, KeyLength, (PVOID *) &sgi))
|
||||
{
|
||||
sgi = ExAllocatePool(NonPagedPool, sizeof(SAMPLE_GROUP_INFO));
|
||||
ASSERT(sgi);
|
||||
sgi->Address = Address;
|
||||
sgi->Count = 1;
|
||||
strcpy(sgi->Description, NameBuffer);
|
||||
InsertTailList(&SamplesListHead, &sgi->ListEntry);
|
||||
ExInsertHashTable(&Hashtable, sgi->Description, KeyLength, (PVOID) sgi);
|
||||
}
|
||||
else
|
||||
{
|
||||
sgi->Count++;
|
||||
}
|
||||
}
|
||||
|
||||
ExFreePool(block);
|
||||
|
||||
current = RemoveHeadList(&KdbProfileDatabase->ListHead);
|
||||
}
|
||||
|
||||
KdbProfilerWriteSampleGroups(&SamplesListHead);
|
||||
|
||||
ExDeleteHashTable(&Hashtable);
|
||||
|
||||
KdbDeleteProfileDatabase(KdbProfileDatabase);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
VOID STDCALL
|
||||
KdbProfilerThreadMain(PVOID Context)
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
KeWaitForSingleObject(&KdbProfilerTimer, Executive, KernelMode, TRUE, NULL);
|
||||
|
||||
KeWaitForSingleObject(&KdbProfilerLock, Executive, KernelMode, FALSE, NULL);
|
||||
|
||||
KdbSuspendProfiling();
|
||||
|
||||
KdbProfilerAnalyzeSamples();
|
||||
|
||||
KdbResumeProfiling();
|
||||
|
||||
KeReleaseMutex(&KdbProfilerLock, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
KdbDisableProfiling()
|
||||
{
|
||||
if (KdbProfilingEnabled == TRUE)
|
||||
{
|
||||
/* FIXME: Implement */
|
||||
#if 0
|
||||
KdbProfilingEnabled = FALSE;
|
||||
/* Stop timer */
|
||||
/* Close file */
|
||||
if (KdbProfileDatabase != NULL)
|
||||
{
|
||||
KdbDeleteProfileDatabase(KdbProfileDatabase);
|
||||
ExFreePool(KdbProfileDatabase);
|
||||
KdbProfileDatabase = NULL;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* SystemArgument1 = EIP
|
||||
*/
|
||||
static VOID STDCALL
|
||||
KdbProfilerCollectorDpcRoutine(PKDPC Dpc, PVOID DeferredContext,
|
||||
PVOID SystemArgument1, PVOID SystemArgument2)
|
||||
{
|
||||
ULONG_PTR address = (ULONG_PTR) SystemArgument1;
|
||||
|
||||
KdbAddEntryToProfileDatabase(KdbProfileDatabase, address);
|
||||
}
|
||||
|
||||
VOID INIT_FUNCTION
|
||||
KdbEnableProfiling()
|
||||
{
|
||||
if (KdbProfilingEnabled == FALSE)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
UNICODE_STRING FileName;
|
||||
IO_STATUS_BLOCK Iosb;
|
||||
LARGE_INTEGER DueTime;
|
||||
|
||||
RtlInitUnicodeString(&FileName, L"\\SystemRoot\\profiler.log");
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&FileName,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = NtCreateFile(&KdbProfilerLogFile,
|
||||
FILE_ALL_ACCESS,
|
||||
&ObjectAttributes,
|
||||
&Iosb,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
FILE_SUPERSEDE,
|
||||
FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
NULL,
|
||||
0);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to create profiler log file\n");
|
||||
return;
|
||||
}
|
||||
KeInitializeMutex(&KdbProfilerLock, 0);
|
||||
|
||||
KdbProfileDatabase = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE));
|
||||
ASSERT(KdbProfileDatabase);
|
||||
InitializeListHead(&KdbProfileDatabase->ListHead);
|
||||
KeInitializeDpc(&KdbProfilerCollectorDpc, KdbProfilerCollectorDpcRoutine, NULL);
|
||||
|
||||
/* Initialize our periodic timer and its associated DPC object. When the timer
|
||||
expires, the KdbProfilerSessionEndDpc deferred procedure call (DPC) is queued */
|
||||
KeInitializeTimerEx(&KdbProfilerTimer, SynchronizationTimer);
|
||||
|
||||
Status = PsCreateSystemThread(&KdbProfilerThreadHandle,
|
||||
THREAD_ALL_ACCESS,
|
||||
NULL,
|
||||
NULL,
|
||||
&KdbProfilerThreadCid,
|
||||
KdbProfilerThreadMain,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("Failed to create profiler thread\n");
|
||||
return;
|
||||
}
|
||||
|
||||
/* Start the periodic timer with an initial and periodic
|
||||
relative expiration time of PROFILE_SESSION_LENGTH seconds */
|
||||
DueTime.QuadPart = -(LONGLONG) PROFILE_SESSION_LENGTH * 1000 * 10000;
|
||||
KeSetTimerEx(&KdbProfilerTimer, DueTime, PROFILE_SESSION_LENGTH * 1000, NULL);
|
||||
|
||||
KdbProfilingEnabled = TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
KdbProfileInterrupt(ULONG_PTR Address)
|
||||
{
|
||||
ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
|
||||
|
||||
if (KdbProfilingInitialized != TRUE)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ((KdbProfilingEnabled) && (!KdbProfilingSuspended))
|
||||
{
|
||||
(BOOLEAN) KeInsertQueueDpc(&KdbProfilerCollectorDpc, (PVOID) Address, NULL);
|
||||
}
|
||||
}
|
|
@ -1,644 +0,0 @@
|
|||
/* $Id:$
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ex/btree.c
|
||||
* PURPOSE: Binary tree support
|
||||
*
|
||||
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||
*/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* DATA **********************************************************************/
|
||||
|
||||
typedef struct _BINARY_TREE_NODE
|
||||
{
|
||||
struct _BINARY_TREE_NODE * Parent;
|
||||
struct _BINARY_TREE_NODE * LeftChild;
|
||||
struct _BINARY_TREE_NODE * RightChild;
|
||||
PVOID Key;
|
||||
PVOID Value;
|
||||
} BINARY_TREE_NODE, *PBINARY_TREE_NODE;
|
||||
|
||||
typedef struct _TRAVERSE_CONTEXT {
|
||||
PTRAVERSE_ROUTINE Routine;
|
||||
PVOID Context;
|
||||
} TRAVERSE_CONTEXT, *PTRAVERSE_CONTEXT;
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
#define ExpBinaryTreeRootNode(Tree)(((PBINARY_TREE) (Tree))->RootNode)
|
||||
#define ExpBinaryTreeIsExternalNode(Node)(((Node)->LeftChild == NULL) && ((Node)->RightChild == NULL))
|
||||
#define ExpBinaryTreeIsInternalNode(Node)(!ExpBinaryTreeIsExternalNode(Node))
|
||||
#define ExpBinaryTreeNodeKey(Node)((Node)->Key)
|
||||
#define ExpBinaryTreeNodeValue(Node)((Node)->Value)
|
||||
#define ExpBinaryTreeParentNode(Node)((Node)->Parent)
|
||||
#define ExpBinaryTreeLeftChildNode(Node)((Node)->LeftChild)
|
||||
#define ExpBinaryTreeRightChildNode(Node)((Node)->RightChild)
|
||||
#define ExpBinaryTreeNodeEqual(Equality)((Equality) == 0)
|
||||
#define ExpBinaryTreeNodeLess(Equality)((Equality) < 0)
|
||||
#define ExpBinaryTreeNodeMore(Equality)((Equality) > 0)
|
||||
|
||||
|
||||
/*
|
||||
* Lock the binary tree
|
||||
*/
|
||||
inline VOID
|
||||
ExpLockBinaryTree(PBINARY_TREE Tree,
|
||||
PKIRQL OldIrql)
|
||||
{
|
||||
if (Tree->UseNonPagedPool)
|
||||
{
|
||||
KeAcquireSpinLock(&Tree->Lock.NonPaged, OldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExAcquireFastMutex(&Tree->Lock.Paged);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unlock the binary tree
|
||||
*/
|
||||
inline VOID
|
||||
ExpUnlockBinaryTree(PBINARY_TREE Tree,
|
||||
PKIRQL OldIrql)
|
||||
{
|
||||
if (Tree->UseNonPagedPool)
|
||||
{
|
||||
KeReleaseSpinLock(&Tree->Lock.NonPaged, *OldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExReleaseFastMutex(&Tree->Lock.Paged);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Allocate resources for a new node and initialize it.
|
||||
*/
|
||||
inline PBINARY_TREE_NODE
|
||||
ExpCreateBinaryTreeNode(PBINARY_TREE Tree,
|
||||
PBINARY_TREE_NODE Parent,
|
||||
PVOID Value)
|
||||
{
|
||||
PBINARY_TREE_NODE Node;
|
||||
|
||||
if (Tree->UseNonPagedPool)
|
||||
{
|
||||
Node = (PBINARY_TREE_NODE) ExAllocateFromNPagedLookasideList(&Tree->List.NonPaged);
|
||||
}
|
||||
else
|
||||
{
|
||||
Node = (PBINARY_TREE_NODE) ExAllocateFromPagedLookasideList(&Tree->List.Paged);
|
||||
}
|
||||
|
||||
if (Node)
|
||||
{
|
||||
ExpBinaryTreeParentNode(Node) = Parent;
|
||||
ExpBinaryTreeLeftChildNode(Node) = NULL;
|
||||
ExpBinaryTreeRightChildNode(Node) = NULL;
|
||||
ExpBinaryTreeNodeValue(Node) = Value;
|
||||
}
|
||||
|
||||
return Node;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Release resources for the node.
|
||||
*/
|
||||
inline VOID
|
||||
ExpDestroyBinaryTreeNode(PBINARY_TREE Tree,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
if (Tree->UseNonPagedPool)
|
||||
{
|
||||
ExFreeToNPagedLookasideList(&Tree->List.NonPaged, Node);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExFreeToPagedLookasideList(&Tree->List.Paged, Node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Replaces a child node of a node with a new node.
|
||||
* The lock for the tree must be acquired when this routine is called.
|
||||
*/
|
||||
inline VOID
|
||||
ExpBinaryTreeReplaceChildNode(PBINARY_TREE_NODE Child,
|
||||
PBINARY_TREE_NODE NewChild)
|
||||
{
|
||||
if (ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Child)) == Child)
|
||||
{
|
||||
ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Child)) = NewChild;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpBinaryTreeRightChildNode(ExpBinaryTreeParentNode(Child)) = NewChild;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the sibling node of a node.
|
||||
* The lock for the tree must be acquired when this routine is called.
|
||||
*/
|
||||
inline PBINARY_TREE_NODE
|
||||
ExpSiblingBinaryTreeNode(PBINARY_TREE Tree,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
if (Node == ExpBinaryTreeRootNode(Tree))
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Node)) == Node)
|
||||
{
|
||||
return ExpBinaryTreeRightChildNode(ExpBinaryTreeParentNode(Node));
|
||||
}
|
||||
else
|
||||
{
|
||||
return ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Node));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Expands an external node to an internal node.
|
||||
* The lock for the tree must be acquired when this routine is called.
|
||||
*/
|
||||
VOID
|
||||
ExpExpandExternalBinaryTreeNode(PBINARY_TREE Tree,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
ExpBinaryTreeLeftChildNode(Node) = ExpCreateBinaryTreeNode(Tree, Node, NULL);
|
||||
|
||||
if (!ExpBinaryTreeLeftChildNode(Node))
|
||||
{
|
||||
/* FIXME: Throw exception */
|
||||
DbgPrint("ExpCreateBinaryTreeNode() failed\n");
|
||||
}
|
||||
|
||||
ExpBinaryTreeRightChildNode(Node) = ExpCreateBinaryTreeNode(Tree, Node, NULL);
|
||||
|
||||
if (!ExpBinaryTreeRightChildNode(Node))
|
||||
{
|
||||
ExpDestroyBinaryTreeNode(Tree, ExpBinaryTreeLeftChildNode(Node));
|
||||
/* FIXME: Throw exception */
|
||||
DbgPrint("ExpCreateBinaryTreeNode() failed\n");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Searches a tree for a node with the specified key. If a node with the
|
||||
* specified key is not found, the external node where it should be is
|
||||
* returned.
|
||||
* The lock for the tree must be acquired when this routine is called.
|
||||
*/
|
||||
inline PBINARY_TREE_NODE
|
||||
ExpSearchBinaryTree(PBINARY_TREE Tree,
|
||||
PVOID Key,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
LONG Equality;
|
||||
|
||||
/* FIXME: Possibly do this iteratively due to the small kernel-mode stack */
|
||||
|
||||
if (ExpBinaryTreeIsExternalNode(Node))
|
||||
{
|
||||
return Node;
|
||||
}
|
||||
|
||||
Equality = (*Tree->Compare)(Key, ExpBinaryTreeNodeKey(Node));
|
||||
|
||||
if (ExpBinaryTreeNodeEqual(Equality))
|
||||
{
|
||||
return Node;
|
||||
}
|
||||
|
||||
if (ExpBinaryTreeNodeLess(Equality))
|
||||
{
|
||||
return ExpSearchBinaryTree(Tree, Key, ExpBinaryTreeLeftChildNode(Node));
|
||||
}
|
||||
|
||||
/* if (ExpBinaryTreeNodeMore(Equality)) */
|
||||
{
|
||||
return ExpSearchBinaryTree(Tree, Key, ExpBinaryTreeRightChildNode(Node));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Removes an external node and it's parent node from the tree.
|
||||
* The lock for the tree must be acquired when this routine is called.
|
||||
*/
|
||||
VOID
|
||||
ExpRemoveAboveExternalBinaryTreeNode(PBINARY_TREE Tree,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
ASSERTMSG(ExpBinaryTreeIsExternalNode(Node), ("Node is not external"));
|
||||
|
||||
if (Node == ExpBinaryTreeRootNode(Tree))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
PBINARY_TREE_NODE GrandParent;
|
||||
PBINARY_TREE_NODE NewChild;
|
||||
|
||||
GrandParent = ExpBinaryTreeParentNode(ExpBinaryTreeParentNode(Node));
|
||||
NewChild = ExpSiblingBinaryTreeNode(Tree, Node);
|
||||
|
||||
if (GrandParent != NULL)
|
||||
{
|
||||
ExpBinaryTreeReplaceChildNode(ExpBinaryTreeParentNode(Node), NewChild);
|
||||
}
|
||||
|
||||
ExpDestroyBinaryTreeNode(Tree, ExpBinaryTreeParentNode(Node));
|
||||
ExpDestroyBinaryTreeNode(Tree, Node);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Release resources used by nodes of a binary (sub)tree.
|
||||
*/
|
||||
VOID
|
||||
ExpDeleteBinaryTree(PBINARY_TREE Tree,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
/* FIXME: Possibly do this iteratively due to the small kernel-mode stack */
|
||||
|
||||
if (ExpBinaryTreeIsInternalNode(Node))
|
||||
{
|
||||
ExpDeleteBinaryTree(Tree, ExpBinaryTreeLeftChildNode(Node));
|
||||
ExpDeleteBinaryTree(Tree, ExpBinaryTreeRightChildNode(Node));
|
||||
}
|
||||
|
||||
ExpDestroyBinaryTreeNode(Tree, Node);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Traverse a binary tree using preorder traversal method.
|
||||
* Returns FALSE, if the traversal was terminated prematurely or
|
||||
* TRUE if the callback routine did not request that the traversal
|
||||
* be terminated prematurely.
|
||||
* The lock for the tree must be acquired when this routine is called.
|
||||
*/
|
||||
BOOLEAN
|
||||
ExpTraverseBinaryTreePreorder(PTRAVERSE_CONTEXT Context,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
if (ExpBinaryTreeIsInternalNode(Node))
|
||||
{
|
||||
/* Call the traversal routine */
|
||||
if (!(*Context->Routine)(Context->Context,
|
||||
ExpBinaryTreeNodeKey(Node),
|
||||
ExpBinaryTreeNodeValue(Node)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Traverse left subtree */
|
||||
ExpTraverseBinaryTreePreorder(Context, ExpBinaryTreeLeftChildNode(Node));
|
||||
|
||||
/* Traverse right subtree */
|
||||
ExpTraverseBinaryTreePreorder(Context, ExpBinaryTreeRightChildNode(Node));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Traverse a binary tree using inorder traversal method.
|
||||
* Returns FALSE, if the traversal was terminated prematurely or
|
||||
* TRUE if the callback routine did not request that the traversal
|
||||
* be terminated prematurely.
|
||||
* The lock for the tree must be acquired when this routine is called.
|
||||
*/
|
||||
BOOLEAN
|
||||
ExpTraverseBinaryTreeInorder(PTRAVERSE_CONTEXT Context,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
if (ExpBinaryTreeIsInternalNode(Node))
|
||||
{
|
||||
/* Traverse left subtree */
|
||||
ExpTraverseBinaryTreeInorder(Context, ExpBinaryTreeLeftChildNode(Node));
|
||||
|
||||
/* Call the traversal routine */
|
||||
if (!(*Context->Routine)(Context->Context,
|
||||
ExpBinaryTreeNodeKey(Node),
|
||||
ExpBinaryTreeNodeValue(Node)))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Traverse right subtree */
|
||||
ExpTraverseBinaryTreeInorder(Context, ExpBinaryTreeRightChildNode(Node));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Traverse a binary tree using postorder traversal method.
|
||||
* Returns FALSE, if the traversal was terminated prematurely or
|
||||
* TRUE if the callback routine did not request that the traversal
|
||||
* be terminated prematurely.
|
||||
* The lock for the tree must be acquired when this routine is called.
|
||||
*/
|
||||
BOOLEAN
|
||||
ExpTraverseBinaryTreePostorder(PTRAVERSE_CONTEXT Context,
|
||||
PBINARY_TREE_NODE Node)
|
||||
{
|
||||
if (ExpBinaryTreeIsInternalNode(Node))
|
||||
{
|
||||
/* Traverse left subtree */
|
||||
ExpTraverseBinaryTreePostorder(Context, ExpBinaryTreeLeftChildNode(Node));
|
||||
|
||||
/* Traverse right subtree */
|
||||
ExpTraverseBinaryTreePostorder(Context, ExpBinaryTreeRightChildNode(Node));
|
||||
|
||||
/* Call the traversal routine */
|
||||
return (*Context->Routine)(Context->Context,
|
||||
ExpBinaryTreeNodeKey(Node),
|
||||
ExpBinaryTreeNodeValue(Node));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Default key compare function. Compares the integer values of the two keys.
|
||||
*/
|
||||
LONG STDCALL
|
||||
ExpBinaryTreeDefaultCompare(PVOID Key1,
|
||||
PVOID Key2)
|
||||
{
|
||||
if (Key1 == Key2)
|
||||
return 0;
|
||||
|
||||
return (((LONG_PTR) Key1 < (LONG_PTR) Key2) ? -1 : 1);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initializes a binary tree.
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
ExInitializeBinaryTree(IN PBINARY_TREE Tree,
|
||||
IN PKEY_COMPARATOR Compare,
|
||||
IN BOOLEAN UseNonPagedPool)
|
||||
{
|
||||
RtlZeroMemory(Tree, sizeof(BINARY_TREE));
|
||||
|
||||
Tree->Compare = (Compare == NULL)
|
||||
? ExpBinaryTreeDefaultCompare : Compare;
|
||||
|
||||
Tree->UseNonPagedPool = UseNonPagedPool;
|
||||
|
||||
if (UseNonPagedPool)
|
||||
{
|
||||
ExInitializeNPagedLookasideList(
|
||||
&Tree->List.NonPaged, /* Lookaside list */
|
||||
NULL, /* Allocate routine */
|
||||
NULL, /* Free routine */
|
||||
0, /* Flags */
|
||||
sizeof(BINARY_TREE_NODE), /* Size of each entry */
|
||||
TAG('E','X','B','T'), /* Tag */
|
||||
0); /* Depth */
|
||||
|
||||
KeInitializeSpinLock(&Tree->Lock.NonPaged);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExInitializePagedLookasideList(
|
||||
&Tree->List.Paged, /* Lookaside list */
|
||||
NULL, /* Allocate routine */
|
||||
NULL, /* Free routine */
|
||||
0, /* Flags */
|
||||
sizeof(BINARY_TREE_NODE), /* Size of each entry */
|
||||
TAG('E','X','B','T'), /* Tag */
|
||||
0); /* Depth */
|
||||
|
||||
ExInitializeFastMutex(&Tree->Lock.Paged);
|
||||
}
|
||||
|
||||
ExpBinaryTreeRootNode(Tree) = ExpCreateBinaryTreeNode(Tree, NULL, NULL);
|
||||
|
||||
if (ExpBinaryTreeRootNode(Tree) == NULL)
|
||||
{
|
||||
if (UseNonPagedPool)
|
||||
{
|
||||
ExDeleteNPagedLookasideList(&Tree->List.NonPaged);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExDeletePagedLookasideList(&Tree->List.Paged);
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Release resources used by a binary tree.
|
||||
*/
|
||||
VOID STDCALL
|
||||
ExDeleteBinaryTree(IN PBINARY_TREE Tree)
|
||||
{
|
||||
/* Remove all nodes */
|
||||
ExpDeleteBinaryTree(Tree, ExpBinaryTreeRootNode(Tree));
|
||||
|
||||
if (Tree->UseNonPagedPool)
|
||||
{
|
||||
ExDeleteNPagedLookasideList(&Tree->List.NonPaged);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExDeletePagedLookasideList(&Tree->List.Paged);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Insert a value in a binary tree.
|
||||
*/
|
||||
VOID STDCALL
|
||||
ExInsertBinaryTree(IN PBINARY_TREE Tree,
|
||||
IN PVOID Key,
|
||||
IN PVOID Value)
|
||||
{
|
||||
PBINARY_TREE_NODE Node;
|
||||
KIRQL OldIrql;
|
||||
|
||||
/* FIXME: Use SEH for error reporting */
|
||||
|
||||
ExpLockBinaryTree(Tree, &OldIrql);
|
||||
Node = ExpBinaryTreeRootNode(Tree);
|
||||
do
|
||||
{
|
||||
Node = ExpSearchBinaryTree(Tree, Key, Node);
|
||||
|
||||
if (ExpBinaryTreeIsExternalNode(Node))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
Node = ExpBinaryTreeRightChildNode(Node);
|
||||
}
|
||||
} while (TRUE);
|
||||
ExpExpandExternalBinaryTreeNode(Tree, Node);
|
||||
ExpBinaryTreeNodeKey(Node) = Key;
|
||||
ExpBinaryTreeNodeValue(Node) = Value;
|
||||
ExpUnlockBinaryTree(Tree, &OldIrql);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Search for a value associated with a given key in a binary tree.
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
ExSearchBinaryTree(IN PBINARY_TREE Tree,
|
||||
IN PVOID Key,
|
||||
OUT PVOID * Value)
|
||||
{
|
||||
PBINARY_TREE_NODE Node;
|
||||
KIRQL OldIrql;
|
||||
|
||||
ExpLockBinaryTree(Tree, &OldIrql);
|
||||
Node = ExpSearchBinaryTree(Tree, Key, ExpBinaryTreeRootNode(Tree));
|
||||
|
||||
if (ExpBinaryTreeIsInternalNode(Node))
|
||||
{
|
||||
*Value = ExpBinaryTreeNodeValue(Node);
|
||||
ExpUnlockBinaryTree(Tree, &OldIrql);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
ExpUnlockBinaryTree(Tree, &OldIrql);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove a value associated with a given key from a binary tree.
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
ExRemoveBinaryTree(IN PBINARY_TREE Tree,
|
||||
IN PVOID Key,
|
||||
IN PVOID * Value)
|
||||
{
|
||||
PBINARY_TREE_NODE Node;
|
||||
KIRQL OldIrql;
|
||||
|
||||
ExpLockBinaryTree(Tree, &OldIrql);
|
||||
|
||||
Node = ExpSearchBinaryTree(Tree, Key, ExpBinaryTreeRootNode(Tree));
|
||||
|
||||
if (ExpBinaryTreeIsExternalNode(Node))
|
||||
{
|
||||
ExpUnlockBinaryTree(Tree, &OldIrql);
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
*Value = ExpBinaryTreeNodeValue(Node);
|
||||
if (ExpBinaryTreeIsExternalNode(ExpBinaryTreeLeftChildNode(Node)))
|
||||
{
|
||||
Node = ExpBinaryTreeLeftChildNode(Node);
|
||||
}
|
||||
else if (ExpBinaryTreeIsExternalNode(ExpBinaryTreeRightChildNode(Node)))
|
||||
{
|
||||
Node = ExpBinaryTreeRightChildNode(Node);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Node has internal children
|
||||
PBINARY_TREE_NODE SwapNode;
|
||||
|
||||
SwapNode = Node;
|
||||
Node = ExpBinaryTreeRightChildNode(SwapNode);
|
||||
do
|
||||
{
|
||||
Node = ExpBinaryTreeLeftChildNode(Node);
|
||||
} while (ExpBinaryTreeIsInternalNode(Node));
|
||||
}
|
||||
|
||||
ExpRemoveAboveExternalBinaryTreeNode(Tree, Node);
|
||||
ExpUnlockBinaryTree(Tree, &OldIrql);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Traverse a binary tree using either preorder, inorder or postorder
|
||||
* traversal method.
|
||||
* Returns FALSE, if the traversal was terminated prematurely or
|
||||
* TRUE if the callback routine did not request that the traversal
|
||||
* be terminated prematurely.
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
ExTraverseBinaryTree(IN PBINARY_TREE Tree,
|
||||
IN TRAVERSE_METHOD Method,
|
||||
IN PTRAVERSE_ROUTINE Routine,
|
||||
IN PVOID Context)
|
||||
{
|
||||
TRAVERSE_CONTEXT tc;
|
||||
BOOLEAN Status;
|
||||
KIRQL OldIrql;
|
||||
|
||||
tc.Routine = Routine;
|
||||
tc.Context = Context;
|
||||
|
||||
ExpLockBinaryTree(Tree, &OldIrql);
|
||||
|
||||
switch (Method)
|
||||
{
|
||||
case TraverseMethodPreorder:
|
||||
Status = ExpTraverseBinaryTreePreorder(&tc, ExpBinaryTreeRootNode(Tree));
|
||||
break;
|
||||
|
||||
case TraverseMethodInorder:
|
||||
Status = ExpTraverseBinaryTreeInorder(&tc, ExpBinaryTreeRootNode(Tree));
|
||||
break;
|
||||
|
||||
case TraverseMethodPostorder:
|
||||
Status = ExpTraverseBinaryTreePostorder(&tc, ExpBinaryTreeRootNode(Tree));
|
||||
break;
|
||||
|
||||
default:
|
||||
Status = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
ExpUnlockBinaryTree(Tree, &OldIrql);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -1,306 +0,0 @@
|
|||
/* $Id:$
|
||||
*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ex/hashtab.c
|
||||
* PURPOSE: Hash table support
|
||||
*
|
||||
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
|
||||
*/
|
||||
|
||||
/*
|
||||
* NOTES: The hash function is from:
|
||||
* Bob Jenkins <bob_jenkins@burtleburtle.net>
|
||||
* http://burtleburtle.net/bob/hash/doobs.html
|
||||
*/
|
||||
|
||||
#include <ntoskrnl.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* FUNCTIONS ****************************************************************/
|
||||
|
||||
#define ExpHashTableSize(n) ((ULONG)1 << (n))
|
||||
#define ExpHashTableMask(n) (ExpHashTableSize(n) - 1)
|
||||
|
||||
#define ExpHashMix(a, b, c) \
|
||||
{ \
|
||||
a -= b; a -= c; a ^= (c >> 13); \
|
||||
b -= c; b -= a; b ^= (a << 8); \
|
||||
c -= a; c -= b; c ^= (b >> 13); \
|
||||
a -= b; a -= c; a ^= (c >> 12); \
|
||||
b -= c; b -= a; b ^= (a << 16); \
|
||||
c -= a; c -= b; c ^= (b >> 5); \
|
||||
a -= b; a -= c; a ^= (c >> 3); \
|
||||
b -= c; b -= a; b ^= (a << 10); \
|
||||
c -= a; c -= b; c ^= (b >> 15); \
|
||||
}
|
||||
|
||||
|
||||
ULONG
|
||||
ExpHash(PUCHAR Key,
|
||||
ULONG KeyLength)
|
||||
{
|
||||
register ULONG a, b, c, len;
|
||||
|
||||
/* Set up the internal state */
|
||||
len = KeyLength;
|
||||
a = b = 0x9e3779b9; /* The golden ratio; an arbitrary value */
|
||||
c = 0;
|
||||
|
||||
/* Handle most of the key */
|
||||
while (len >= 12)
|
||||
{
|
||||
a += (Key[0] + ((ULONG)Key[1]<<8) + ((ULONG)Key[2]<<16) + ((ULONG)Key[3]<<24));
|
||||
b += (Key[4] + ((ULONG)Key[5]<<8) + ((ULONG)Key[6]<<16) + ((ULONG)Key[7]<<24));
|
||||
c += (Key[8] + ((ULONG)Key[9]<<8) + ((ULONG)Key[10]<<16)+ ((ULONG)Key[11]<<24));
|
||||
ExpHashMix(a, b, c);
|
||||
Key += 12; len -= 12;
|
||||
}
|
||||
|
||||
/* Handle the last 11 bytes */
|
||||
c += KeyLength;
|
||||
switch(len) /* All the case statements fall through */
|
||||
{
|
||||
case 11: c += ((ULONG)Key[10] << 24);
|
||||
case 10: c += ((ULONG)Key[9] << 16);
|
||||
case 9 : c += ((ULONG)Key[8] << 8);
|
||||
/* The first byte of c is reserved for the length */
|
||||
case 8 : b += ((ULONG)Key[7] << 24);
|
||||
case 7 : b += ((ULONG)Key[6] << 16);
|
||||
case 6 : b += ((ULONG)Key[5] << 8);
|
||||
case 5 : b += Key[4];
|
||||
case 4 : a += ((ULONG)Key[3] << 24);
|
||||
case 3 : a += ((ULONG)Key[2] << 16);
|
||||
case 2 : a += ((ULONG)Key[1] << 8);
|
||||
case 1 : a += Key[0];
|
||||
/* case 0: nothing left to add */
|
||||
}
|
||||
|
||||
ExpHashMix(a, b, c);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Lock the hash table
|
||||
*/
|
||||
inline VOID
|
||||
ExpLockHashTable(PHASH_TABLE HashTable,
|
||||
PKIRQL OldIrql)
|
||||
{
|
||||
if (HashTable->UseNonPagedPool)
|
||||
{
|
||||
KeAcquireSpinLock(&HashTable->Lock.NonPaged, OldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExAcquireFastMutex(&HashTable->Lock.Paged);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Unlock the hash table
|
||||
*/
|
||||
inline VOID
|
||||
ExpUnlockHashTable(PHASH_TABLE HashTable,
|
||||
PKIRQL OldIrql)
|
||||
{
|
||||
if (HashTable->UseNonPagedPool)
|
||||
{
|
||||
KeReleaseSpinLock(&HashTable->Lock.NonPaged, *OldIrql);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExReleaseFastMutex(&HashTable->Lock.Paged);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Insert a value in a hash table.
|
||||
*/
|
||||
inline VOID STDCALL
|
||||
ExpInsertHashTable(IN PHASH_TABLE HashTable,
|
||||
IN PVOID Key,
|
||||
IN ULONG KeyLength,
|
||||
IN PVOID Value)
|
||||
{
|
||||
ULONG Index;
|
||||
|
||||
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
|
||||
|
||||
ExInsertSplayTree(&HashTable->HashTrees[Index], Key, Value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Search for a value associated with a given key in a hash table.
|
||||
*/
|
||||
inline BOOLEAN STDCALL
|
||||
ExpSearchHashTable(IN PHASH_TABLE HashTable,
|
||||
IN PVOID Key,
|
||||
IN ULONG KeyLength,
|
||||
OUT PVOID * Value)
|
||||
{
|
||||
ULONG Index;
|
||||
|
||||
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
|
||||
|
||||
return ExSearchSplayTree(&HashTable->HashTrees[Index], Key, Value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove a value associated with a given key from a hash table.
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
ExpRemoveHashTable(IN PHASH_TABLE HashTable,
|
||||
IN PVOID Key,
|
||||
IN ULONG KeyLength,
|
||||
IN PVOID * Value)
|
||||
{
|
||||
ULONG Index;
|
||||
|
||||
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
|
||||
|
||||
return ExRemoveSplayTree(&HashTable->HashTrees[Index], Key, Value);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initializes a hash table.
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
ExInitializeHashTable(IN PHASH_TABLE HashTable,
|
||||
IN ULONG HashTableSize,
|
||||
IN PKEY_COMPARATOR Compare OPTIONAL,
|
||||
IN BOOLEAN UseNonPagedPool)
|
||||
{
|
||||
BOOLEAN Status;
|
||||
ULONG Index;
|
||||
|
||||
RtlZeroMemory(HashTable, sizeof(HASH_TABLE));
|
||||
|
||||
HashTable->HashTableSize = HashTableSize;
|
||||
|
||||
HashTable->UseNonPagedPool = UseNonPagedPool;
|
||||
|
||||
if (UseNonPagedPool)
|
||||
{
|
||||
KeInitializeSpinLock(&HashTable->Lock.NonPaged);
|
||||
HashTable->HashTrees = ExAllocatePool(NonPagedPool, ExpHashTableSize(HashTableSize) * sizeof(SPLAY_TREE));
|
||||
}
|
||||
else
|
||||
{
|
||||
ExInitializeFastMutex(&HashTable->Lock.Paged);
|
||||
HashTable->HashTrees = ExAllocatePool(PagedPool, ExpHashTableSize(HashTableSize) * sizeof(SPLAY_TREE));
|
||||
}
|
||||
|
||||
if (HashTable->HashTrees == NULL)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (Index = 0; Index < ExpHashTableSize(HashTableSize); Index++)
|
||||
{
|
||||
Status = ExInitializeSplayTree(&HashTable->HashTrees[Index], Compare, FALSE, UseNonPagedPool);
|
||||
|
||||
if (!Status)
|
||||
{
|
||||
LONG i;
|
||||
|
||||
for (i = Index - 1; i >= 0; i--)
|
||||
{
|
||||
ExDeleteSplayTree(&HashTable->HashTrees[i]);
|
||||
}
|
||||
|
||||
ExFreePool(HashTable->HashTrees);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Release resources used by a hash table.
|
||||
*/
|
||||
VOID STDCALL
|
||||
ExDeleteHashTable(IN PHASH_TABLE HashTable)
|
||||
{
|
||||
ULONG Index;
|
||||
|
||||
for (Index = 0; Index < ExpHashTableSize(HashTable->HashTableSize); Index++)
|
||||
{
|
||||
ExDeleteSplayTree(&HashTable->HashTrees[Index]);
|
||||
}
|
||||
|
||||
ExFreePool(HashTable->HashTrees);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Insert a value in a hash table.
|
||||
*/
|
||||
VOID STDCALL
|
||||
ExInsertHashTable(IN PHASH_TABLE HashTable,
|
||||
IN PVOID Key,
|
||||
IN ULONG KeyLength,
|
||||
IN PVOID Value)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
|
||||
/* FIXME: Use SEH for error reporting */
|
||||
|
||||
ExpLockHashTable(HashTable, &OldIrql);
|
||||
ExpInsertHashTable(HashTable, Key, KeyLength, Value);
|
||||
ExpUnlockHashTable(HashTable, &OldIrql);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Search for a value associated with a given key in a hash table.
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
ExSearchHashTable(IN PHASH_TABLE HashTable,
|
||||
IN PVOID Key,
|
||||
IN ULONG KeyLength,
|
||||
OUT PVOID * Value)
|
||||
{
|
||||
BOOLEAN Status;
|
||||
KIRQL OldIrql;
|
||||
|
||||
ExpLockHashTable(HashTable, &OldIrql);
|
||||
Status = ExpSearchHashTable(HashTable, Key, KeyLength, Value);
|
||||
ExpUnlockHashTable(HashTable, &OldIrql);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Remove a value associated with a given key from a hash table.
|
||||
*/
|
||||
BOOLEAN STDCALL
|
||||
ExRemoveHashTable(IN PHASH_TABLE HashTable,
|
||||
IN PVOID Key,
|
||||
IN ULONG KeyLength,
|
||||
IN PVOID * Value)
|
||||
{
|
||||
BOOLEAN Status;
|
||||
KIRQL OldIrql;
|
||||
|
||||
ExpLockHashTable(HashTable, &OldIrql);
|
||||
Status = ExpRemoveHashTable(HashTable, Key, KeyLength, Value);
|
||||
ExpUnlockHashTable(HashTable, &OldIrql);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -1,11 +1,10 @@
|
|||
/* $Id:$
|
||||
*
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/nt/profile.c
|
||||
* PURPOSE: Support for profiling
|
||||
* FILE: ntoskrnl/ex/profile.c
|
||||
* PURPOSE: Support for Executive Profile Objects
|
||||
*
|
||||
* PROGRAMMERS: No programmer listed.
|
||||
* PROGRAMMERS: Alex Ionescu
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
|
@ -13,369 +12,448 @@
|
|||
#include <ntoskrnl.h>
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* TYPES ********************************************************************/
|
||||
/* This structure is a *GUESS* -- Alex */
|
||||
typedef struct _EPROFILE {
|
||||
PEPROCESS Process;
|
||||
PVOID ImageBase;
|
||||
ULONG ImageSize;
|
||||
ULONG BucketSize;
|
||||
PVOID Buffer;
|
||||
ULONG BufferSize;
|
||||
PKPROFILE KeProfile;
|
||||
KPROFILE_SOURCE ProfileSource;
|
||||
KAFFINITY Affinity;
|
||||
PMDL Mdl;
|
||||
PVOID LockedBuffer;
|
||||
} EPROFILE, *PEPROFILE;
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
|
||||
|
||||
static KMUTEX ExpProfileMutex;
|
||||
|
||||
#define PROFILE_CONTROL 1
|
||||
|
||||
static GENERIC_MAPPING ExpProfileMapping = {
|
||||
STANDARD_RIGHTS_READ,
|
||||
STANDARD_RIGHTS_WRITE,
|
||||
STANDARD_RIGHTS_EXECUTE,
|
||||
STANDARD_RIGHTS_ALL};
|
||||
STANDARD_RIGHTS_READ | PROFILE_CONTROL,
|
||||
STANDARD_RIGHTS_WRITE | PROFILE_CONTROL,
|
||||
STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
|
||||
STANDARD_RIGHTS_ALL};
|
||||
|
||||
/*
|
||||
* Size of the profile hash table.
|
||||
*/
|
||||
#define PROFILE_HASH_TABLE_SIZE (32)
|
||||
VOID
|
||||
STDCALL
|
||||
ExpDeleteProfile(PVOID ObjectBody)
|
||||
{
|
||||
PEPROFILE Profile;
|
||||
|
||||
/*
|
||||
* Table of lists of per-process profiling data structures hashed by PID.
|
||||
*/
|
||||
LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
|
||||
/* Typecast the Object */
|
||||
Profile = (PEPROFILE)ObjectBody;
|
||||
|
||||
/* Check if there if the Profile was started */
|
||||
if (Profile->LockedBuffer) {
|
||||
|
||||
/* Stop the Profile */
|
||||
KeStopProfile(Profile->KeProfile);
|
||||
|
||||
/* Unmap the Locked Buffer */
|
||||
MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
|
||||
MmUnlockPages(Profile->Mdl);
|
||||
ExFreePool(Profile->Mdl);
|
||||
}
|
||||
|
||||
/* Check if a Process is associated */
|
||||
if (Profile->Process != NULL) {
|
||||
|
||||
/* Dereference it */
|
||||
ObDereferenceObject(Profile->Process);
|
||||
Profile->Process = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Head of the list of profile data structures for the kernel.
|
||||
*/
|
||||
LIST_ENTRY SystemProfileList;
|
||||
|
||||
/*
|
||||
* Lock that protects the profiling data structures.
|
||||
*/
|
||||
KSPIN_LOCK ProfileListLock;
|
||||
|
||||
/*
|
||||
* Timer interrupts happen before we have initialized the profiling
|
||||
* data structures so just ignore them before that.
|
||||
*/
|
||||
BOOLEAN ProfileInitDone = FALSE;
|
||||
|
||||
VOID INIT_FUNCTION
|
||||
VOID
|
||||
INIT_FUNCTION
|
||||
ExpInitializeProfileImplementation(VOID)
|
||||
{
|
||||
ULONG i;
|
||||
|
||||
InitializeListHead(&SystemProfileList);
|
||||
|
||||
for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++)
|
||||
{
|
||||
InitializeListHead(&ProcessProfileListHashTable[i]);
|
||||
}
|
||||
|
||||
KeInitializeSpinLock(&ProfileListLock);
|
||||
ProfileInitDone = TRUE;
|
||||
|
||||
ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
|
||||
|
||||
RtlpCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile", NonPagedPool);
|
||||
|
||||
ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
|
||||
ExProfileObjectType->PeakObjects = 0;
|
||||
ExProfileObjectType->PeakHandles = 0;
|
||||
ExProfileObjectType->TotalObjects = 0;
|
||||
ExProfileObjectType->TotalHandles = 0;
|
||||
ExProfileObjectType->PagedPoolCharge = 0;
|
||||
ExProfileObjectType->NonpagedPoolCharge = sizeof(KPROFILE);
|
||||
ExProfileObjectType->Mapping = &ExpProfileMapping;
|
||||
ExProfileObjectType->Dump = NULL;
|
||||
ExProfileObjectType->Open = NULL;
|
||||
ExProfileObjectType->Close = NULL;
|
||||
ExProfileObjectType->Delete = KiDeleteProfile;
|
||||
ExProfileObjectType->Parse = NULL;
|
||||
ExProfileObjectType->Security = NULL;
|
||||
ExProfileObjectType->QueryName = NULL;
|
||||
ExProfileObjectType->OkayToClose = NULL;
|
||||
ExProfileObjectType->Create = NULL;
|
||||
|
||||
ObpCreateTypeObject(ExProfileObjectType);
|
||||
/* Initialize the Mutex to lock the States */
|
||||
KeInitializeMutex(&ExpProfileMutex, 0x40);
|
||||
|
||||
/* Create the Object Type */
|
||||
ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
|
||||
RtlInitUnicodeString(&ExProfileObjectType->TypeName, L"Profile");
|
||||
ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
|
||||
ExProfileObjectType->PeakObjects = 0;
|
||||
ExProfileObjectType->PeakHandles = 0;
|
||||
ExProfileObjectType->TotalObjects = 0;
|
||||
ExProfileObjectType->TotalHandles = 0;
|
||||
ExProfileObjectType->PagedPoolCharge = 0;
|
||||
ExProfileObjectType->NonpagedPoolCharge = sizeof(EPROFILE);
|
||||
ExProfileObjectType->Mapping = &ExpProfileMapping;
|
||||
ExProfileObjectType->Dump = NULL;
|
||||
ExProfileObjectType->Open = NULL;
|
||||
ExProfileObjectType->Close = NULL;
|
||||
ExProfileObjectType->Delete = ExpDeleteProfile;
|
||||
ExProfileObjectType->Parse = NULL;
|
||||
ExProfileObjectType->Security = NULL;
|
||||
ExProfileObjectType->QueryName = NULL;
|
||||
ExProfileObjectType->OkayToClose = NULL;
|
||||
ExProfileObjectType->Create = NULL;
|
||||
ObpCreateTypeObject(ExProfileObjectType);
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtCreateProfile(OUT PHANDLE ProfileHandle,
|
||||
IN HANDLE Process OPTIONAL,
|
||||
IN PVOID ImageBase,
|
||||
IN ULONG ImageSize,
|
||||
IN ULONG BucketSize,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
IN KPROFILE_SOURCE ProfileSource,
|
||||
IN KAFFINITY Affinity)
|
||||
IN HANDLE Process OPTIONAL,
|
||||
IN PVOID ImageBase,
|
||||
IN ULONG ImageSize,
|
||||
IN ULONG BucketSize,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG BufferSize,
|
||||
IN KPROFILE_SOURCE ProfileSource,
|
||||
IN KAFFINITY Affinity)
|
||||
{
|
||||
HANDLE hProfile;
|
||||
PKPROFILE Profile;
|
||||
PEPROCESS pProcess;
|
||||
KPROCESSOR_MODE PreviousMode;
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
HANDLE hProfile;
|
||||
PEPROFILE Profile;
|
||||
PEPROCESS pProcess;
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
OBJECT_ATTRIBUTES ObjectAttributes;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
PreviousMode = ExGetPreviousMode();
|
||||
|
||||
if(BufferSize == 0)
|
||||
{
|
||||
return STATUS_INVALID_PARAMETER_7;
|
||||
}
|
||||
|
||||
if(PreviousMode != KernelMode)
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
ProbeForWrite(ProfileHandle,
|
||||
sizeof(HANDLE),
|
||||
sizeof(ULONG));
|
||||
ProbeForWrite(Buffer,
|
||||
BufferSize,
|
||||
sizeof(ULONG));
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
PAGED_CODE();
|
||||
|
||||
/* Easy way out */
|
||||
if(BufferSize == 0) return STATUS_INVALID_PARAMETER_7;
|
||||
|
||||
/* Check the Parameters for validity */
|
||||
if(PreviousMode != KernelMode) {
|
||||
|
||||
_SEH_TRY {
|
||||
|
||||
ProbeForWrite(ProfileHandle,
|
||||
sizeof(HANDLE),
|
||||
sizeof(ULONG));
|
||||
|
||||
ProbeForWrite(Buffer,
|
||||
BufferSize,
|
||||
sizeof(ULONG));
|
||||
} _SEH_HANDLE {
|
||||
|
||||
Status = _SEH_GetExceptionCode();
|
||||
} _SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Reference the associated process
|
||||
*/
|
||||
if (Process != NULL)
|
||||
{
|
||||
Status = ObReferenceObjectByHandle(Process,
|
||||
PROCESS_QUERY_INFORMATION,
|
||||
PsProcessType,
|
||||
PreviousMode,
|
||||
(PVOID*)&pProcess,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pProcess = NULL;
|
||||
if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege,
|
||||
PreviousMode))
|
||||
{
|
||||
DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
|
||||
return STATUS_PRIVILEGE_NOT_HELD;
|
||||
}
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Check the parameters
|
||||
*/
|
||||
if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) ||
|
||||
(pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE))
|
||||
{
|
||||
return(STATUS_INVALID_PARAMETER_3);
|
||||
}
|
||||
if (((ImageSize >> BucketSize) * 4) >= BufferSize)
|
||||
{
|
||||
return(STATUS_BUFFER_TOO_SMALL);
|
||||
}
|
||||
if (ProfileSource != ProfileTime)
|
||||
{
|
||||
return(STATUS_INVALID_PARAMETER_9);
|
||||
}
|
||||
if (Affinity != 0)
|
||||
{
|
||||
return(STATUS_INVALID_PARAMETER_10);
|
||||
/* Check if a process was specified */
|
||||
if (Process) {
|
||||
|
||||
/* Reference it */
|
||||
Status = ObReferenceObjectByHandle(Process,
|
||||
PROCESS_QUERY_INFORMATION,
|
||||
PsProcessType,
|
||||
PreviousMode,
|
||||
(PVOID*)&pProcess,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status)) return(Status);
|
||||
|
||||
} else {
|
||||
|
||||
/* No process was specified, which means a System-Wide Profile */
|
||||
pProcess = NULL;
|
||||
|
||||
/* For this, we need to check the Privilege */
|
||||
if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode)) {
|
||||
|
||||
DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
|
||||
return STATUS_PRIVILEGE_NOT_HELD;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Create the object
|
||||
*/
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
/* Create the object */
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
Status = ObCreateObject(KernelMode,
|
||||
ExProfileObjectType,
|
||||
&ObjectAttributes,
|
||||
PreviousMode,
|
||||
NULL,
|
||||
sizeof(EPROFILE),
|
||||
0,
|
||||
0,
|
||||
(PVOID*)&Profile);
|
||||
if (!NT_SUCCESS(Status)) return(Status);
|
||||
|
||||
/* Initialize it */
|
||||
Profile->ImageBase = ImageBase;
|
||||
Profile->ImageSize = ImageSize;
|
||||
Profile->Buffer = Buffer;
|
||||
Profile->BufferSize = BufferSize;
|
||||
Profile->BucketSize = BucketSize;
|
||||
Profile->LockedBuffer = NULL;
|
||||
Profile->Affinity = Affinity;
|
||||
Profile->Process = pProcess;
|
||||
|
||||
/* Insert into the Object Tree */
|
||||
Status = ObInsertObject ((PVOID)Profile,
|
||||
NULL,
|
||||
PROFILE_CONTROL,
|
||||
0,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
Status = ObCreateObject(KernelMode,
|
||||
ExProfileObjectType,
|
||||
&ObjectAttributes,
|
||||
PreviousMode,
|
||||
NULL,
|
||||
sizeof(KPROFILE),
|
||||
0,
|
||||
0,
|
||||
(PVOID*)&Profile);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize it
|
||||
*/
|
||||
Profile->Base = ImageBase;
|
||||
Profile->Size = ImageSize;
|
||||
Profile->BucketShift = BucketSize;
|
||||
Profile->BufferMdl = MmCreateMdl(NULL, Buffer, BufferSize);
|
||||
if(Profile->BufferMdl == NULL) {
|
||||
DPRINT("MmCreateMdl: Out of memory!");
|
||||
ObDereferenceObject (Profile);
|
||||
return(STATUS_NO_MEMORY);
|
||||
}
|
||||
MmProbeAndLockPages(Profile->BufferMdl, UserMode, IoWriteAccess);
|
||||
Profile->Buffer = MmGetSystemAddressForMdl(Profile->BufferMdl);
|
||||
Profile->BufferSize = BufferSize;
|
||||
Profile->ProcessorMask = Affinity;
|
||||
Profile->Started = FALSE;
|
||||
Profile->Process = pProcess;
|
||||
|
||||
/*
|
||||
* Insert the profile into the profile list data structures
|
||||
*/
|
||||
KiInsertProfile(Profile);
|
||||
|
||||
Status = ObInsertObject ((PVOID)Profile,
|
||||
NULL,
|
||||
STANDARD_RIGHTS_ALL,
|
||||
0,
|
||||
NULL,
|
||||
&hProfile);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
ObDereferenceObject (Profile);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copy the created handle back to the caller
|
||||
*/
|
||||
_SEH_TRY
|
||||
{
|
||||
*ProfileHandle = hProfile;
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
ObDereferenceObject(Profile);
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
|
||||
OUT PULONG Interval)
|
||||
{
|
||||
KPROCESSOR_MODE PreviousMode;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
PreviousMode = ExGetPreviousMode();
|
||||
|
||||
if(PreviousMode != KernelMode)
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
ProbeForWrite(Interval,
|
||||
sizeof(ULONG),
|
||||
sizeof(ULONG));
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
&hProfile);
|
||||
ObDereferenceObject(Profile);
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
/* Check for Success */
|
||||
if (!NT_SUCCESS(Status)) {
|
||||
|
||||
/* Dereference Process on failure */
|
||||
if (pProcess) ObDereferenceObject(pProcess);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
if (ProfileSource == ProfileTime)
|
||||
{
|
||||
ULONG ReturnInterval;
|
||||
|
||||
/* FIXME: What units does this use, for now nanoseconds */
|
||||
ReturnInterval = 100;
|
||||
|
||||
_SEH_TRY
|
||||
{
|
||||
*Interval = ReturnInterval;
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
|
||||
/* Copy the created handle back to the caller*/
|
||||
_SEH_TRY {
|
||||
|
||||
*ProfileHandle = hProfile;
|
||||
|
||||
} _SEH_HANDLE {
|
||||
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
return Status;
|
||||
}
|
||||
return STATUS_INVALID_PARAMETER_2;
|
||||
} _SEH_END;
|
||||
|
||||
/* Return Status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtSetIntervalProfile(IN ULONG Interval,
|
||||
IN KPROFILE_SOURCE Source)
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
|
||||
OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
|
||||
{
|
||||
return(STATUS_NOT_IMPLEMENTED);
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
LARGE_INTEGER PerfFrequency;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
/* Check the Parameters for validity */
|
||||
if(PreviousMode != KernelMode) {
|
||||
|
||||
_SEH_TRY {
|
||||
|
||||
ProbeForWrite(PerformanceCounter,
|
||||
sizeof(LARGE_INTEGER),
|
||||
sizeof(ULONG));
|
||||
|
||||
ProbeForWrite(PerformanceFrequency,
|
||||
sizeof(LARGE_INTEGER),
|
||||
sizeof(ULONG));
|
||||
} _SEH_HANDLE {
|
||||
|
||||
Status = _SEH_GetExceptionCode();
|
||||
} _SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
_SEH_TRY {
|
||||
|
||||
/* Query the Kernel */
|
||||
*PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency);
|
||||
|
||||
/* Return Frequency if requested */
|
||||
if(PerformanceFrequency) {
|
||||
|
||||
*PerformanceFrequency = PerfFrequency;
|
||||
}
|
||||
} _SEH_HANDLE {
|
||||
|
||||
Status = _SEH_GetExceptionCode();
|
||||
|
||||
} _SEH_END;
|
||||
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtStartProfile(IN HANDLE ProfileHandle)
|
||||
{
|
||||
PKPROFILE Profile;
|
||||
KPROCESSOR_MODE PreviousMode;
|
||||
NTSTATUS Status;
|
||||
PEPROFILE Profile;
|
||||
PKPROFILE KeProfile;
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
PVOID TempLockedBuffer;
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
PreviousMode = ExGetPreviousMode();
|
||||
PAGED_CODE();
|
||||
|
||||
Status = ObReferenceObjectByHandle(ProfileHandle,
|
||||
STANDARD_RIGHTS_ALL,
|
||||
ExProfileObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&Profile,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
/* Get the Object */
|
||||
Status = ObReferenceObjectByHandle(ProfileHandle,
|
||||
PROFILE_CONTROL,
|
||||
ExProfileObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&Profile,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status)) return(Status);
|
||||
|
||||
/* To avoid a Race, wait on the Mutex */
|
||||
KeWaitForSingleObject(&ExpProfileMutex,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
/* The Profile can still be enabled though, so handle that */
|
||||
if (Profile->LockedBuffer) {
|
||||
|
||||
/* Release our lock, dereference and return */
|
||||
KeReleaseMutex(&ExpProfileMutex, FALSE);
|
||||
ObDereferenceObject(Profile);
|
||||
return STATUS_PROFILING_NOT_STOPPED;
|
||||
}
|
||||
Profile->Started = TRUE;
|
||||
ObDereferenceObject(Profile);
|
||||
return(STATUS_SUCCESS);
|
||||
|
||||
/* Allocate a Kernel Profile Object. */
|
||||
KeProfile = ExAllocatePoolWithTag(NonPagedPool,
|
||||
sizeof(EPROFILE),
|
||||
TAG('P', 'r', 'o', 'f'));
|
||||
|
||||
/* Allocate the Mdl Structure */
|
||||
Profile->Mdl = MmCreateMdl(NULL, Profile->Buffer, Profile->BufferSize);
|
||||
|
||||
/* Probe and Lock for Write Access */
|
||||
MmProbeAndLockPages(Profile->Mdl, PreviousMode, IoWriteAccess);
|
||||
|
||||
/* Map the pages */
|
||||
TempLockedBuffer = MmMapLockedPages(Profile->Mdl, KernelMode);
|
||||
|
||||
/* Initialize the Kernel Profile Object */
|
||||
Profile->KeProfile = KeProfile;
|
||||
KeInitializeProfile(KeProfile,
|
||||
(PKPROCESS)Profile->Process,
|
||||
Profile->ImageBase,
|
||||
Profile->ImageSize,
|
||||
Profile->BucketSize,
|
||||
Profile->ProfileSource,
|
||||
Profile->Affinity);
|
||||
|
||||
/* Start the Profiling */
|
||||
KeStartProfile(KeProfile, TempLockedBuffer);
|
||||
|
||||
/* Now it's safe to save this */
|
||||
Profile->LockedBuffer = TempLockedBuffer;
|
||||
|
||||
/* Release mutex, dereference and return */
|
||||
KeReleaseMutex(&ExpProfileMutex, FALSE);
|
||||
ObDereferenceObject(Profile);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtStopProfile(IN HANDLE ProfileHandle)
|
||||
{
|
||||
PKPROFILE Profile;
|
||||
KPROCESSOR_MODE PreviousMode;
|
||||
NTSTATUS Status;
|
||||
PEPROFILE Profile;
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
NTSTATUS Status;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
PreviousMode = ExGetPreviousMode();
|
||||
PAGED_CODE();
|
||||
|
||||
Status = ObReferenceObjectByHandle(ProfileHandle,
|
||||
STANDARD_RIGHTS_ALL,
|
||||
ExProfileObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&Profile,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
return(Status);
|
||||
/* Get the Object */
|
||||
Status = ObReferenceObjectByHandle(ProfileHandle,
|
||||
PROFILE_CONTROL,
|
||||
ExProfileObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&Profile,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status)) return(Status);
|
||||
|
||||
/* Get the Mutex */
|
||||
KeWaitForSingleObject(&ExpProfileMutex,
|
||||
Executive,
|
||||
KernelMode,
|
||||
FALSE,
|
||||
NULL);
|
||||
|
||||
/* Make sure the Profile Object is really Started */
|
||||
if (!Profile->LockedBuffer) {
|
||||
|
||||
Status = STATUS_PROFILING_NOT_STARTED;
|
||||
goto Exit;
|
||||
}
|
||||
Profile->Started = FALSE;
|
||||
ObDereferenceObject(Profile);
|
||||
return(STATUS_SUCCESS);
|
||||
|
||||
/* Stop the Profile */
|
||||
KeStopProfile(Profile->KeProfile);
|
||||
|
||||
/* Unlock the Buffer */
|
||||
MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
|
||||
MmUnlockPages(Profile->Mdl);
|
||||
ExFreePool(Profile->KeProfile);
|
||||
|
||||
/* Clear the Locked Buffer pointer, meaning the Object is Stopped */
|
||||
Profile->LockedBuffer = NULL;
|
||||
|
||||
Exit:
|
||||
/* Release Mutex, Dereference and Return */
|
||||
KeReleaseMutex(&ExpProfileMutex, FALSE);
|
||||
ObDereferenceObject(Profile);
|
||||
return Status;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
|
||||
OUT PULONG Interval)
|
||||
{
|
||||
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
|
||||
ULONG ReturnInterval;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PAGED_CODE();
|
||||
|
||||
/* Check the Parameters for validity */
|
||||
if(PreviousMode != KernelMode) {
|
||||
|
||||
_SEH_TRY {
|
||||
|
||||
ProbeForWrite(Interval,
|
||||
sizeof(ULONG),
|
||||
sizeof(ULONG));
|
||||
|
||||
} _SEH_HANDLE {
|
||||
|
||||
Status = _SEH_GetExceptionCode();
|
||||
} _SEH_END;
|
||||
|
||||
if(!NT_SUCCESS(Status)) return Status;
|
||||
}
|
||||
|
||||
/* Query the Interval */
|
||||
ReturnInterval = KeQueryIntervalProfile(ProfileSource);
|
||||
|
||||
/* Return the data */
|
||||
_SEH_TRY {
|
||||
|
||||
*Interval = ReturnInterval;
|
||||
|
||||
} _SEH_HANDLE {
|
||||
|
||||
Status = _SEH_GetExceptionCode();
|
||||
|
||||
} _SEH_END;
|
||||
|
||||
/* Return Success */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
STDCALL
|
||||
NtSetIntervalProfile(IN ULONG Interval,
|
||||
IN KPROFILE_SOURCE Source)
|
||||
{
|
||||
/* Let the Kernel do the job */
|
||||
KeSetIntervalProfile(Interval, Source);
|
||||
|
||||
/* Nothing can go wrong */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -65,56 +65,23 @@ KeIpiGenericCall(VOID (STDCALL *WorkerRoutine)(PVOID),
|
|||
|
||||
/* next file ***************************************************************/
|
||||
|
||||
typedef struct _KPROCESS_PROFILE
|
||||
/*
|
||||
* List of the profile data structures associated with a process.
|
||||
*/
|
||||
{
|
||||
LIST_ENTRY ProfileListHead;
|
||||
LIST_ENTRY ListEntry;
|
||||
HANDLE Pid;
|
||||
} KPROCESS_PROFILE, *PKPROCESS_PROFILE;
|
||||
typedef struct _KPROFILE_SOURCE_OBJECT {
|
||||
KPROFILE_SOURCE Source;
|
||||
LIST_ENTRY ListEntry;
|
||||
} KPROFILE_SOURCE_OBJECT, *PKPROFILE_SOURCE_OBJECT;
|
||||
|
||||
typedef struct _KPROFILE
|
||||
/*
|
||||
* Describes a contiguous region of process memory that is being profiled.
|
||||
*/
|
||||
{
|
||||
CSHORT Type;
|
||||
CSHORT Name;
|
||||
|
||||
/* Entry in the list of profile data structures for this process. */
|
||||
LIST_ENTRY ListEntry;
|
||||
|
||||
/* Base of the region being profiled. */
|
||||
PVOID Base;
|
||||
|
||||
/* Size of the region being profiled. */
|
||||
ULONG Size;
|
||||
|
||||
/* Shift of offsets from the region to buckets in the profiling buffer. */
|
||||
ULONG BucketShift;
|
||||
|
||||
/* MDL which described the buffer that receives profiling data. */
|
||||
struct _MDL *BufferMdl;
|
||||
|
||||
/* System alias for the profiling buffer. */
|
||||
PULONG Buffer;
|
||||
|
||||
/* Size of the buffer for profiling data. */
|
||||
ULONG BufferSize;
|
||||
|
||||
/*
|
||||
* Mask of processors for which profiling data should be collected.
|
||||
* Currently unused.
|
||||
*/
|
||||
ULONG ProcessorMask;
|
||||
|
||||
/* TRUE if profiling has been started for this region. */
|
||||
BOOLEAN Started;
|
||||
|
||||
/* Pointer (and reference) to the process which is being profiled. */
|
||||
struct _EPROCESS *Process;
|
||||
typedef struct _KPROFILE {
|
||||
CSHORT Type;
|
||||
CSHORT Size;
|
||||
LIST_ENTRY ListEntry;
|
||||
PVOID RegionStart;
|
||||
PVOID RegionEnd;
|
||||
ULONG BucketShift;
|
||||
PVOID Buffer;
|
||||
CSHORT Source;
|
||||
ULONG Affinity;
|
||||
BOOLEAN Active;
|
||||
struct _KPROCESS *Process;
|
||||
} KPROFILE, *PKPROFILE;
|
||||
|
||||
/* Cached modules from the loader block */
|
||||
|
@ -131,6 +98,34 @@ extern PLOADER_MODULE CachedModules[MaximumCachedModuleType];
|
|||
VOID STDCALL
|
||||
DbgBreakPointNoBugCheck(VOID);
|
||||
|
||||
STDCALL
|
||||
VOID
|
||||
KeInitializeProfile(struct _KPROFILE* Profile,
|
||||
struct _KPROCESS* Process,
|
||||
PVOID ImageBase,
|
||||
ULONG ImageSize,
|
||||
ULONG BucketSize,
|
||||
KPROFILE_SOURCE ProfileSource,
|
||||
KAFFINITY Affinity);
|
||||
|
||||
STDCALL
|
||||
VOID
|
||||
KeStartProfile(struct _KPROFILE* Profile,
|
||||
PVOID Buffer);
|
||||
|
||||
STDCALL
|
||||
VOID
|
||||
KeStopProfile(struct _KPROFILE* Profile);
|
||||
|
||||
STDCALL
|
||||
ULONG
|
||||
KeQueryIntervalProfile(KPROFILE_SOURCE ProfileSource);
|
||||
|
||||
STDCALL
|
||||
VOID
|
||||
KeSetIntervalProfile(KPROFILE_SOURCE ProfileSource,
|
||||
ULONG Interval);
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
KeProfileInterrupt(
|
||||
|
@ -144,8 +139,6 @@ KeProfileInterruptWithSource(
|
|||
IN KPROFILE_SOURCE Source
|
||||
);
|
||||
|
||||
VOID KiAddProfileEventToProcess(PLIST_ENTRY ListHead, PVOID Eip);
|
||||
VOID KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Eip);
|
||||
VOID KiInsertProfileIntoProcess(PLIST_ENTRY ListHead, PKPROFILE Profile);
|
||||
VOID KiInsertProfile(PKPROFILE Profile);
|
||||
VOID KiRemoveProfile(PKPROFILE Profile);
|
||||
|
|
|
@ -410,7 +410,16 @@ IofCompleteRequest(PIRP Irp,
|
|||
|
||||
if (Irp->UserIosb)
|
||||
{
|
||||
*Irp->UserIosb = Irp->IoStatus;
|
||||
_SEH_TRY
|
||||
{
|
||||
*Irp->UserIosb = Irp->IoStatus;
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
DPRINT1("Unable to set UserIosb (at 0x%x) to 0x%x, Error: 0x%x\n",
|
||||
Irp->UserIosb, Irp->IoStatus, _SEH_GetExceptionCode());
|
||||
}
|
||||
_SEH_END;
|
||||
}
|
||||
|
||||
if (Irp->UserEvent)
|
||||
|
|
|
@ -243,12 +243,6 @@ KdInitSystem(ULONG BootPhase,
|
|||
}
|
||||
}
|
||||
}
|
||||
#if defined(KDBG) || defined(DBG)
|
||||
else if (!_strnicmp(p2, "PROFILE", 7) && BootPhase > 0)
|
||||
{
|
||||
KdbInitProfiling();
|
||||
}
|
||||
#endif /* KDBG */
|
||||
p1 = p2;
|
||||
}
|
||||
|
||||
|
|
|
@ -340,9 +340,6 @@ KiInterruptDispatch (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
|
|||
{
|
||||
KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
|
||||
KeUpdateSystemTime(&KernelTrapFrame, old_level);
|
||||
#if defined(KDBG) || defined(DBG)
|
||||
KdbProfileInterrupt(Trapframe->Eip);
|
||||
#endif /* KDBG */
|
||||
}
|
||||
else
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
/* $Id$
|
||||
*
|
||||
/*
|
||||
* COPYRIGHT: See COPYING in the top level directory
|
||||
* PROJECT: ReactOS kernel
|
||||
* FILE: ntoskrnl/ke/profile.c
|
||||
|
@ -8,335 +7,294 @@
|
|||
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||
*/
|
||||
|
||||
/* INCLUDES *****************************************************************/
|
||||
#include <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
extern LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
|
||||
extern LIST_ENTRY SystemProfileList;
|
||||
extern KSPIN_LOCK ProfileListLock;
|
||||
extern BOOLEAN ProfileInitDone;
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
KIRQL KiProfileIrql = PROFILE_LEVEL;
|
||||
LIST_ENTRY KiProfileListHead;
|
||||
LIST_ENTRY KiProfileSourceListHead;
|
||||
KSPIN_LOCK KiProfileLock;
|
||||
ULONG KiProfileTimeInterval = 78125; /* Default resolution 7.8ms (sysinternals) */
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
STDCALL
|
||||
VOID
|
||||
KiAddProfileEventToProcess(PLIST_ENTRY ListHead, PVOID Eip)
|
||||
/*
|
||||
* Add a profile event to the profile objects for a particular process
|
||||
* or the system
|
||||
*/
|
||||
KeInitializeProfile(PKPROFILE Profile,
|
||||
PKPROCESS Process,
|
||||
PVOID ImageBase,
|
||||
ULONG ImageSize,
|
||||
ULONG BucketSize,
|
||||
KPROFILE_SOURCE ProfileSource,
|
||||
KAFFINITY Affinity)
|
||||
{
|
||||
PKPROFILE current;
|
||||
PLIST_ENTRY current_entry;
|
||||
|
||||
current_entry = ListHead->Flink;
|
||||
while (current_entry != ListHead)
|
||||
{
|
||||
current = CONTAINING_RECORD(current_entry, KPROFILE, ListEntry);
|
||||
|
||||
if (current->Base > Eip)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (current->Base <= Eip && ((char*)current->Base + current->Size) > (char*)Eip &&
|
||||
current->Started)
|
||||
{
|
||||
ULONG Bucket;
|
||||
|
||||
Bucket = ((ULONG)((char*)Eip - (char*)current->Base)) >> current->BucketShift;
|
||||
|
||||
if ((Bucket*4) < current->BufferSize)
|
||||
{
|
||||
current->Buffer[Bucket]++;
|
||||
}
|
||||
}
|
||||
|
||||
current_entry = current_entry->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Eip)
|
||||
/*
|
||||
* Add a profile event
|
||||
*/
|
||||
{
|
||||
HANDLE Pid;
|
||||
PKPROCESS_PROFILE current;
|
||||
PLIST_ENTRY current_entry;
|
||||
PLIST_ENTRY ListHead;
|
||||
|
||||
if (!ProfileInitDone)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Pid = PsGetCurrentProcessId();
|
||||
ListHead =
|
||||
ProcessProfileListHashTable[(ULONG)Pid % PROFILE_HASH_TABLE_SIZE].Flink;
|
||||
|
||||
KeAcquireSpinLockAtDpcLevel(&ProfileListLock);
|
||||
|
||||
current_entry = ListHead;
|
||||
while (current_entry != ListHead)
|
||||
{
|
||||
current = CONTAINING_RECORD(current_entry, KPROCESS_PROFILE, ListEntry);
|
||||
|
||||
if (current->Pid == Pid)
|
||||
{
|
||||
KiAddProfileEventToProcess(¤t->ProfileListHead, (PVOID)Eip);
|
||||
break;
|
||||
}
|
||||
|
||||
current_entry = current_entry->Flink;
|
||||
}
|
||||
|
||||
KiAddProfileEventToProcess(&SystemProfileList, (PVOID)Eip);
|
||||
|
||||
KeReleaseSpinLockFromDpcLevel(&ProfileListLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
KiInsertProfileIntoProcess(PLIST_ENTRY ListHead, PKPROFILE Profile)
|
||||
/*
|
||||
* Insert a profile object into the list for a process or the system
|
||||
*/
|
||||
{
|
||||
PKPROFILE current;
|
||||
PLIST_ENTRY current_entry;
|
||||
|
||||
current_entry = ListHead;
|
||||
while (current_entry != ListHead)
|
||||
{
|
||||
current = CONTAINING_RECORD(current_entry, KPROFILE, ListEntry);
|
||||
|
||||
if (current->Base > Profile->Base)
|
||||
{
|
||||
Profile->ListEntry.Flink = current_entry;
|
||||
Profile->ListEntry.Blink = current_entry->Blink;
|
||||
current_entry->Blink->Flink = &Profile->ListEntry;
|
||||
current_entry->Blink = &Profile->ListEntry;
|
||||
return;
|
||||
}
|
||||
|
||||
current_entry = current_entry->Flink;
|
||||
}
|
||||
InsertTailList(ListHead, &Profile->ListEntry);
|
||||
}
|
||||
|
||||
VOID
|
||||
KiInsertProfile(PKPROFILE Profile)
|
||||
/*
|
||||
* Insert a profile into the relevant data structures
|
||||
*/
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&ProfileListLock, &oldIrql);
|
||||
|
||||
if (Profile->Process == NULL)
|
||||
{
|
||||
KiInsertProfileIntoProcess(&SystemProfileList, Profile);
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE Pid;
|
||||
PKPROCESS_PROFILE current;
|
||||
PLIST_ENTRY current_entry;
|
||||
PLIST_ENTRY ListHead;
|
||||
|
||||
Pid = Profile->Process->UniqueProcessId;
|
||||
ListHead = &ProcessProfileListHashTable[(ULONG_PTR)Pid % PROFILE_HASH_TABLE_SIZE];
|
||||
|
||||
current_entry = ListHead;
|
||||
while(current_entry != ListHead)
|
||||
{
|
||||
current = CONTAINING_RECORD(current_entry, KPROCESS_PROFILE,
|
||||
ListEntry);
|
||||
|
||||
if (current->Pid == Pid)
|
||||
{
|
||||
KiInsertProfileIntoProcess(¤t->ProfileListHead, Profile);
|
||||
KeReleaseSpinLock(&ProfileListLock, oldIrql);
|
||||
return;
|
||||
}
|
||||
|
||||
current_entry = current_entry->Flink;
|
||||
}
|
||||
|
||||
current = ExAllocatePool(NonPagedPool, sizeof(KPROCESS_PROFILE));
|
||||
|
||||
current->Pid = Pid;
|
||||
InitializeListHead(¤t->ProfileListHead);
|
||||
InsertTailList(ListHead, ¤t->ListEntry);
|
||||
|
||||
KiInsertProfileIntoProcess(¤t->ProfileListHead, Profile);
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&ProfileListLock, oldIrql);
|
||||
}
|
||||
|
||||
VOID KiRemoveProfile(PKPROFILE Profile)
|
||||
{
|
||||
KIRQL oldIrql;
|
||||
|
||||
KeAcquireSpinLock(&ProfileListLock, &oldIrql);
|
||||
|
||||
if (Profile->Process == NULL)
|
||||
{
|
||||
RemoveEntryList(&Profile->ListEntry);
|
||||
}
|
||||
else
|
||||
{
|
||||
HANDLE Pid;
|
||||
PLIST_ENTRY ListHead;
|
||||
PKPROCESS_PROFILE current;
|
||||
PLIST_ENTRY current_entry;
|
||||
|
||||
RemoveEntryList(&Profile->ListEntry);
|
||||
|
||||
Pid = Profile->Process->UniqueProcessId;
|
||||
ListHead = &ProcessProfileListHashTable[(ULONG_PTR)Pid % PROFILE_HASH_TABLE_SIZE];
|
||||
|
||||
current_entry = ListHead;
|
||||
while(current_entry != ListHead)
|
||||
{
|
||||
current = CONTAINING_RECORD(current_entry, KPROCESS_PROFILE,
|
||||
ListEntry);
|
||||
|
||||
if (current->Pid == Pid)
|
||||
{
|
||||
if (IsListEmpty(¤t->ProfileListHead))
|
||||
{
|
||||
RemoveEntryList(¤t->ListEntry);
|
||||
ExFreePool(current);
|
||||
}
|
||||
KeReleaseSpinLock(&ProfileListLock, oldIrql);
|
||||
return;
|
||||
}
|
||||
|
||||
current_entry = current_entry->Flink;
|
||||
}
|
||||
KEBUGCHECK(0);
|
||||
}
|
||||
|
||||
KeReleaseSpinLock(&ProfileListLock, oldIrql);
|
||||
}
|
||||
|
||||
VOID STDCALL
|
||||
KiDeleteProfile(PVOID ObjectBody)
|
||||
{
|
||||
PKPROFILE Profile;
|
||||
|
||||
Profile = (PKPROFILE)ObjectBody;
|
||||
|
||||
KiRemoveProfile(Profile);
|
||||
if (Profile->Process != NULL)
|
||||
{
|
||||
ObDereferenceObject(Profile->Process);
|
||||
Profile->Process = NULL;
|
||||
}
|
||||
|
||||
if (Profile->BufferMdl->MappedSystemVa != NULL)
|
||||
{
|
||||
MmUnmapLockedPages(Profile->BufferMdl->MappedSystemVa,
|
||||
Profile->BufferMdl);
|
||||
}
|
||||
MmUnlockPages(Profile->BufferMdl);
|
||||
ExFreePool(Profile->BufferMdl);
|
||||
Profile->BufferMdl = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
STDCALL
|
||||
VOID
|
||||
KeProfileInterrupt(
|
||||
PKTRAP_FRAME TrapFrame
|
||||
)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
STDCALL
|
||||
VOID
|
||||
KeProfileInterruptWithSource(
|
||||
IN PKTRAP_FRAME TrapFrame,
|
||||
IN KPROFILE_SOURCE Source
|
||||
)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
STDCALL
|
||||
VOID
|
||||
KeSetProfileIrql(
|
||||
IN KIRQL ProfileIrql
|
||||
)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS STDCALL
|
||||
NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
|
||||
OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
|
||||
{
|
||||
LARGE_INTEGER PerfCounter;
|
||||
LARGE_INTEGER PerfFrequency;
|
||||
KPROCESSOR_MODE PreviousMode;
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
|
||||
PreviousMode = ExGetPreviousMode();
|
||||
|
||||
if(PreviousMode != KernelMode)
|
||||
{
|
||||
_SEH_TRY
|
||||
{
|
||||
ProbeForWrite(PerformanceCounter,
|
||||
sizeof(LARGE_INTEGER),
|
||||
sizeof(ULONG));
|
||||
if(PerformanceFrequency != NULL)
|
||||
{
|
||||
ProbeForWrite(PerformanceFrequency,
|
||||
sizeof(LARGE_INTEGER),
|
||||
sizeof(ULONG));
|
||||
}
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
/* Initialize the Header */
|
||||
Profile->Type = ProfileObject;
|
||||
Profile->Size = sizeof(KPROFILE);
|
||||
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
PerfCounter = KeQueryPerformanceCounter(&PerfFrequency);
|
||||
|
||||
_SEH_TRY
|
||||
{
|
||||
*PerformanceCounter = PerfCounter;
|
||||
if(PerformanceFrequency != NULL)
|
||||
{
|
||||
*PerformanceFrequency = PerfFrequency;
|
||||
}
|
||||
}
|
||||
_SEH_HANDLE
|
||||
{
|
||||
Status = _SEH_GetExceptionCode();
|
||||
}
|
||||
_SEH_END;
|
||||
|
||||
return Status;
|
||||
/* Copy all the settings we were given */
|
||||
Profile->Process = Process;
|
||||
Profile->RegionStart = ImageBase;
|
||||
Profile->BucketShift = BucketSize - 2; /* See ntinternals.net -- Alex */
|
||||
Profile->RegionEnd = (PVOID)(ULONG_PTR)ImageBase + ImageSize;
|
||||
Profile->Active = FALSE;
|
||||
Profile->Source = ProfileSource;
|
||||
Profile->Affinity = Affinity;
|
||||
}
|
||||
|
||||
STDCALL
|
||||
VOID
|
||||
KeStartProfile(PKPROFILE Profile,
|
||||
PVOID Buffer)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PKPROFILE_SOURCE_OBJECT SourceBuffer;
|
||||
PKPROFILE_SOURCE_OBJECT Source = NULL;
|
||||
PKPROFILE_SOURCE_OBJECT CurrentSource;
|
||||
BOOLEAN FreeBuffer = TRUE;
|
||||
PKPROCESS ProfileProcess;
|
||||
PLIST_ENTRY ListEntry;
|
||||
|
||||
/* Allocate a buffer first, before we raise IRQL */
|
||||
SourceBuffer = ExAllocatePoolWithTag(NonPagedPool,
|
||||
sizeof(KPROFILE_SOURCE_OBJECT),
|
||||
TAG('P', 'r', 'o', 'f'));
|
||||
RtlZeroMemory(Source, sizeof(KPROFILE_SOURCE_OBJECT));
|
||||
|
||||
/* Raise to PROFILE_LEVEL */
|
||||
KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
|
||||
KeAcquireSpinLockAtDpcLevel(&KiProfileLock);
|
||||
|
||||
/* Make sure it's not running */
|
||||
if (!Profile->Active) {
|
||||
|
||||
/* Set it as active */
|
||||
Profile->Buffer = Buffer;
|
||||
Profile->Active = TRUE;
|
||||
|
||||
/* Get the process, if any */
|
||||
ProfileProcess = Profile->Process;
|
||||
|
||||
/* Insert it into the Process List or Global List */
|
||||
if (ProfileProcess) {
|
||||
|
||||
InsertTailList(&ProfileProcess->ProfileListHead, &Profile->ListEntry);
|
||||
|
||||
} else {
|
||||
|
||||
InsertTailList(&KiProfileListHead, &Profile->ListEntry);
|
||||
}
|
||||
|
||||
/* Check if this type of profile (source) is already running */
|
||||
for (ListEntry = KiProfileSourceListHead.Flink;
|
||||
ListEntry != &KiProfileSourceListHead;
|
||||
ListEntry = ListEntry->Flink) {
|
||||
|
||||
/* Get the Source Object */
|
||||
CurrentSource = CONTAINING_RECORD(ListEntry,
|
||||
KPROFILE_SOURCE_OBJECT,
|
||||
ListEntry);
|
||||
|
||||
/* Check if it's the same as the one being requested now */
|
||||
if (CurrentSource->Source == Profile->Source) {
|
||||
|
||||
Source = CurrentSource;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* See if the loop found something */
|
||||
if (!Source) {
|
||||
|
||||
/* Nothing found, use our allocated buffer */
|
||||
Source = SourceBuffer;
|
||||
|
||||
/* Set up the Source Object */
|
||||
Source->Source = Profile->Source;
|
||||
InsertHeadList(&KiProfileSourceListHead, &Source->ListEntry);
|
||||
|
||||
/* Don't free the pool later on */
|
||||
FreeBuffer = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Lower the IRQL */
|
||||
KeReleaseSpinLockFromDpcLevel(&KiProfileLock);
|
||||
KeLowerIrql(OldIrql);
|
||||
|
||||
/* FIXME: Tell HAL to Start the Profile Interrupt */
|
||||
//HalStartProfileInterrupt(Profile->Source);
|
||||
|
||||
/* Free the pool */
|
||||
if (!FreeBuffer) ExFreePool(SourceBuffer);
|
||||
}
|
||||
|
||||
STDCALL
|
||||
VOID
|
||||
KeStopProfile(PKPROFILE Profile)
|
||||
{
|
||||
KIRQL OldIrql;
|
||||
PLIST_ENTRY ListEntry;
|
||||
PKPROFILE_SOURCE_OBJECT CurrentSource = NULL;
|
||||
|
||||
/* Raise to PROFILE_LEVEL and acquire spinlock */
|
||||
KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
|
||||
KeAcquireSpinLockAtDpcLevel(&KiProfileLock);
|
||||
|
||||
/* Make sure it's running */
|
||||
if (Profile->Active) {
|
||||
|
||||
/* Remove it from the list and disable */
|
||||
RemoveEntryList(&Profile->ListEntry);
|
||||
Profile->Active = FALSE;
|
||||
|
||||
/* Find the Source Object */
|
||||
for (ListEntry = KiProfileSourceListHead.Flink;
|
||||
CurrentSource->Source != Profile->Source;
|
||||
ListEntry = ListEntry->Flink) {
|
||||
|
||||
/* Get the Source Object */
|
||||
CurrentSource = CONTAINING_RECORD(ListEntry,
|
||||
KPROFILE_SOURCE_OBJECT,
|
||||
ListEntry);
|
||||
}
|
||||
|
||||
/* Remove it */
|
||||
RemoveEntryList(&CurrentSource->ListEntry);
|
||||
}
|
||||
|
||||
/* Lower IRQL */
|
||||
KeReleaseSpinLockFromDpcLevel(&KiProfileLock);
|
||||
KeLowerIrql(OldIrql);
|
||||
|
||||
/* Stop Profiling. FIXME: Implement in HAL */
|
||||
//HalStopProfileInterrupt(Profile->Source);
|
||||
|
||||
/* Free the Source Object */
|
||||
if (CurrentSource) ExFreePool(CurrentSource);
|
||||
}
|
||||
|
||||
STDCALL
|
||||
ULONG
|
||||
KeQueryIntervalProfile(KPROFILE_SOURCE ProfileSource)
|
||||
{
|
||||
/* Check if this is the timer profile */
|
||||
if (ProfileSource == ProfileTime) {
|
||||
|
||||
/* Return the good old 100ns sampling interval */
|
||||
return KiProfileTimeInterval;
|
||||
|
||||
} else {
|
||||
|
||||
/* Request it from HAL. FIXME: What structure is used? */
|
||||
HalQuerySystemInformation(HalProfileSourceInformation,
|
||||
sizeof(NULL),
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
STDCALL
|
||||
VOID
|
||||
KeSetIntervalProfile(KPROFILE_SOURCE ProfileSource,
|
||||
ULONG Interval)
|
||||
{
|
||||
/* Check if this is the timer profile */
|
||||
if (ProfileSource == ProfileTime) {
|
||||
|
||||
/* Set the good old 100ns sampling interval */
|
||||
KiProfileTimeInterval = Interval;
|
||||
|
||||
} else {
|
||||
|
||||
/* Set it with HAL. FIXME: What structure is used? */
|
||||
HalSetSystemInformation(HalProfileSourceInformation,
|
||||
sizeof(NULL),
|
||||
NULL);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
STDCALL
|
||||
VOID
|
||||
KeProfileInterrupt(PKTRAP_FRAME TrapFrame)
|
||||
{
|
||||
/* Called from HAL for Timer Profiling */
|
||||
KeProfileInterruptWithSource(TrapFrame, ProfileTime);
|
||||
}
|
||||
|
||||
VOID
|
||||
STDCALL
|
||||
KiParseProfileList(IN PKTRAP_FRAME TrapFrame,
|
||||
IN KPROFILE_SOURCE Source,
|
||||
IN PLIST_ENTRY ListHead)
|
||||
{
|
||||
PULONG BucketValue;
|
||||
PKPROFILE Profile;
|
||||
PLIST_ENTRY NextEntry;
|
||||
|
||||
/* Loop the List */
|
||||
for (NextEntry = ListHead->Flink; NextEntry != ListHead; NextEntry = NextEntry->Flink) {
|
||||
|
||||
/* Get the Current Profile in the List */
|
||||
Profile = CONTAINING_RECORD(NextEntry, KPROFILE, ListEntry);
|
||||
|
||||
/* Check if the source is good, and if it's within the range */
|
||||
if ((Profile->Source != Source) ||
|
||||
(TrapFrame->Eip < (ULONG_PTR)Profile->RegionStart) ||
|
||||
(TrapFrame->Eip > (ULONG_PTR)Profile->RegionEnd)) {
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Get the Pointer to the Bucket Value representing this EIP */
|
||||
BucketValue = (PULONG)(((ULONG_PTR)(Profile->Buffer +
|
||||
(TrapFrame->Eip - (ULONG_PTR)Profile->RegionStart))
|
||||
>> Profile->BucketShift) &~ 0x3);
|
||||
|
||||
/* Increment the value */
|
||||
++BucketValue;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*
|
||||
* Remarks:
|
||||
* Called from HAL, this function looks up the process
|
||||
* entries, finds the proper source object, verifies the
|
||||
* ranges with the trapframe data, and inserts the information
|
||||
* from the trap frame into the buffer, while using buckets and
|
||||
* shifting like we specified. -- Alex
|
||||
*/
|
||||
STDCALL
|
||||
VOID
|
||||
KeProfileInterruptWithSource(IN PKTRAP_FRAME TrapFrame,
|
||||
IN KPROFILE_SOURCE Source)
|
||||
{
|
||||
PKPROCESS Process = KeGetCurrentThread()->ApcState.Process;
|
||||
|
||||
/* We have to parse 2 lists. Per-Process and System-Wide */
|
||||
KiParseProfileList(TrapFrame, Source, &Process->ProfileListHead);
|
||||
KiParseProfileList(TrapFrame, Source, &KiProfileListHead);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
STDCALL
|
||||
VOID
|
||||
KeSetProfileIrql(IN KIRQL ProfileIrql)
|
||||
{
|
||||
/* Set the IRQL at which Profiling will run */
|
||||
KiProfileIrql = ProfileIrql;
|
||||
}
|
||||
|
|
|
@ -219,7 +219,6 @@ KiExpireTimers(PKDPC Dpc,
|
|||
PVOID SystemArgument1,
|
||||
PVOID SystemArgument2)
|
||||
{
|
||||
ULONG Eip = (ULONG)SystemArgument1;
|
||||
PKTIMER Timer;
|
||||
ULONGLONG InterruptTime;
|
||||
LIST_ENTRY ExpiredTimerList;
|
||||
|
@ -267,8 +266,6 @@ KiExpireTimers(PKDPC Dpc,
|
|||
}
|
||||
|
||||
DPRINT("Timers expired\n");
|
||||
/* Add a Profile Event */
|
||||
KiAddProfileEvent(ProfileTime, Eip);
|
||||
|
||||
/* Release Dispatcher Lock */
|
||||
KeReleaseDispatcherDatabaseLock(OldIrql);
|
||||
|
|
|
@ -152,24 +152,6 @@ ExUuidCreate@4
|
|||
ExVerifySuite@4
|
||||
@ExWaitForRundownProtectionRelease@4
|
||||
ExWindowStationObjectType DATA
|
||||
ExInitializeBinaryTree@12
|
||||
ExDeleteBinaryTree@4
|
||||
ExInsertBinaryTree@12
|
||||
ExSearchBinaryTree@12
|
||||
ExRemoveBinaryTree@12
|
||||
ExTraverseBinaryTree@16
|
||||
ExInitializeSplayTree@16
|
||||
ExDeleteSplayTree@4
|
||||
ExInsertSplayTree@12
|
||||
ExSearchSplayTree@12
|
||||
ExRemoveSplayTree@12
|
||||
ExWeightOfSplayTree@8
|
||||
ExTraverseSplayTree@16
|
||||
ExInitializeHashTable@16
|
||||
ExDeleteHashTable@4
|
||||
ExInsertHashTable@16
|
||||
ExSearchHashTable@16
|
||||
ExRemoveHashTable@16
|
||||
@ExfAcquirePushLockExclusive@4
|
||||
@ExfAcquirePushLockShared@4
|
||||
@ExfReleasePushLock@4
|
||||
|
|
Loading…
Reference in a new issue