From b1ce653a14543b365a32de890086388bb92c73ed Mon Sep 17 00:00:00 2001 From: Thomas Bluemel Date: Sun, 13 Mar 2005 18:41:59 +0000 Subject: [PATCH] Alex Ionescu - 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 --- reactos/ntoskrnl/Makefile | 5 +- reactos/ntoskrnl/dbg/kdb.h | 13 - reactos/ntoskrnl/dbg/profile.c | 478 --------- reactos/ntoskrnl/ex/btree.c | 644 ------------ reactos/ntoskrnl/ex/hashtab.c | 306 ------ reactos/ntoskrnl/ex/profile.c | 726 +++++++------ reactos/ntoskrnl/ex/stree.c | 1339 ------------------------ reactos/ntoskrnl/include/internal/ke.h | 95 +- reactos/ntoskrnl/io/irp.c | 11 +- reactos/ntoskrnl/kd/kdebug.c | 6 - reactos/ntoskrnl/ke/i386/irq.c | 3 - reactos/ntoskrnl/ke/profile.c | 604 +++++------ reactos/ntoskrnl/ke/timer.c | 3 - reactos/ntoskrnl/ntoskrnl.def | 18 - 14 files changed, 738 insertions(+), 3513 deletions(-) delete mode 100755 reactos/ntoskrnl/dbg/profile.c delete mode 100644 reactos/ntoskrnl/ex/btree.c delete mode 100644 reactos/ntoskrnl/ex/hashtab.c delete mode 100644 reactos/ntoskrnl/ex/stree.c diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index 18b781efbad..ac8c7987a52 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -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 \ diff --git a/reactos/ntoskrnl/dbg/kdb.h b/reactos/ntoskrnl/dbg/kdb.h index 0bbbfa2974f..c9b631d51a5 100644 --- a/reactos/ntoskrnl/dbg/kdb.h +++ b/reactos/ntoskrnl/dbg/kdb.h @@ -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) diff --git a/reactos/ntoskrnl/dbg/profile.c b/reactos/ntoskrnl/dbg/profile.c deleted file mode 100755 index 3b2350541b5..00000000000 --- a/reactos/ntoskrnl/dbg/profile.c +++ /dev/null @@ -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 -#include "kdb.h" - -#define NDEBUG -#include - -/* 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); - } -} diff --git a/reactos/ntoskrnl/ex/btree.c b/reactos/ntoskrnl/ex/btree.c deleted file mode 100644 index 6ced8855417..00000000000 --- a/reactos/ntoskrnl/ex/btree.c +++ /dev/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 -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/ex/hashtab.c b/reactos/ntoskrnl/ex/hashtab.c deleted file mode 100644 index 011aec6eb02..00000000000 --- a/reactos/ntoskrnl/ex/hashtab.c +++ /dev/null @@ -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 - * http://burtleburtle.net/bob/hash/doobs.html - */ - -#include - -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/ex/profile.c b/reactos/ntoskrnl/ex/profile.c index 863add88d9e..cb9c86b532d 100644 --- a/reactos/ntoskrnl/ex/profile.c +++ b/reactos/ntoskrnl/ex/profile.c @@ -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 #include -/* 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; +} diff --git a/reactos/ntoskrnl/ex/stree.c b/reactos/ntoskrnl/ex/stree.c deleted file mode 100644 index 14c740dfbcd..00000000000 --- a/reactos/ntoskrnl/ex/stree.c +++ /dev/null @@ -1,1339 +0,0 @@ -/* $Id:$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ex/stree.c - * PURPOSE: Splay tree support - * - * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net) - * - * NOTES: Based on a splay tree implementation by - * Daniel Stenberg - * http://www.contactor.se/~dast/stuff/dsplay-1.2.tar.gz - */ - -#include -#define NDEBUG -#include - -/* DATA **********************************************************************/ - -#define WEIGHT 1 -#undef UNIQUE_KEYS - -typedef struct _SPLAY_TREE_NODE -{ - /* Children on this branch that has smaller keys than this node */ - struct _SPLAY_TREE_NODE * SmallerChild; - - /* Children on this branch that has larger keys than this node */ - struct _SPLAY_TREE_NODE * LargerChild; - - /* Points to a node with identical key */ - struct _SPLAY_TREE_NODE * Same; - - /* Key of this node */ - PVOID Key; - - /* Value of this node */ - PVOID Value; - - /* The number of nodes rooted here */ - LONG Weight; -} SPLAY_TREE_NODE, *PSPLAY_TREE_NODE; - -typedef struct _TRAVERSE_CONTEXT { - PTRAVERSE_ROUTINE Routine; - PVOID Context; -} TRAVERSE_CONTEXT, *PTRAVERSE_CONTEXT; - -#define SPLAY_INDEX 0 -#define SEARCH_INDEX 1 -#define INSERT_INDEX 2 -#define REMOVE_INDEX 3 - -typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_SPLAY)(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node); - -typedef BOOLEAN (*PSPLAY_TREE_SEARCH)(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE * ReturnNode); - -typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_INSERT)(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE New); - -typedef PSPLAY_TREE_NODE (*PSPLAY_TREE_REMOVE)(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE * RemovedNode); - -/* FUNCTIONS ****************************************************************/ - -#define ExpSplayTreeRootNode(Tree)(((PSPLAY_TREE) (Tree))->RootNode) -#define ExpSplayTreeNodeKey(Node)((Node)->Key) -#define ExpSplayTreeNodeValue(Node)((Node)->Value) -#define ExpSplayTreeSmallerChildNode(Node)((Node)->SmallerChild) -#define ExpSplayTreeLargerChildNode(Node)((Node)->LargerChild) -#define ExpSplayTreeNodeEqual(Equality)((Equality) == 0) -#define ExpSplayTreeNodeLess(Equality)((Equality) < 0) -#define ExpSplayTreeNodeMore(Equality)((Equality) > 0) -#define ExpSplayTreeNodeSame(Node)((Node)->Same) -#define ExpSplayTreeNodeWeight(Node)((Node)->Weight) -#define ExpSplayTreeNodeGetWeight(Node)(((Node) == NULL) ? 0 : ((Node)->Weight)) -#define ExpSplayTreeNodeSetWeight(Node, _Weight)((Node)->Weight = (_Weight)) - -#define KEY_NOTUSED (PVOID)-1 - - -/* - * Lock the splay tree - */ -inline VOID -ExpLockSplayTree(PSPLAY_TREE Tree, - PKIRQL OldIrql) -{ - if (Tree->UseNonPagedPool) - { - KeAcquireSpinLock(&Tree->Lock.NonPaged, OldIrql); - } - else - { - ExAcquireFastMutex(&Tree->Lock.Paged); - } -} - - -/* - * Unlock the splay tree - */ -inline VOID -ExpUnlockSplayTree(PSPLAY_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 PSPLAY_TREE_NODE -ExpCreateSplayTreeNode(PSPLAY_TREE Tree, - PVOID Value) -{ - PSPLAY_TREE_NODE Node; - - if (Tree->UseNonPagedPool) - { - Node = (PSPLAY_TREE_NODE) ExAllocateFromNPagedLookasideList(&Tree->List.NonPaged); - } - else - { - Node = (PSPLAY_TREE_NODE) ExAllocateFromPagedLookasideList(&Tree->List.Paged); - } - - if (Node) - { - ExpSplayTreeSmallerChildNode(Node) = NULL; - ExpSplayTreeLargerChildNode(Node) = NULL; - ExpSplayTreeNodeValue(Node) = Value; - } - - return Node; -} - -/* - * Release resources for the node. - */ -inline VOID -ExpDestroySplayTreeNode(PSPLAY_TREE Tree, - PSPLAY_TREE_NODE Node) -{ - if (Tree->UseNonPagedPool) - { - ExFreeToNPagedLookasideList(&Tree->List.NonPaged, Node); - } - else - { - ExFreeToPagedLookasideList(&Tree->List.Paged, Node); - } -} - - -/* - * Splay using the key 'Key' (which may or may not be in the tree). The starting - * root is Node. - * The lock for the tree must be acquired when this routine is called. - * This routine does not maintain weight information. - */ -PSPLAY_TREE_NODE -ExpSplayTreeNoWeight(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node) -{ - PSPLAY_TREE_NODE l; - PSPLAY_TREE_NODE r; - PSPLAY_TREE_NODE y; - LONG ChildEquality; - SPLAY_TREE_NODE N; - LONG Equality; - - if (Node == NULL) - return Node; - - ExpSplayTreeSmallerChildNode(&N) = NULL; - ExpSplayTreeLargerChildNode(&N) = NULL; - l = &N; - r = &N; - - for (;;) - { - Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)); - - if (ExpSplayTreeNodeLess(Equality)) - { - if (ExpSplayTreeSmallerChildNode(Node) == NULL) - break; - - ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeSmallerChildNode(Node))); - if (ExpSplayTreeNodeLess(ChildEquality)) - { - y = ExpSplayTreeSmallerChildNode(Node); /* Rotate smaller */ - ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(y); - ExpSplayTreeLargerChildNode(y) = Node; - - Node = y; - if (ExpSplayTreeSmallerChildNode(Node) == NULL) - break; - } - - ExpSplayTreeSmallerChildNode(r) = Node; /* Link smaller */ - r = Node; - Node = ExpSplayTreeSmallerChildNode(Node); - } - else if (ExpSplayTreeNodeMore(Equality)) - { - if (ExpSplayTreeLargerChildNode(Node) == NULL) - break; - - ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeLargerChildNode(Node))); - if (ExpSplayTreeNodeMore(ChildEquality)) - { - y = ExpSplayTreeLargerChildNode(Node); /* Rotate larger */ - ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(y); - ExpSplayTreeSmallerChildNode(y) = Node; - - Node = y; - if (ExpSplayTreeLargerChildNode(Node) == NULL) - break; - } - - ExpSplayTreeLargerChildNode(l) = Node; /* Link larger */ - l = Node; - Node = ExpSplayTreeLargerChildNode(Node); - } - else - { - break; - } - } - - ExpSplayTreeLargerChildNode(l) = NULL; - ExpSplayTreeSmallerChildNode(r) = NULL; - - ExpSplayTreeLargerChildNode(l) = ExpSplayTreeSmallerChildNode(Node); /* Assemble */ - ExpSplayTreeSmallerChildNode(r) = ExpSplayTreeLargerChildNode(Node); - ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(&N); - ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(&N); - - return Node; -} - - -/* - * Splay using the key 'Key' (which may or may not be in the tree). The starting - * root is Node. - * The lock for the tree must be acquired when this routine is called. - * This routine maintains weight information. - */ -PSPLAY_TREE_NODE -ExpSplayTreeWeight(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node) -{ - PSPLAY_TREE_NODE l; - PSPLAY_TREE_NODE r; - PSPLAY_TREE_NODE y; - LONG ChildEquality; - SPLAY_TREE_NODE N; - LONG Equality; -#ifdef WEIGHT - LONG RootWeight; - LONG Weight1; - LONG Weight2; -#endif - - if (Node == NULL) - return Node; - - ExpSplayTreeSmallerChildNode(&N) = NULL; - ExpSplayTreeLargerChildNode(&N) = NULL; - l = &N; - r = &N; - -#ifdef WEIGHT - RootWeight = ExpSplayTreeNodeGetWeight(Node); - Weight1 = 0; - Weight2 = 0; -#endif - - for (;;) - { - Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)); - - if (ExpSplayTreeNodeLess(Equality)) - { - if (ExpSplayTreeSmallerChildNode(Node) == NULL) - break; - - ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeSmallerChildNode(Node))); - if (ExpSplayTreeNodeLess(ChildEquality)) - { - y = ExpSplayTreeSmallerChildNode(Node); /* Rotate smaller */ - ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(y); - ExpSplayTreeLargerChildNode(y) = Node; - -#ifdef WEIGHT - ExpSplayTreeNodeSetWeight(Node, ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node)) - + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)) + 1); -#endif - - Node = y; - if (ExpSplayTreeSmallerChildNode(Node) == NULL) - break; - } - - ExpSplayTreeSmallerChildNode(r) = Node; /* Link smaller */ - r = Node; - Node = ExpSplayTreeSmallerChildNode(Node); - -#ifdef WEIGHT - Weight2 += 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(r)); -#endif - } - else if (ExpSplayTreeNodeMore(Equality)) - { - if (ExpSplayTreeLargerChildNode(Node) == NULL) - break; - - ChildEquality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(ExpSplayTreeLargerChildNode(Node))); - if (ExpSplayTreeNodeMore(ChildEquality)) - { - y = ExpSplayTreeLargerChildNode(Node); /* Rotate larger */ - ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(y); - ExpSplayTreeSmallerChildNode(y) = Node; - -#ifdef WEIGHT - ExpSplayTreeNodeSetWeight(Node, ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node)) - + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)) + 1); -#endif - - Node = y; - if (ExpSplayTreeLargerChildNode(Node) == NULL) - break; - } - - ExpSplayTreeLargerChildNode(l) = Node; /* Link larger */ - l = Node; - Node = ExpSplayTreeLargerChildNode(Node); - -#ifdef WEIGHT - Weight1 += 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(l)); -#endif - - } - else - { - break; - } - } - -#ifdef WEIGHT - Weight1 += ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node)); /* Now Weight1 and Weight2 are the weights of */ - Weight2 += ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)); /* The 'smaller' and 'larger' trees we just built. */ - ExpSplayTreeNodeSetWeight(Node, Weight1 + Weight2 + 1); -#endif - - ExpSplayTreeLargerChildNode(l) = NULL; - ExpSplayTreeSmallerChildNode(r) = NULL; - -#ifdef WEIGHT - /* The following two loops correct the weight fields of the right path from - * the left child of the root and the right path from the left child of the - * root. - */ - for (y = ExpSplayTreeLargerChildNode(&N); y != NULL; y = ExpSplayTreeLargerChildNode(y)) { - ExpSplayTreeNodeSetWeight(y, Weight1); - Weight1 -= 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(y)); - } - for (y = ExpSplayTreeSmallerChildNode(&N); y != NULL; y = ExpSplayTreeSmallerChildNode(y)) { - ExpSplayTreeNodeSetWeight(y, Weight2); - Weight2 -= 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(y)); - } -#endif - - ExpSplayTreeLargerChildNode(l) = ExpSplayTreeSmallerChildNode(Node); /* Assemble */ - ExpSplayTreeSmallerChildNode(r) = ExpSplayTreeLargerChildNode(Node); - ExpSplayTreeSmallerChildNode(Node) = ExpSplayTreeLargerChildNode(&N); - ExpSplayTreeLargerChildNode(Node) = ExpSplayTreeSmallerChildNode(&N); - - return Node; -} - - -inline PSPLAY_TREE_NODE -ExpSplayTree(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node) -{ - return (*((PSPLAY_TREE_SPLAY)Tree->Reserved[SPLAY_INDEX]))(Tree, Key, Node); -} - - -/* - * The lock for the tree must be acquired when this routine is called. - * This routine does not maintain weight information. - */ -BOOLEAN -ExpSearchSplayTreeNoWeight(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE * ReturnNode) -{ - LONG Equality; - - if (Node == NULL) - return FALSE; - - Node = ExpSplayTree(Tree, Key, Node); - - Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)); - if (ExpSplayTreeNodeEqual(Equality)) - { - /* Found the key */ - - *ReturnNode = Node; - return TRUE; - } - else - { - *ReturnNode = NULL; /* No match */ - return FALSE; /* It wasn't there */ - } -} - - -/* - * The lock for the tree must be acquired when this routine is called. - * This routine maintains weight information. - */ -BOOLEAN -ExpSearchSplayTreeWeight(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE * ReturnNode) -{ - PSPLAY_TREE_NODE x = NULL; - LONG Equality; -#ifdef WEIGHT - LONG tweight; -#endif - - if (Node == NULL) - return FALSE; - -#ifdef WEIGHT - tweight = ExpSplayTreeNodeGetWeight(Node); -#endif - - Node = ExpSplayTree(Tree, Key, Node); - - Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)); - if (ExpSplayTreeNodeEqual(Equality)) - { - /* Found the key */ - -#ifdef WEIGHT - if (x != NULL) - { - ExpSplayTreeNodeSetWeight(x, tweight - 1); - } -#endif - - *ReturnNode = Node; - return TRUE; - } - else - { - *ReturnNode = NULL; /* No match */ - return FALSE; /* It wasn't there */ - } -} - - -inline BOOLEAN -ExpSearchSplayTree(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE * ReturnNode) -{ - return (*((PSPLAY_TREE_SEARCH)Tree->Reserved[SEARCH_INDEX]))(Tree, Key, Node, ReturnNode); -} - - -/* - * The lock for the tree must be acquired when this routine is called. - * This routine does not maintain weight information. - */ -PSPLAY_TREE_NODE -ExpInsertSplayTreeNoWeight(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE New) -{ - if (New == NULL) - return Node; - - if (Node != NULL) - { - LONG Equality; - - Node = ExpSplayTree(Tree, Key, Node); - - Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)); - if (ExpSplayTreeNodeEqual(Equality)) - { - -#ifdef UNIQUE_KEYS - - /* This is how to prevent the same node key getting added twice */ - return NULL; - -#else - - /* It already exists one of this size */ - - ExpSplayTreeNodeSame(New) = Node; - ExpSplayTreeNodeKey(New) = Key; - ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node); - ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node); - - ExpSplayTreeSmallerChildNode(Node) = New; - ExpSplayTreeNodeKey(Node) = KEY_NOTUSED; - - /* New root node */ - return New; - -#endif - - } - } - - if (Node == NULL) - { - ExpSplayTreeSmallerChildNode(New) = NULL; - ExpSplayTreeLargerChildNode(New) = NULL; - } - else if (ExpSplayTreeNodeLess((*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)))) - { - ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node); - ExpSplayTreeLargerChildNode(New) = Node; - ExpSplayTreeSmallerChildNode(Node) = NULL; - } - else - { - ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node); - ExpSplayTreeSmallerChildNode(New) = Node; - ExpSplayTreeLargerChildNode(Node) = NULL; - } - - ExpSplayTreeNodeKey(New) = Key; - -#ifndef UNIQUE_KEYS - /* No identical nodes (yet) */ - ExpSplayTreeNodeSame(New) = NULL; -#endif - - return New; -} - - -/* - * The lock for the tree must be acquired when this routine is called. - * This routine maintains weight information. - */ -PSPLAY_TREE_NODE -ExpInsertSplayTreeWeight(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE New) -{ - if (New == NULL) - return Node; - - if (Node != NULL) - { - LONG Equality; - - Node = ExpSplayTree(Tree, Key, Node); - - Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)); - if (ExpSplayTreeNodeEqual(Equality)) - { - -#ifdef UNIQUE_KEYS - - /* This is how to prevent the same node key getting added twice */ - return NULL; - -#else - - /* It already exists one of this size */ - - ExpSplayTreeNodeSame(New) = Node; - ExpSplayTreeNodeKey(New) = Key; - ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node); - ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node); - -#ifdef WEIGHT - ExpSplayTreeNodeSetWeight(New, ExpSplayTreeNodeGetWeight(Node)); -#endif - - ExpSplayTreeSmallerChildNode(Node) = New; - ExpSplayTreeNodeKey(Node) = KEY_NOTUSED; - - /* New root node */ - return New; - -#endif - - } - } - - if (Node == NULL) - { - ExpSplayTreeSmallerChildNode(New) = NULL; - ExpSplayTreeLargerChildNode(New) = NULL; - } - else if (ExpSplayTreeNodeLess((*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)))) - { - ExpSplayTreeSmallerChildNode(New) = ExpSplayTreeSmallerChildNode(Node); - ExpSplayTreeLargerChildNode(New) = Node; - ExpSplayTreeSmallerChildNode(Node) = NULL; - -#ifdef WEIGHT - ExpSplayTreeNodeSetWeight(Node, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node))); -#endif - - } - else - { - ExpSplayTreeLargerChildNode(New) = ExpSplayTreeLargerChildNode(Node); - ExpSplayTreeSmallerChildNode(New) = Node; - ExpSplayTreeLargerChildNode(Node) = NULL; - -#ifdef WEIGHT - ExpSplayTreeNodeSetWeight(Node, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node))); -#endif - - } - - ExpSplayTreeNodeKey(New) = Key; - -#ifdef WEIGHT - ExpSplayTreeNodeSetWeight(New, 1 + ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(New)) - + ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(New))); -#endif - -#ifndef UNIQUE_KEYS - /* No identical nodes (yet) */ - ExpSplayTreeNodeSame(New) = NULL; -#endif - - return New; -} - - -inline PSPLAY_TREE_NODE -ExpInsertSplayTree(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE New) -{ - return (*((PSPLAY_TREE_INSERT)Tree->Reserved[INSERT_INDEX]))(Tree, Key, Node, New); -} - - -/* - * Deletes the node with key 'Key' from the tree if it's there. - * Return a pointer to the resulting tree. - * The lock for the tree must be acquired when this routine is called. - * This routine does not maintain weight information. - */ -PSPLAY_TREE_NODE -ExpRemoveSplayTreeNoWeight(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE * RemovedNode) -{ - PSPLAY_TREE_NODE x; - LONG Equality; - - if (Node == NULL) - return NULL; - - Node = ExpSplayTree(Tree, Key, Node); - - Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)); - if (ExpSplayTreeNodeEqual(Equality)) - { - /* Found the key */ - -#ifndef UNIQUE_KEYS - /* FIRST! Check if there is a list with identical sizes */ - x = ExpSplayTreeNodeSame(Node); - if (x) - { - /* There is several, pick one from the list */ - - /* 'x' is the new root node */ - - ExpSplayTreeNodeKey(x) = ExpSplayTreeNodeKey(Node); - ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node); - ExpSplayTreeSmallerChildNode(x) = ExpSplayTreeSmallerChildNode(Node); - - *RemovedNode = Node; - return x; - } -#endif - - if (ExpSplayTreeSmallerChildNode(Node) == NULL) - { - x = ExpSplayTreeLargerChildNode(Node); - } - else - { - x = ExpSplayTree(Tree, Key, ExpSplayTreeSmallerChildNode(Node)); - ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node); - } - *RemovedNode = Node; - - return x; - } - else - { - *RemovedNode = NULL; /* No match */ - return Node; /* It wasn't there */ - } -} - - -/* - * Deletes the node with key 'Key' from the tree if it's there. - * Return a pointer to the resulting tree. - * The lock for the tree must be acquired when this routine is called. - * This routine maintains weight information. - */ -PSPLAY_TREE_NODE -ExpRemoveSplayTreeWeight(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE * RemovedNode) -{ - PSPLAY_TREE_NODE x; - LONG Equality; - -#ifdef WEIGHT - LONG tweight; -#endif - - if (Node == NULL) - return NULL; - -#ifdef WEIGHT - tweight = ExpSplayTreeNodeGetWeight(Node); -#endif - - Node = ExpSplayTree(Tree, Key, Node); - - Equality = (*Tree->Compare)(Key, ExpSplayTreeNodeKey(Node)); - if (ExpSplayTreeNodeEqual(Equality)) - { - /* Found the key */ - -#ifndef UNIQUE_KEYS - /* FIRST! Check if there is a list with identical sizes */ - x = ExpSplayTreeNodeSame(Node); - if (x) - { - /* There is several, pick one from the list */ - - /* 'x' is the new root node */ - - ExpSplayTreeNodeKey(x) = ExpSplayTreeNodeKey(Node); - ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node); - ExpSplayTreeSmallerChildNode(x) = ExpSplayTreeSmallerChildNode(Node); - -#ifdef WEIGHT - ExpSplayTreeNodeSetWeight(x, ExpSplayTreeNodeGetWeight(Node)); -#endif - - *RemovedNode = Node; - return x; - } -#endif - - if (ExpSplayTreeSmallerChildNode(Node) == NULL) - { - x = ExpSplayTreeLargerChildNode(Node); - } - else - { - x = ExpSplayTree(Tree, Key, ExpSplayTreeSmallerChildNode(Node)); - ExpSplayTreeLargerChildNode(x) = ExpSplayTreeLargerChildNode(Node); - } - *RemovedNode = Node; - -#ifdef WEIGHT - if (x != NULL) - { - ExpSplayTreeNodeSetWeight(x, tweight - 1); - } -#endif - - return x; - } - else - { - *RemovedNode = NULL; /* No match */ - return Node; /* It wasn't there */ - } -} - - -inline PSPLAY_TREE_NODE -ExpRemoveSplayTree(PSPLAY_TREE Tree, - PVOID Key, - PSPLAY_TREE_NODE Node, - PSPLAY_TREE_NODE * RemovedNode) -{ - return (*((PSPLAY_TREE_REMOVE)Tree->Reserved[REMOVE_INDEX]))(Tree, Key, Node, RemovedNode); -} - - -/* - * The lock for the tree must be acquired when this routine is called. - */ -ULONG -ExpPrintSplayTree(PSPLAY_TREE Tree, - PSPLAY_TREE_NODE Node, - ULONG Distance) -{ - PSPLAY_TREE_NODE n; - ULONG d = 0; - ULONG i; - - if (Node == NULL) - return 0; - - Distance += ExpPrintSplayTree(Tree, ExpSplayTreeLargerChildNode(Node), Distance + 1); - - for (i = 0; i < Distance; i++) - { - DbgPrint(" "); - } - - if (Tree->Weighted) - { - DbgPrint("%d(%d)[%d]", ExpSplayTreeNodeKey(Node), ExpSplayTreeNodeGetWeight(Node), i); - } - else - { - DbgPrint("%d[%d]", ExpSplayTreeNodeKey(Node), i); - } - - for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n)) - { - d += i; - - DbgPrint(" [+]"); - } - - d += i; - - d += ExpPrintSplayTree(Tree, ExpSplayTreeSmallerChildNode(Node), Distance + 1); - - return d; -} - - -#define MAX_DIFF 4 - -#ifdef WEIGHT - -/* - * The lock for the tree must be acquired when this routine is called. - * Returns the new root of the tree. - * Use of this routine could improve performance, or it might not. - * FIXME: Do some performance tests - */ -PSPLAY_TREE_NODE -ExpSplayTreeMaxTreeWeight(PSPLAY_TREE Tree, - PSPLAY_TREE_NODE Node) -{ - PSPLAY_TREE_NODE First = Node; - LONG Diff; - - do - { - Diff = ExpSplayTreeNodeGetWeight(ExpSplayTreeSmallerChildNode(Node)) - - ExpSplayTreeNodeGetWeight(ExpSplayTreeLargerChildNode(Node)); - - if (Diff >= MAX_DIFF) - { - Node = ExpSplayTreeSmallerChildNode(Node); - } - else if (Diff <= -MAX_DIFF) - { - Node = ExpSplayTreeLargerChildNode(Node); - } - else - break; - } while (abs(Diff) >= MAX_DIFF); - - if (Node != First) - return ExpSplayTree(Tree, ExpSplayTreeNodeKey(Node), First); - else - return First; -} - -#endif - - -/* - * Traverse a splay 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 -ExpTraverseSplayTreePreorder(PTRAVERSE_CONTEXT Context, - PSPLAY_TREE_NODE Node) -{ - PSPLAY_TREE_NODE n; - - if (Node == NULL) - return TRUE; - - /* Call the traversal routine */ - if (!(*Context->Routine)(Context->Context, - ExpSplayTreeNodeKey(Node), - ExpSplayTreeNodeValue(Node))) - { - return FALSE; - } - - for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n)) - { - /* Call the traversal routine */ - if (!(*Context->Routine)(Context->Context, - ExpSplayTreeNodeKey(n), - ExpSplayTreeNodeValue(n))) - { - return FALSE; - } - } - - /* Traverse 'smaller' subtree */ - ExpTraverseSplayTreePreorder(Context, ExpSplayTreeSmallerChildNode(Node)); - - /* Traverse 'larger' subtree */ - ExpTraverseSplayTreePreorder(Context, ExpSplayTreeLargerChildNode(Node)); - - return TRUE; -} - - -/* - * Traverse a splay 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 -ExpTraverseSplayTreeInorder(PTRAVERSE_CONTEXT Context, - PSPLAY_TREE_NODE Node) -{ - PSPLAY_TREE_NODE n; - - if (Node == NULL) - return TRUE; - - /* Traverse 'smaller' subtree */ - ExpTraverseSplayTreeInorder(Context, ExpSplayTreeSmallerChildNode(Node)); - - /* Call the traversal routine */ - if (!(*Context->Routine)(Context->Context, - ExpSplayTreeNodeKey(Node), - ExpSplayTreeNodeValue(Node))) - { - return FALSE; - } - - for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n)) - { - /* Call the traversal routine */ - if (!(*Context->Routine)(Context->Context, - ExpSplayTreeNodeKey(n), - ExpSplayTreeNodeValue(n))) - { - return FALSE; - } - } - - /* Traverse right subtree */ - ExpTraverseSplayTreeInorder(Context, ExpSplayTreeLargerChildNode(Node)); - - return TRUE; -} - - -/* - * Traverse a splay 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 -ExpTraverseSplayTreePostorder(PTRAVERSE_CONTEXT Context, - PSPLAY_TREE_NODE Node) -{ - PSPLAY_TREE_NODE n; - - if (Node == NULL) - return TRUE; - - /* Traverse 'smaller' subtree */ - ExpTraverseSplayTreePostorder(Context, ExpSplayTreeSmallerChildNode(Node)); - - /* Traverse 'larger' subtree */ - ExpTraverseSplayTreePostorder(Context, ExpSplayTreeLargerChildNode(Node)); - - /* Call the traversal routine */ - if (!(*Context->Routine)(Context->Context, - ExpSplayTreeNodeKey(Node), - ExpSplayTreeNodeValue(Node))) - { - return FALSE; - } - - for (n = ExpSplayTreeNodeSame(Node); n; n = ExpSplayTreeNodeSame(n)) - { - /* Call the traversal routine */ - if (!(*Context->Routine)(Context->Context, - ExpSplayTreeNodeKey(n), - ExpSplayTreeNodeValue(n))) - { - return FALSE; - } - } - - return TRUE; -} - - -/* - * Default key compare function. Compares the integer values of the two keys. - */ -LONG STDCALL -ExpSplayTreeDefaultCompare(IN PVOID Key1, - IN PVOID Key2) -{ - if (Key1 == Key2) - return 0; - - return (((LONG_PTR) Key1 < (LONG_PTR) Key2) ? -1 : 1); -} - - -/* - * Initializes a splay tree. - */ -BOOLEAN STDCALL -ExInitializeSplayTree(IN PSPLAY_TREE Tree, - IN PKEY_COMPARATOR Compare, - IN BOOLEAN Weighted, - IN BOOLEAN UseNonPagedPool) -{ - RtlZeroMemory(Tree, sizeof(SPLAY_TREE)); - - Tree->Compare = (Compare == NULL) - ? ExpSplayTreeDefaultCompare : Compare; - - Tree->Weighted = Weighted; - - if (Weighted) - { - Tree->Reserved[SPLAY_INDEX] = (PVOID) ExpSplayTreeWeight; - Tree->Reserved[SEARCH_INDEX] = (PVOID) ExpSearchSplayTreeWeight; - Tree->Reserved[INSERT_INDEX] = (PVOID) ExpInsertSplayTreeWeight; - Tree->Reserved[REMOVE_INDEX] = (PVOID) ExpRemoveSplayTreeWeight; - } - else - { - Tree->Reserved[SPLAY_INDEX] = (PVOID) ExpSplayTreeNoWeight; - Tree->Reserved[SEARCH_INDEX] = (PVOID) ExpSearchSplayTreeNoWeight; - Tree->Reserved[INSERT_INDEX] = (PVOID) ExpInsertSplayTreeNoWeight; - Tree->Reserved[REMOVE_INDEX] = (PVOID) ExpRemoveSplayTreeNoWeight; - } - - Tree->UseNonPagedPool = UseNonPagedPool; - - if (UseNonPagedPool) - { - ExInitializeNPagedLookasideList( - &Tree->List.NonPaged, /* Lookaside list */ - NULL, /* Allocate routine */ - NULL, /* Free routine */ - 0, /* Flags */ - sizeof(SPLAY_TREE_NODE), /* Size of each entry */ - TAG('E','X','S','T'), /* Tag */ - 0); /* Depth */ - - KeInitializeSpinLock(&Tree->Lock.NonPaged); - } - else - { - ExInitializePagedLookasideList( - &Tree->List.Paged, /* Lookaside list */ - NULL, /* Allocate routine */ - NULL, /* Free routine */ - 0, /* Flags */ - sizeof(SPLAY_TREE_NODE), /* Size of each entry */ - TAG('E','X','S','T'), /* Tag */ - 0); /* Depth */ - - ExInitializeFastMutex(&Tree->Lock.Paged); - } - - return TRUE; -} - - -/* - * Release resources used by a splay tree. - */ -VOID STDCALL -ExDeleteSplayTree(IN PSPLAY_TREE Tree) -{ - PSPLAY_TREE_NODE RemovedNode; - PSPLAY_TREE_NODE Node; - - /* Remove all nodes */ - Node = ExpSplayTreeRootNode(Tree); - while (Node != NULL) - { - Node = ExpRemoveSplayTree(Tree, Node->Key, Node, &RemovedNode); - - if (RemovedNode != NULL) - { - ExpDestroySplayTreeNode(Tree, RemovedNode); - } - } - - if (Tree->UseNonPagedPool) - { - ExDeleteNPagedLookasideList(&Tree->List.NonPaged); - } - else - { - ExDeletePagedLookasideList(&Tree->List.Paged); - } -} - - -/* - * Insert a value in a splay tree. - */ -VOID STDCALL -ExInsertSplayTree(IN PSPLAY_TREE Tree, - IN PVOID Key, - IN PVOID Value) -{ - PSPLAY_TREE_NODE Node; - PSPLAY_TREE_NODE NewNode; - KIRQL OldIrql; - - /* FIXME: Use SEH for error reporting */ - - NewNode = ExpCreateSplayTreeNode(Tree, Value); - - ExpLockSplayTree(Tree, &OldIrql); - Node = ExpInsertSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), NewNode); - ExpSplayTreeRootNode(Tree) = Node; - ExpUnlockSplayTree(Tree, &OldIrql); -} - - -/* - * Search for a value associated with a given key in a splay tree. - */ -BOOLEAN STDCALL -ExSearchSplayTree(IN PSPLAY_TREE Tree, - IN PVOID Key, - OUT PVOID * Value) -{ - PSPLAY_TREE_NODE Node; - BOOLEAN Status; - KIRQL OldIrql; - - ExpLockSplayTree(Tree, &OldIrql); - Status = ExpSearchSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), &Node); - - if (Status) - { - ExpSplayTreeRootNode(Tree) = Node; - *Value = ExpSplayTreeNodeValue(Node); - ExpUnlockSplayTree(Tree, &OldIrql); - return TRUE; - } - else - { - ExpUnlockSplayTree(Tree, &OldIrql); - return FALSE; - } -} - - -/* - * Remove a value associated with a given key from a splay tree. - */ -BOOLEAN STDCALL -ExRemoveSplayTree(IN PSPLAY_TREE Tree, - IN PVOID Key, - IN PVOID * Value) -{ - PSPLAY_TREE_NODE RemovedNode; - PSPLAY_TREE_NODE Node; - KIRQL OldIrql; - - ExpLockSplayTree(Tree, &OldIrql); - Node = ExpRemoveSplayTree(Tree, Key, ExpSplayTreeRootNode(Tree), &RemovedNode); - ExpSplayTreeRootNode(Tree) = Node; - ExpUnlockSplayTree(Tree, &OldIrql); - - if (RemovedNode != NULL) - { - *Value = ExpSplayTreeNodeValue(RemovedNode); - ExpDestroySplayTreeNode(Tree, RemovedNode); - return TRUE; - } - else - { - return FALSE; - } -} - - -/* - * Return the weight of the root node in the splay tree. - * The returned value is the number of nodes in the tree. - */ -BOOLEAN STDCALL -ExWeightOfSplayTree(IN PSPLAY_TREE Tree, - OUT PULONG Weight) -{ - KIRQL OldIrql; - - ExpLockSplayTree(Tree, &OldIrql); - - if (!Tree->Weighted) - { - ExpUnlockSplayTree(Tree, &OldIrql); - return FALSE; - } - - *Weight = ExpSplayTreeNodeWeight(ExpSplayTreeRootNode(Tree)); - ExpUnlockSplayTree(Tree, &OldIrql); - - return TRUE; -} - - -/* - * Traverse a splay 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 -ExTraverseSplayTree(IN PSPLAY_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; - - ExpLockSplayTree(Tree, &OldIrql); - - if (ExpSplayTreeRootNode(Tree) == NULL) - { - ExpUnlockSplayTree(Tree, &OldIrql); - return TRUE; - } - - switch (Method) - { - case TraverseMethodPreorder: - Status = ExpTraverseSplayTreePreorder(&tc, ExpSplayTreeRootNode(Tree)); - break; - - case TraverseMethodInorder: - Status = ExpTraverseSplayTreeInorder(&tc, ExpSplayTreeRootNode(Tree)); - break; - - case TraverseMethodPostorder: - Status = ExpTraverseSplayTreePostorder(&tc, ExpSplayTreeRootNode(Tree)); - break; - - default: - Status = FALSE; - break; - } - - ExpUnlockSplayTree(Tree, &OldIrql); - - return Status; -} - -/* EOF */ diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index a25b2f8a7d6..a89cd9784ea 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -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); diff --git a/reactos/ntoskrnl/io/irp.c b/reactos/ntoskrnl/io/irp.c index ed98e86d973..7f3a7701689 100644 --- a/reactos/ntoskrnl/io/irp.c +++ b/reactos/ntoskrnl/io/irp.c @@ -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) diff --git a/reactos/ntoskrnl/kd/kdebug.c b/reactos/ntoskrnl/kd/kdebug.c index bc403f3cab0..8c6e357fad0 100644 --- a/reactos/ntoskrnl/kd/kdebug.c +++ b/reactos/ntoskrnl/kd/kdebug.c @@ -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; } diff --git a/reactos/ntoskrnl/ke/i386/irq.c b/reactos/ntoskrnl/ke/i386/irq.c index 865dd302fcb..22d269b69ac 100644 --- a/reactos/ntoskrnl/ke/i386/irq.c +++ b/reactos/ntoskrnl/ke/i386/irq.c @@ -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 diff --git a/reactos/ntoskrnl/ke/profile.c b/reactos/ntoskrnl/ke/profile.c index 454e15c3afc..cb2279bf878 100644 --- a/reactos/ntoskrnl/ke/profile.c +++ b/reactos/ntoskrnl/ke/profile.c @@ -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 #define NDEBUG #include -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; } diff --git a/reactos/ntoskrnl/ke/timer.c b/reactos/ntoskrnl/ke/timer.c index c46db9ddcff..44f7b19b34a 100644 --- a/reactos/ntoskrnl/ke/timer.c +++ b/reactos/ntoskrnl/ke/timer.c @@ -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); diff --git a/reactos/ntoskrnl/ntoskrnl.def b/reactos/ntoskrnl/ntoskrnl.def index 9444fe08006..956d20c43ae 100644 --- a/reactos/ntoskrnl/ntoskrnl.def +++ b/reactos/ntoskrnl/ntoskrnl.def @@ -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