Alex Ionescu <ionucu@videotron.ca>

- Fix implementation of NT Profile Objects. Structures are guesses, but seem pretty close to the NT ones... a lot of stuff based on David Welch's old implementation, but simplified the way profiles are managed extensively, and also using the same buckethash mechanism as NT, this is required for compatibility with Nt Native APIs that use Profile Objects.
- Removed KDBG internal profile management and associated files. I will re-write the Profiler to use NT Profile Objects, which will allow us more extensibilty while profiling and also greater compatibility with NT.

svn path=/trunk/; revision=14022
This commit is contained in:
Thomas Bluemel 2005-03-13 18:41:59 +00:00
parent b607cb6445
commit b1ce653a14
14 changed files with 738 additions and 3513 deletions

View file

@ -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 \

View file

@ -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)

View file

@ -1,478 +0,0 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/dbg/profile.c
* PURPOSE: Kernel profiling
*
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#include "kdb.h"
#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS *****************************************************************/
#define PROFILE_SESSION_LENGTH 30 /* Session length in seconds */
typedef struct _PROFILE_DATABASE_ENTRY
{
ULONG_PTR Address;
} PROFILE_DATABASE_ENTRY, *PPROFILE_DATABASE_ENTRY;
#define PDE_BLOCK_ENTRIES ((PAGE_SIZE - (sizeof(LIST_ENTRY) + sizeof(ULONG))) / sizeof(PROFILE_DATABASE_ENTRY))
typedef struct _PROFILE_DATABASE_BLOCK
{
LIST_ENTRY ListEntry;
ULONG UsedEntries;
PROFILE_DATABASE_ENTRY Entries[PDE_BLOCK_ENTRIES];
} PROFILE_DATABASE_BLOCK, *PPROFILE_DATABASE_BLOCK;
typedef struct _PROFILE_DATABASE
{
LIST_ENTRY ListHead;
} PROFILE_DATABASE, *PPROFILE_DATABASE;
typedef struct _SAMPLE_GROUP_INFO
{
ULONG_PTR Address;
ULONG Count;
CHAR Description[128];
LIST_ENTRY ListEntry;
} SAMPLE_GROUP_INFO, *PSAMPLE_GROUP_INFO;
static volatile BOOLEAN KdbProfilingInitialized = FALSE;
static volatile BOOLEAN KdbProfilingEnabled = FALSE;
static volatile BOOLEAN KdbProfilingSuspended = FALSE;
static PPROFILE_DATABASE KdbProfileDatabase = NULL;
static KDPC KdbProfilerCollectorDpc;
static HANDLE KdbProfilerThreadHandle;
static CLIENT_ID KdbProfilerThreadCid;
static HANDLE KdbProfilerLogFile;
static KTIMER KdbProfilerTimer;
static KMUTEX KdbProfilerLock;
static BOOLEAN KdbEnableProfiler = FALSE;
VOID
KdbDeleteProfileDatabase(PPROFILE_DATABASE ProfileDatabase)
{
PLIST_ENTRY current = NULL;
current = RemoveHeadList(&ProfileDatabase->ListHead);
while (current != &ProfileDatabase->ListHead)
{
PPROFILE_DATABASE_BLOCK block = CONTAINING_RECORD(
current, PROFILE_DATABASE_BLOCK, ListEntry);
ExFreePool(block);
current = RemoveHeadList(&ProfileDatabase->ListHead);
}
}
VOID
KdbAddEntryToProfileDatabase(PPROFILE_DATABASE ProfileDatabase, ULONG_PTR Address)
{
PPROFILE_DATABASE_BLOCK block;
if (IsListEmpty(&ProfileDatabase->ListHead))
{
block = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE_BLOCK));
ASSERT(block);
block->UsedEntries = 0;
InsertTailList(&ProfileDatabase->ListHead, &block->ListEntry);
block->Entries[block->UsedEntries++].Address = Address;
return;
}
block = CONTAINING_RECORD(ProfileDatabase->ListHead.Blink, PROFILE_DATABASE_BLOCK, ListEntry);
if (block->UsedEntries >= PDE_BLOCK_ENTRIES)
{
block = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE_BLOCK));
ASSERT(block);
block->UsedEntries = 0;
InsertTailList(&ProfileDatabase->ListHead, &block->ListEntry);
}
block->Entries[block->UsedEntries++].Address = Address;
}
VOID INIT_FUNCTION
KdbInitProfiling()
{
KdbEnableProfiler = TRUE;
}
VOID INIT_FUNCTION
KdbInitProfiling2()
{
if (KdbEnableProfiler)
{
KdbEnableProfiling();
KdbProfilingInitialized = TRUE;
}
}
VOID
KdbSuspendProfiling()
{
KdbProfilingSuspended = TRUE;
}
VOID
KdbResumeProfiling()
{
KdbProfilingSuspended = FALSE;
}
BOOLEAN
KdbProfilerGetSymbolInfo(PVOID address, OUT PCH NameBuffer)
{
PLIST_ENTRY current_entry;
MODULE_TEXT_SECTION* current;
extern LIST_ENTRY ModuleTextListHead;
ULONG_PTR RelativeAddress;
NTSTATUS Status;
CHAR FileName[256];
CHAR FunctionName[256];
current_entry = ModuleTextListHead.Flink;
while (current_entry != &ModuleTextListHead &&
current_entry != NULL)
{
current =
CONTAINING_RECORD(current_entry, MODULE_TEXT_SECTION, ListEntry);
if (address >= (PVOID)current->Base &&
address < (PVOID)(current->Base + current->Length))
{
RelativeAddress = (ULONG_PTR) address - current->Base;
Status = KdbSymGetAddressInformation(current->RosSymInfo,
RelativeAddress,
NULL,
FileName,
FunctionName);
if (NT_SUCCESS(Status))
{
sprintf(NameBuffer, "%s (%s)", FunctionName, FileName);
return(TRUE);
}
return(TRUE);
}
current_entry = current_entry->Flink;
}
return(FALSE);
}
PLIST_ENTRY
KdbProfilerLargestSampleGroup(PLIST_ENTRY SamplesListHead)
{
PLIST_ENTRY current;
PLIST_ENTRY largest;
ULONG count;
count = 0;
largest = SamplesListHead->Flink;
current = SamplesListHead->Flink;
while (current != SamplesListHead)
{
PSAMPLE_GROUP_INFO sgi = CONTAINING_RECORD(
current, SAMPLE_GROUP_INFO, ListEntry);
if (sgi->Count > count)
{
largest = current;
count = sgi->Count;
}
current = current->Flink;
}
if (count == 0)
{
return NULL;
}
return largest;
}
VOID
KdbProfilerWriteString(PCH String)
{
IO_STATUS_BLOCK Iosb;
NTSTATUS Status;
ULONG Length;
Length = strlen(String);
Status = NtWriteFile(KdbProfilerLogFile,
NULL,
NULL,
NULL,
&Iosb,
String,
Length,
NULL,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtWriteFile() failed with status 0x%.08x\n", Status);
}
}
NTSTATUS
KdbProfilerWriteSampleGroups(PLIST_ENTRY SamplesListHead)
{
CHAR Buffer[256];
PLIST_ENTRY current = NULL;
PLIST_ENTRY Largest;
KdbProfilerWriteString("\r\n\r\n");
KdbProfilerWriteString("Count Symbol\r\n");
KdbProfilerWriteString("--------------------------------------------------\r\n");
current = SamplesListHead->Flink;
while (current != SamplesListHead)
{
Largest = KdbProfilerLargestSampleGroup(SamplesListHead);
if (Largest != NULL)
{
PSAMPLE_GROUP_INFO sgi = CONTAINING_RECORD(
Largest, SAMPLE_GROUP_INFO, ListEntry);
//DbgPrint("%.08lu %s\n", sgi->Count, sgi->Description);
sprintf(Buffer, "%.08lu %s\r\n", sgi->Count, sgi->Description);
KdbProfilerWriteString(Buffer);
RemoveEntryList(Largest);
ExFreePool(sgi);
}
else
{
break;
}
current = SamplesListHead->Flink;
}
return STATUS_SUCCESS;
}
LONG STDCALL
KdbProfilerKeyCompare(IN PVOID Key1,
IN PVOID Key2)
{
int value = strcmp(Key1, Key2);
if (value == 0)
return 0;
return (value < 0) ? -1 : 1;
}
NTSTATUS
KdbProfilerAnalyzeSamples()
{
CHAR NameBuffer[512];
ULONG KeyLength;
PLIST_ENTRY current = NULL;
HASH_TABLE Hashtable;
LIST_ENTRY SamplesListHead;
ULONG Index;
ULONG_PTR Address;
if (!ExInitializeHashTable(&Hashtable, 12, KdbProfilerKeyCompare, TRUE))
{
DPRINT1("ExInitializeHashTable() failed.");
KEBUGCHECK(0);
}
InitializeListHead(&SamplesListHead);
current = RemoveHeadList(&KdbProfileDatabase->ListHead);
while (current != &KdbProfileDatabase->ListHead)
{
PPROFILE_DATABASE_BLOCK block;
block = CONTAINING_RECORD(current, PROFILE_DATABASE_BLOCK, ListEntry);
for (Index = 0; Index < block->UsedEntries; Index++)
{
PSAMPLE_GROUP_INFO sgi;
Address = block->Entries[Index].Address;
if (KdbProfilerGetSymbolInfo((PVOID) Address, (PCH) &NameBuffer))
{
}
else
{
sprintf(NameBuffer, "(0x%.08lx)", (ULONG) Address);
}
KeyLength = strlen(NameBuffer);
if (!ExSearchHashTable(&Hashtable, (PVOID) NameBuffer, KeyLength, (PVOID *) &sgi))
{
sgi = ExAllocatePool(NonPagedPool, sizeof(SAMPLE_GROUP_INFO));
ASSERT(sgi);
sgi->Address = Address;
sgi->Count = 1;
strcpy(sgi->Description, NameBuffer);
InsertTailList(&SamplesListHead, &sgi->ListEntry);
ExInsertHashTable(&Hashtable, sgi->Description, KeyLength, (PVOID) sgi);
}
else
{
sgi->Count++;
}
}
ExFreePool(block);
current = RemoveHeadList(&KdbProfileDatabase->ListHead);
}
KdbProfilerWriteSampleGroups(&SamplesListHead);
ExDeleteHashTable(&Hashtable);
KdbDeleteProfileDatabase(KdbProfileDatabase);
return STATUS_SUCCESS;
}
VOID STDCALL
KdbProfilerThreadMain(PVOID Context)
{
for (;;)
{
KeWaitForSingleObject(&KdbProfilerTimer, Executive, KernelMode, TRUE, NULL);
KeWaitForSingleObject(&KdbProfilerLock, Executive, KernelMode, FALSE, NULL);
KdbSuspendProfiling();
KdbProfilerAnalyzeSamples();
KdbResumeProfiling();
KeReleaseMutex(&KdbProfilerLock, FALSE);
}
}
VOID
KdbDisableProfiling()
{
if (KdbProfilingEnabled == TRUE)
{
/* FIXME: Implement */
#if 0
KdbProfilingEnabled = FALSE;
/* Stop timer */
/* Close file */
if (KdbProfileDatabase != NULL)
{
KdbDeleteProfileDatabase(KdbProfileDatabase);
ExFreePool(KdbProfileDatabase);
KdbProfileDatabase = NULL;
}
#endif
}
}
/*
* SystemArgument1 = EIP
*/
static VOID STDCALL
KdbProfilerCollectorDpcRoutine(PKDPC Dpc, PVOID DeferredContext,
PVOID SystemArgument1, PVOID SystemArgument2)
{
ULONG_PTR address = (ULONG_PTR) SystemArgument1;
KdbAddEntryToProfileDatabase(KdbProfileDatabase, address);
}
VOID INIT_FUNCTION
KdbEnableProfiling()
{
if (KdbProfilingEnabled == FALSE)
{
NTSTATUS Status;
OBJECT_ATTRIBUTES ObjectAttributes;
UNICODE_STRING FileName;
IO_STATUS_BLOCK Iosb;
LARGE_INTEGER DueTime;
RtlInitUnicodeString(&FileName, L"\\SystemRoot\\profiler.log");
InitializeObjectAttributes(&ObjectAttributes,
&FileName,
0,
NULL,
NULL);
Status = NtCreateFile(&KdbProfilerLogFile,
FILE_ALL_ACCESS,
&ObjectAttributes,
&Iosb,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_SUPERSEDE,
FILE_WRITE_THROUGH | FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create profiler log file\n");
return;
}
KeInitializeMutex(&KdbProfilerLock, 0);
KdbProfileDatabase = ExAllocatePool(NonPagedPool, sizeof(PROFILE_DATABASE));
ASSERT(KdbProfileDatabase);
InitializeListHead(&KdbProfileDatabase->ListHead);
KeInitializeDpc(&KdbProfilerCollectorDpc, KdbProfilerCollectorDpcRoutine, NULL);
/* Initialize our periodic timer and its associated DPC object. When the timer
expires, the KdbProfilerSessionEndDpc deferred procedure call (DPC) is queued */
KeInitializeTimerEx(&KdbProfilerTimer, SynchronizationTimer);
Status = PsCreateSystemThread(&KdbProfilerThreadHandle,
THREAD_ALL_ACCESS,
NULL,
NULL,
&KdbProfilerThreadCid,
KdbProfilerThreadMain,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT1("Failed to create profiler thread\n");
return;
}
/* Start the periodic timer with an initial and periodic
relative expiration time of PROFILE_SESSION_LENGTH seconds */
DueTime.QuadPart = -(LONGLONG) PROFILE_SESSION_LENGTH * 1000 * 10000;
KeSetTimerEx(&KdbProfilerTimer, DueTime, PROFILE_SESSION_LENGTH * 1000, NULL);
KdbProfilingEnabled = TRUE;
}
}
VOID
KdbProfileInterrupt(ULONG_PTR Address)
{
ASSERT(KeGetCurrentIrql() == PROFILE_LEVEL);
if (KdbProfilingInitialized != TRUE)
{
return;
}
if ((KdbProfilingEnabled) && (!KdbProfilingSuspended))
{
(BOOLEAN) KeInsertQueueDpc(&KdbProfilerCollectorDpc, (PVOID) Address, NULL);
}
}

View file

@ -1,644 +0,0 @@
/* $Id:$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ex/btree.c
* PURPOSE: Binary tree support
*
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* DATA **********************************************************************/
typedef struct _BINARY_TREE_NODE
{
struct _BINARY_TREE_NODE * Parent;
struct _BINARY_TREE_NODE * LeftChild;
struct _BINARY_TREE_NODE * RightChild;
PVOID Key;
PVOID Value;
} BINARY_TREE_NODE, *PBINARY_TREE_NODE;
typedef struct _TRAVERSE_CONTEXT {
PTRAVERSE_ROUTINE Routine;
PVOID Context;
} TRAVERSE_CONTEXT, *PTRAVERSE_CONTEXT;
/* FUNCTIONS ****************************************************************/
#define ExpBinaryTreeRootNode(Tree)(((PBINARY_TREE) (Tree))->RootNode)
#define ExpBinaryTreeIsExternalNode(Node)(((Node)->LeftChild == NULL) && ((Node)->RightChild == NULL))
#define ExpBinaryTreeIsInternalNode(Node)(!ExpBinaryTreeIsExternalNode(Node))
#define ExpBinaryTreeNodeKey(Node)((Node)->Key)
#define ExpBinaryTreeNodeValue(Node)((Node)->Value)
#define ExpBinaryTreeParentNode(Node)((Node)->Parent)
#define ExpBinaryTreeLeftChildNode(Node)((Node)->LeftChild)
#define ExpBinaryTreeRightChildNode(Node)((Node)->RightChild)
#define ExpBinaryTreeNodeEqual(Equality)((Equality) == 0)
#define ExpBinaryTreeNodeLess(Equality)((Equality) < 0)
#define ExpBinaryTreeNodeMore(Equality)((Equality) > 0)
/*
* Lock the binary tree
*/
inline VOID
ExpLockBinaryTree(PBINARY_TREE Tree,
PKIRQL OldIrql)
{
if (Tree->UseNonPagedPool)
{
KeAcquireSpinLock(&Tree->Lock.NonPaged, OldIrql);
}
else
{
ExAcquireFastMutex(&Tree->Lock.Paged);
}
}
/*
* Unlock the binary tree
*/
inline VOID
ExpUnlockBinaryTree(PBINARY_TREE Tree,
PKIRQL OldIrql)
{
if (Tree->UseNonPagedPool)
{
KeReleaseSpinLock(&Tree->Lock.NonPaged, *OldIrql);
}
else
{
ExReleaseFastMutex(&Tree->Lock.Paged);
}
}
/*
* Allocate resources for a new node and initialize it.
*/
inline PBINARY_TREE_NODE
ExpCreateBinaryTreeNode(PBINARY_TREE Tree,
PBINARY_TREE_NODE Parent,
PVOID Value)
{
PBINARY_TREE_NODE Node;
if (Tree->UseNonPagedPool)
{
Node = (PBINARY_TREE_NODE) ExAllocateFromNPagedLookasideList(&Tree->List.NonPaged);
}
else
{
Node = (PBINARY_TREE_NODE) ExAllocateFromPagedLookasideList(&Tree->List.Paged);
}
if (Node)
{
ExpBinaryTreeParentNode(Node) = Parent;
ExpBinaryTreeLeftChildNode(Node) = NULL;
ExpBinaryTreeRightChildNode(Node) = NULL;
ExpBinaryTreeNodeValue(Node) = Value;
}
return Node;
}
/*
* Release resources for the node.
*/
inline VOID
ExpDestroyBinaryTreeNode(PBINARY_TREE Tree,
PBINARY_TREE_NODE Node)
{
if (Tree->UseNonPagedPool)
{
ExFreeToNPagedLookasideList(&Tree->List.NonPaged, Node);
}
else
{
ExFreeToPagedLookasideList(&Tree->List.Paged, Node);
}
}
/*
* Replaces a child node of a node with a new node.
* The lock for the tree must be acquired when this routine is called.
*/
inline VOID
ExpBinaryTreeReplaceChildNode(PBINARY_TREE_NODE Child,
PBINARY_TREE_NODE NewChild)
{
if (ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Child)) == Child)
{
ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Child)) = NewChild;
}
else
{
ExpBinaryTreeRightChildNode(ExpBinaryTreeParentNode(Child)) = NewChild;
}
}
/*
* Returns the sibling node of a node.
* The lock for the tree must be acquired when this routine is called.
*/
inline PBINARY_TREE_NODE
ExpSiblingBinaryTreeNode(PBINARY_TREE Tree,
PBINARY_TREE_NODE Node)
{
if (Node == ExpBinaryTreeRootNode(Tree))
{
return NULL;
}
else
{
if (ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Node)) == Node)
{
return ExpBinaryTreeRightChildNode(ExpBinaryTreeParentNode(Node));
}
else
{
return ExpBinaryTreeLeftChildNode(ExpBinaryTreeParentNode(Node));
}
}
}
/*
* Expands an external node to an internal node.
* The lock for the tree must be acquired when this routine is called.
*/
VOID
ExpExpandExternalBinaryTreeNode(PBINARY_TREE Tree,
PBINARY_TREE_NODE Node)
{
ExpBinaryTreeLeftChildNode(Node) = ExpCreateBinaryTreeNode(Tree, Node, NULL);
if (!ExpBinaryTreeLeftChildNode(Node))
{
/* FIXME: Throw exception */
DbgPrint("ExpCreateBinaryTreeNode() failed\n");
}
ExpBinaryTreeRightChildNode(Node) = ExpCreateBinaryTreeNode(Tree, Node, NULL);
if (!ExpBinaryTreeRightChildNode(Node))
{
ExpDestroyBinaryTreeNode(Tree, ExpBinaryTreeLeftChildNode(Node));
/* FIXME: Throw exception */
DbgPrint("ExpCreateBinaryTreeNode() failed\n");
}
}
/*
* Searches a tree for a node with the specified key. If a node with the
* specified key is not found, the external node where it should be is
* returned.
* The lock for the tree must be acquired when this routine is called.
*/
inline PBINARY_TREE_NODE
ExpSearchBinaryTree(PBINARY_TREE Tree,
PVOID Key,
PBINARY_TREE_NODE Node)
{
LONG Equality;
/* FIXME: Possibly do this iteratively due to the small kernel-mode stack */
if (ExpBinaryTreeIsExternalNode(Node))
{
return Node;
}
Equality = (*Tree->Compare)(Key, ExpBinaryTreeNodeKey(Node));
if (ExpBinaryTreeNodeEqual(Equality))
{
return Node;
}
if (ExpBinaryTreeNodeLess(Equality))
{
return ExpSearchBinaryTree(Tree, Key, ExpBinaryTreeLeftChildNode(Node));
}
/* if (ExpBinaryTreeNodeMore(Equality)) */
{
return ExpSearchBinaryTree(Tree, Key, ExpBinaryTreeRightChildNode(Node));
}
}
/*
* Removes an external node and it's parent node from the tree.
* The lock for the tree must be acquired when this routine is called.
*/
VOID
ExpRemoveAboveExternalBinaryTreeNode(PBINARY_TREE Tree,
PBINARY_TREE_NODE Node)
{
ASSERTMSG(ExpBinaryTreeIsExternalNode(Node), ("Node is not external"));
if (Node == ExpBinaryTreeRootNode(Tree))
{
return;
}
else
{
PBINARY_TREE_NODE GrandParent;
PBINARY_TREE_NODE NewChild;
GrandParent = ExpBinaryTreeParentNode(ExpBinaryTreeParentNode(Node));
NewChild = ExpSiblingBinaryTreeNode(Tree, Node);
if (GrandParent != NULL)
{
ExpBinaryTreeReplaceChildNode(ExpBinaryTreeParentNode(Node), NewChild);
}
ExpDestroyBinaryTreeNode(Tree, ExpBinaryTreeParentNode(Node));
ExpDestroyBinaryTreeNode(Tree, Node);
}
}
/*
* Release resources used by nodes of a binary (sub)tree.
*/
VOID
ExpDeleteBinaryTree(PBINARY_TREE Tree,
PBINARY_TREE_NODE Node)
{
/* FIXME: Possibly do this iteratively due to the small kernel-mode stack */
if (ExpBinaryTreeIsInternalNode(Node))
{
ExpDeleteBinaryTree(Tree, ExpBinaryTreeLeftChildNode(Node));
ExpDeleteBinaryTree(Tree, ExpBinaryTreeRightChildNode(Node));
}
ExpDestroyBinaryTreeNode(Tree, Node);
}
/*
* Traverse a binary tree using preorder traversal method.
* Returns FALSE, if the traversal was terminated prematurely or
* TRUE if the callback routine did not request that the traversal
* be terminated prematurely.
* The lock for the tree must be acquired when this routine is called.
*/
BOOLEAN
ExpTraverseBinaryTreePreorder(PTRAVERSE_CONTEXT Context,
PBINARY_TREE_NODE Node)
{
if (ExpBinaryTreeIsInternalNode(Node))
{
/* Call the traversal routine */
if (!(*Context->Routine)(Context->Context,
ExpBinaryTreeNodeKey(Node),
ExpBinaryTreeNodeValue(Node)))
{
return FALSE;
}
/* Traverse left subtree */
ExpTraverseBinaryTreePreorder(Context, ExpBinaryTreeLeftChildNode(Node));
/* Traverse right subtree */
ExpTraverseBinaryTreePreorder(Context, ExpBinaryTreeRightChildNode(Node));
}
return TRUE;
}
/*
* Traverse a binary tree using inorder traversal method.
* Returns FALSE, if the traversal was terminated prematurely or
* TRUE if the callback routine did not request that the traversal
* be terminated prematurely.
* The lock for the tree must be acquired when this routine is called.
*/
BOOLEAN
ExpTraverseBinaryTreeInorder(PTRAVERSE_CONTEXT Context,
PBINARY_TREE_NODE Node)
{
if (ExpBinaryTreeIsInternalNode(Node))
{
/* Traverse left subtree */
ExpTraverseBinaryTreeInorder(Context, ExpBinaryTreeLeftChildNode(Node));
/* Call the traversal routine */
if (!(*Context->Routine)(Context->Context,
ExpBinaryTreeNodeKey(Node),
ExpBinaryTreeNodeValue(Node)))
{
return FALSE;
}
/* Traverse right subtree */
ExpTraverseBinaryTreeInorder(Context, ExpBinaryTreeRightChildNode(Node));
}
return TRUE;
}
/*
* Traverse a binary tree using postorder traversal method.
* Returns FALSE, if the traversal was terminated prematurely or
* TRUE if the callback routine did not request that the traversal
* be terminated prematurely.
* The lock for the tree must be acquired when this routine is called.
*/
BOOLEAN
ExpTraverseBinaryTreePostorder(PTRAVERSE_CONTEXT Context,
PBINARY_TREE_NODE Node)
{
if (ExpBinaryTreeIsInternalNode(Node))
{
/* Traverse left subtree */
ExpTraverseBinaryTreePostorder(Context, ExpBinaryTreeLeftChildNode(Node));
/* Traverse right subtree */
ExpTraverseBinaryTreePostorder(Context, ExpBinaryTreeRightChildNode(Node));
/* Call the traversal routine */
return (*Context->Routine)(Context->Context,
ExpBinaryTreeNodeKey(Node),
ExpBinaryTreeNodeValue(Node));
}
return TRUE;
}
/*
* Default key compare function. Compares the integer values of the two keys.
*/
LONG STDCALL
ExpBinaryTreeDefaultCompare(PVOID Key1,
PVOID Key2)
{
if (Key1 == Key2)
return 0;
return (((LONG_PTR) Key1 < (LONG_PTR) Key2) ? -1 : 1);
}
/*
* Initializes a binary tree.
*/
BOOLEAN STDCALL
ExInitializeBinaryTree(IN PBINARY_TREE Tree,
IN PKEY_COMPARATOR Compare,
IN BOOLEAN UseNonPagedPool)
{
RtlZeroMemory(Tree, sizeof(BINARY_TREE));
Tree->Compare = (Compare == NULL)
? ExpBinaryTreeDefaultCompare : Compare;
Tree->UseNonPagedPool = UseNonPagedPool;
if (UseNonPagedPool)
{
ExInitializeNPagedLookasideList(
&Tree->List.NonPaged, /* Lookaside list */
NULL, /* Allocate routine */
NULL, /* Free routine */
0, /* Flags */
sizeof(BINARY_TREE_NODE), /* Size of each entry */
TAG('E','X','B','T'), /* Tag */
0); /* Depth */
KeInitializeSpinLock(&Tree->Lock.NonPaged);
}
else
{
ExInitializePagedLookasideList(
&Tree->List.Paged, /* Lookaside list */
NULL, /* Allocate routine */
NULL, /* Free routine */
0, /* Flags */
sizeof(BINARY_TREE_NODE), /* Size of each entry */
TAG('E','X','B','T'), /* Tag */
0); /* Depth */
ExInitializeFastMutex(&Tree->Lock.Paged);
}
ExpBinaryTreeRootNode(Tree) = ExpCreateBinaryTreeNode(Tree, NULL, NULL);
if (ExpBinaryTreeRootNode(Tree) == NULL)
{
if (UseNonPagedPool)
{
ExDeleteNPagedLookasideList(&Tree->List.NonPaged);
}
else
{
ExDeletePagedLookasideList(&Tree->List.Paged);
}
return FALSE;
}
else
{
return TRUE;
}
}
/*
* Release resources used by a binary tree.
*/
VOID STDCALL
ExDeleteBinaryTree(IN PBINARY_TREE Tree)
{
/* Remove all nodes */
ExpDeleteBinaryTree(Tree, ExpBinaryTreeRootNode(Tree));
if (Tree->UseNonPagedPool)
{
ExDeleteNPagedLookasideList(&Tree->List.NonPaged);
}
else
{
ExDeletePagedLookasideList(&Tree->List.Paged);
}
}
/*
* Insert a value in a binary tree.
*/
VOID STDCALL
ExInsertBinaryTree(IN PBINARY_TREE Tree,
IN PVOID Key,
IN PVOID Value)
{
PBINARY_TREE_NODE Node;
KIRQL OldIrql;
/* FIXME: Use SEH for error reporting */
ExpLockBinaryTree(Tree, &OldIrql);
Node = ExpBinaryTreeRootNode(Tree);
do
{
Node = ExpSearchBinaryTree(Tree, Key, Node);
if (ExpBinaryTreeIsExternalNode(Node))
{
break;
}
else
{
Node = ExpBinaryTreeRightChildNode(Node);
}
} while (TRUE);
ExpExpandExternalBinaryTreeNode(Tree, Node);
ExpBinaryTreeNodeKey(Node) = Key;
ExpBinaryTreeNodeValue(Node) = Value;
ExpUnlockBinaryTree(Tree, &OldIrql);
}
/*
* Search for a value associated with a given key in a binary tree.
*/
BOOLEAN STDCALL
ExSearchBinaryTree(IN PBINARY_TREE Tree,
IN PVOID Key,
OUT PVOID * Value)
{
PBINARY_TREE_NODE Node;
KIRQL OldIrql;
ExpLockBinaryTree(Tree, &OldIrql);
Node = ExpSearchBinaryTree(Tree, Key, ExpBinaryTreeRootNode(Tree));
if (ExpBinaryTreeIsInternalNode(Node))
{
*Value = ExpBinaryTreeNodeValue(Node);
ExpUnlockBinaryTree(Tree, &OldIrql);
return TRUE;
}
else
{
ExpUnlockBinaryTree(Tree, &OldIrql);
return FALSE;
}
}
/*
* Remove a value associated with a given key from a binary tree.
*/
BOOLEAN STDCALL
ExRemoveBinaryTree(IN PBINARY_TREE Tree,
IN PVOID Key,
IN PVOID * Value)
{
PBINARY_TREE_NODE Node;
KIRQL OldIrql;
ExpLockBinaryTree(Tree, &OldIrql);
Node = ExpSearchBinaryTree(Tree, Key, ExpBinaryTreeRootNode(Tree));
if (ExpBinaryTreeIsExternalNode(Node))
{
ExpUnlockBinaryTree(Tree, &OldIrql);
return FALSE;
}
else
{
*Value = ExpBinaryTreeNodeValue(Node);
if (ExpBinaryTreeIsExternalNode(ExpBinaryTreeLeftChildNode(Node)))
{
Node = ExpBinaryTreeLeftChildNode(Node);
}
else if (ExpBinaryTreeIsExternalNode(ExpBinaryTreeRightChildNode(Node)))
{
Node = ExpBinaryTreeRightChildNode(Node);
}
else
{
// Node has internal children
PBINARY_TREE_NODE SwapNode;
SwapNode = Node;
Node = ExpBinaryTreeRightChildNode(SwapNode);
do
{
Node = ExpBinaryTreeLeftChildNode(Node);
} while (ExpBinaryTreeIsInternalNode(Node));
}
ExpRemoveAboveExternalBinaryTreeNode(Tree, Node);
ExpUnlockBinaryTree(Tree, &OldIrql);
return TRUE;
}
}
/*
* Traverse a binary tree using either preorder, inorder or postorder
* traversal method.
* Returns FALSE, if the traversal was terminated prematurely or
* TRUE if the callback routine did not request that the traversal
* be terminated prematurely.
*/
BOOLEAN STDCALL
ExTraverseBinaryTree(IN PBINARY_TREE Tree,
IN TRAVERSE_METHOD Method,
IN PTRAVERSE_ROUTINE Routine,
IN PVOID Context)
{
TRAVERSE_CONTEXT tc;
BOOLEAN Status;
KIRQL OldIrql;
tc.Routine = Routine;
tc.Context = Context;
ExpLockBinaryTree(Tree, &OldIrql);
switch (Method)
{
case TraverseMethodPreorder:
Status = ExpTraverseBinaryTreePreorder(&tc, ExpBinaryTreeRootNode(Tree));
break;
case TraverseMethodInorder:
Status = ExpTraverseBinaryTreeInorder(&tc, ExpBinaryTreeRootNode(Tree));
break;
case TraverseMethodPostorder:
Status = ExpTraverseBinaryTreePostorder(&tc, ExpBinaryTreeRootNode(Tree));
break;
default:
Status = FALSE;
break;
}
ExpUnlockBinaryTree(Tree, &OldIrql);
return Status;
}
/* EOF */

View file

@ -1,306 +0,0 @@
/* $Id:$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ex/hashtab.c
* PURPOSE: Hash table support
*
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
/*
* NOTES: The hash function is from:
* Bob Jenkins <bob_jenkins@burtleburtle.net>
* http://burtleburtle.net/bob/hash/doobs.html
*/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS ****************************************************************/
#define ExpHashTableSize(n) ((ULONG)1 << (n))
#define ExpHashTableMask(n) (ExpHashTableSize(n) - 1)
#define ExpHashMix(a, b, c) \
{ \
a -= b; a -= c; a ^= (c >> 13); \
b -= c; b -= a; b ^= (a << 8); \
c -= a; c -= b; c ^= (b >> 13); \
a -= b; a -= c; a ^= (c >> 12); \
b -= c; b -= a; b ^= (a << 16); \
c -= a; c -= b; c ^= (b >> 5); \
a -= b; a -= c; a ^= (c >> 3); \
b -= c; b -= a; b ^= (a << 10); \
c -= a; c -= b; c ^= (b >> 15); \
}
ULONG
ExpHash(PUCHAR Key,
ULONG KeyLength)
{
register ULONG a, b, c, len;
/* Set up the internal state */
len = KeyLength;
a = b = 0x9e3779b9; /* The golden ratio; an arbitrary value */
c = 0;
/* Handle most of the key */
while (len >= 12)
{
a += (Key[0] + ((ULONG)Key[1]<<8) + ((ULONG)Key[2]<<16) + ((ULONG)Key[3]<<24));
b += (Key[4] + ((ULONG)Key[5]<<8) + ((ULONG)Key[6]<<16) + ((ULONG)Key[7]<<24));
c += (Key[8] + ((ULONG)Key[9]<<8) + ((ULONG)Key[10]<<16)+ ((ULONG)Key[11]<<24));
ExpHashMix(a, b, c);
Key += 12; len -= 12;
}
/* Handle the last 11 bytes */
c += KeyLength;
switch(len) /* All the case statements fall through */
{
case 11: c += ((ULONG)Key[10] << 24);
case 10: c += ((ULONG)Key[9] << 16);
case 9 : c += ((ULONG)Key[8] << 8);
/* The first byte of c is reserved for the length */
case 8 : b += ((ULONG)Key[7] << 24);
case 7 : b += ((ULONG)Key[6] << 16);
case 6 : b += ((ULONG)Key[5] << 8);
case 5 : b += Key[4];
case 4 : a += ((ULONG)Key[3] << 24);
case 3 : a += ((ULONG)Key[2] << 16);
case 2 : a += ((ULONG)Key[1] << 8);
case 1 : a += Key[0];
/* case 0: nothing left to add */
}
ExpHashMix(a, b, c);
return c;
}
/*
* Lock the hash table
*/
inline VOID
ExpLockHashTable(PHASH_TABLE HashTable,
PKIRQL OldIrql)
{
if (HashTable->UseNonPagedPool)
{
KeAcquireSpinLock(&HashTable->Lock.NonPaged, OldIrql);
}
else
{
ExAcquireFastMutex(&HashTable->Lock.Paged);
}
}
/*
* Unlock the hash table
*/
inline VOID
ExpUnlockHashTable(PHASH_TABLE HashTable,
PKIRQL OldIrql)
{
if (HashTable->UseNonPagedPool)
{
KeReleaseSpinLock(&HashTable->Lock.NonPaged, *OldIrql);
}
else
{
ExReleaseFastMutex(&HashTable->Lock.Paged);
}
}
/*
* Insert a value in a hash table.
*/
inline VOID STDCALL
ExpInsertHashTable(IN PHASH_TABLE HashTable,
IN PVOID Key,
IN ULONG KeyLength,
IN PVOID Value)
{
ULONG Index;
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
ExInsertSplayTree(&HashTable->HashTrees[Index], Key, Value);
}
/*
* Search for a value associated with a given key in a hash table.
*/
inline BOOLEAN STDCALL
ExpSearchHashTable(IN PHASH_TABLE HashTable,
IN PVOID Key,
IN ULONG KeyLength,
OUT PVOID * Value)
{
ULONG Index;
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
return ExSearchSplayTree(&HashTable->HashTrees[Index], Key, Value);
}
/*
* Remove a value associated with a given key from a hash table.
*/
BOOLEAN STDCALL
ExpRemoveHashTable(IN PHASH_TABLE HashTable,
IN PVOID Key,
IN ULONG KeyLength,
IN PVOID * Value)
{
ULONG Index;
Index = (ExpHash(Key, KeyLength) & ExpHashTableMask(HashTable->HashTableSize));
return ExRemoveSplayTree(&HashTable->HashTrees[Index], Key, Value);
}
/*
* Initializes a hash table.
*/
BOOLEAN STDCALL
ExInitializeHashTable(IN PHASH_TABLE HashTable,
IN ULONG HashTableSize,
IN PKEY_COMPARATOR Compare OPTIONAL,
IN BOOLEAN UseNonPagedPool)
{
BOOLEAN Status;
ULONG Index;
RtlZeroMemory(HashTable, sizeof(HASH_TABLE));
HashTable->HashTableSize = HashTableSize;
HashTable->UseNonPagedPool = UseNonPagedPool;
if (UseNonPagedPool)
{
KeInitializeSpinLock(&HashTable->Lock.NonPaged);
HashTable->HashTrees = ExAllocatePool(NonPagedPool, ExpHashTableSize(HashTableSize) * sizeof(SPLAY_TREE));
}
else
{
ExInitializeFastMutex(&HashTable->Lock.Paged);
HashTable->HashTrees = ExAllocatePool(PagedPool, ExpHashTableSize(HashTableSize) * sizeof(SPLAY_TREE));
}
if (HashTable->HashTrees == NULL)
{
return FALSE;
}
for (Index = 0; Index < ExpHashTableSize(HashTableSize); Index++)
{
Status = ExInitializeSplayTree(&HashTable->HashTrees[Index], Compare, FALSE, UseNonPagedPool);
if (!Status)
{
LONG i;
for (i = Index - 1; i >= 0; i--)
{
ExDeleteSplayTree(&HashTable->HashTrees[i]);
}
ExFreePool(HashTable->HashTrees);
return FALSE;
}
}
return TRUE;
}
/*
* Release resources used by a hash table.
*/
VOID STDCALL
ExDeleteHashTable(IN PHASH_TABLE HashTable)
{
ULONG Index;
for (Index = 0; Index < ExpHashTableSize(HashTable->HashTableSize); Index++)
{
ExDeleteSplayTree(&HashTable->HashTrees[Index]);
}
ExFreePool(HashTable->HashTrees);
}
/*
* Insert a value in a hash table.
*/
VOID STDCALL
ExInsertHashTable(IN PHASH_TABLE HashTable,
IN PVOID Key,
IN ULONG KeyLength,
IN PVOID Value)
{
KIRQL OldIrql;
/* FIXME: Use SEH for error reporting */
ExpLockHashTable(HashTable, &OldIrql);
ExpInsertHashTable(HashTable, Key, KeyLength, Value);
ExpUnlockHashTable(HashTable, &OldIrql);
}
/*
* Search for a value associated with a given key in a hash table.
*/
BOOLEAN STDCALL
ExSearchHashTable(IN PHASH_TABLE HashTable,
IN PVOID Key,
IN ULONG KeyLength,
OUT PVOID * Value)
{
BOOLEAN Status;
KIRQL OldIrql;
ExpLockHashTable(HashTable, &OldIrql);
Status = ExpSearchHashTable(HashTable, Key, KeyLength, Value);
ExpUnlockHashTable(HashTable, &OldIrql);
return Status;
}
/*
* Remove a value associated with a given key from a hash table.
*/
BOOLEAN STDCALL
ExRemoveHashTable(IN PHASH_TABLE HashTable,
IN PVOID Key,
IN ULONG KeyLength,
IN PVOID * Value)
{
BOOLEAN Status;
KIRQL OldIrql;
ExpLockHashTable(HashTable, &OldIrql);
Status = ExpRemoveHashTable(HashTable, Key, KeyLength, Value);
ExpUnlockHashTable(HashTable, &OldIrql);
return Status;
}
/* EOF */

View file

@ -1,11 +1,10 @@
/* $Id:$
*
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/nt/profile.c
* PURPOSE: Support for profiling
* FILE: ntoskrnl/ex/profile.c
* PURPOSE: Support for Executive Profile Objects
*
* PROGRAMMERS: No programmer listed.
* PROGRAMMERS: Alex Ionescu
*/
/* INCLUDES *****************************************************************/
@ -13,369 +12,448 @@
#include <ntoskrnl.h>
#include <internal/debug.h>
/* TYPES ********************************************************************/
/* This structure is a *GUESS* -- Alex */
typedef struct _EPROFILE {
PEPROCESS Process;
PVOID ImageBase;
ULONG ImageSize;
ULONG BucketSize;
PVOID Buffer;
ULONG BufferSize;
PKPROFILE KeProfile;
KPROFILE_SOURCE ProfileSource;
KAFFINITY Affinity;
PMDL Mdl;
PVOID LockedBuffer;
} EPROFILE, *PEPROFILE;
/* GLOBALS *******************************************************************/
POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
static KMUTEX ExpProfileMutex;
#define PROFILE_CONTROL 1
static GENERIC_MAPPING ExpProfileMapping = {
STANDARD_RIGHTS_READ,
STANDARD_RIGHTS_WRITE,
STANDARD_RIGHTS_EXECUTE,
STANDARD_RIGHTS_ALL};
STANDARD_RIGHTS_READ | PROFILE_CONTROL,
STANDARD_RIGHTS_WRITE | PROFILE_CONTROL,
STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
STANDARD_RIGHTS_ALL};
/*
* Size of the profile hash table.
*/
#define PROFILE_HASH_TABLE_SIZE (32)
VOID
STDCALL
ExpDeleteProfile(PVOID ObjectBody)
{
PEPROFILE Profile;
/*
* Table of lists of per-process profiling data structures hashed by PID.
*/
LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
/* Typecast the Object */
Profile = (PEPROFILE)ObjectBody;
/* Check if there if the Profile was started */
if (Profile->LockedBuffer) {
/* Stop the Profile */
KeStopProfile(Profile->KeProfile);
/* Unmap the Locked Buffer */
MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
MmUnlockPages(Profile->Mdl);
ExFreePool(Profile->Mdl);
}
/* Check if a Process is associated */
if (Profile->Process != NULL) {
/* Dereference it */
ObDereferenceObject(Profile->Process);
Profile->Process = NULL;
}
}
/*
* Head of the list of profile data structures for the kernel.
*/
LIST_ENTRY SystemProfileList;
/*
* Lock that protects the profiling data structures.
*/
KSPIN_LOCK ProfileListLock;
/*
* Timer interrupts happen before we have initialized the profiling
* data structures so just ignore them before that.
*/
BOOLEAN ProfileInitDone = FALSE;
VOID INIT_FUNCTION
VOID
INIT_FUNCTION
ExpInitializeProfileImplementation(VOID)
{
ULONG i;
InitializeListHead(&SystemProfileList);
for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++)
{
InitializeListHead(&ProcessProfileListHashTable[i]);
}
KeInitializeSpinLock(&ProfileListLock);
ProfileInitDone = TRUE;
ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
RtlpCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile", NonPagedPool);
ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
ExProfileObjectType->PeakObjects = 0;
ExProfileObjectType->PeakHandles = 0;
ExProfileObjectType->TotalObjects = 0;
ExProfileObjectType->TotalHandles = 0;
ExProfileObjectType->PagedPoolCharge = 0;
ExProfileObjectType->NonpagedPoolCharge = sizeof(KPROFILE);
ExProfileObjectType->Mapping = &ExpProfileMapping;
ExProfileObjectType->Dump = NULL;
ExProfileObjectType->Open = NULL;
ExProfileObjectType->Close = NULL;
ExProfileObjectType->Delete = KiDeleteProfile;
ExProfileObjectType->Parse = NULL;
ExProfileObjectType->Security = NULL;
ExProfileObjectType->QueryName = NULL;
ExProfileObjectType->OkayToClose = NULL;
ExProfileObjectType->Create = NULL;
ObpCreateTypeObject(ExProfileObjectType);
/* Initialize the Mutex to lock the States */
KeInitializeMutex(&ExpProfileMutex, 0x40);
/* Create the Object Type */
ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
RtlInitUnicodeString(&ExProfileObjectType->TypeName, L"Profile");
ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
ExProfileObjectType->PeakObjects = 0;
ExProfileObjectType->PeakHandles = 0;
ExProfileObjectType->TotalObjects = 0;
ExProfileObjectType->TotalHandles = 0;
ExProfileObjectType->PagedPoolCharge = 0;
ExProfileObjectType->NonpagedPoolCharge = sizeof(EPROFILE);
ExProfileObjectType->Mapping = &ExpProfileMapping;
ExProfileObjectType->Dump = NULL;
ExProfileObjectType->Open = NULL;
ExProfileObjectType->Close = NULL;
ExProfileObjectType->Delete = ExpDeleteProfile;
ExProfileObjectType->Parse = NULL;
ExProfileObjectType->Security = NULL;
ExProfileObjectType->QueryName = NULL;
ExProfileObjectType->OkayToClose = NULL;
ExProfileObjectType->Create = NULL;
ObpCreateTypeObject(ExProfileObjectType);
}
NTSTATUS STDCALL
NTSTATUS
STDCALL
NtCreateProfile(OUT PHANDLE ProfileHandle,
IN HANDLE Process OPTIONAL,
IN PVOID ImageBase,
IN ULONG ImageSize,
IN ULONG BucketSize,
IN PVOID Buffer,
IN ULONG BufferSize,
IN KPROFILE_SOURCE ProfileSource,
IN KAFFINITY Affinity)
IN HANDLE Process OPTIONAL,
IN PVOID ImageBase,
IN ULONG ImageSize,
IN ULONG BucketSize,
IN PVOID Buffer,
IN ULONG BufferSize,
IN KPROFILE_SOURCE ProfileSource,
IN KAFFINITY Affinity)
{
HANDLE hProfile;
PKPROFILE Profile;
PEPROCESS pProcess;
KPROCESSOR_MODE PreviousMode;
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status = STATUS_SUCCESS;
HANDLE hProfile;
PEPROFILE Profile;
PEPROCESS pProcess;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
if(BufferSize == 0)
{
return STATUS_INVALID_PARAMETER_7;
}
if(PreviousMode != KernelMode)
{
_SEH_TRY
{
ProbeForWrite(ProfileHandle,
sizeof(HANDLE),
sizeof(ULONG));
ProbeForWrite(Buffer,
BufferSize,
sizeof(ULONG));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
PAGED_CODE();
/* Easy way out */
if(BufferSize == 0) return STATUS_INVALID_PARAMETER_7;
/* Check the Parameters for validity */
if(PreviousMode != KernelMode) {
_SEH_TRY {
ProbeForWrite(ProfileHandle,
sizeof(HANDLE),
sizeof(ULONG));
ProbeForWrite(Buffer,
BufferSize,
sizeof(ULONG));
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
} _SEH_END;
if(!NT_SUCCESS(Status))
{
return Status;
}
}
/*
* Reference the associated process
*/
if (Process != NULL)
{
Status = ObReferenceObjectByHandle(Process,
PROCESS_QUERY_INFORMATION,
PsProcessType,
PreviousMode,
(PVOID*)&pProcess,
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
}
}
else
{
pProcess = NULL;
if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege,
PreviousMode))
{
DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
if(!NT_SUCCESS(Status)) return Status;
}
/*
* Check the parameters
*/
if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) ||
(pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE))
{
return(STATUS_INVALID_PARAMETER_3);
}
if (((ImageSize >> BucketSize) * 4) >= BufferSize)
{
return(STATUS_BUFFER_TOO_SMALL);
}
if (ProfileSource != ProfileTime)
{
return(STATUS_INVALID_PARAMETER_9);
}
if (Affinity != 0)
{
return(STATUS_INVALID_PARAMETER_10);
/* Check if a process was specified */
if (Process) {
/* Reference it */
Status = ObReferenceObjectByHandle(Process,
PROCESS_QUERY_INFORMATION,
PsProcessType,
PreviousMode,
(PVOID*)&pProcess,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
} else {
/* No process was specified, which means a System-Wide Profile */
pProcess = NULL;
/* For this, we need to check the Privilege */
if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode)) {
DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
}
/*
* Create the object
*/
InitializeObjectAttributes(&ObjectAttributes,
/* Create the object */
InitializeObjectAttributes(&ObjectAttributes,
NULL,
0,
NULL,
NULL);
Status = ObCreateObject(KernelMode,
ExProfileObjectType,
&ObjectAttributes,
PreviousMode,
NULL,
sizeof(EPROFILE),
0,
0,
(PVOID*)&Profile);
if (!NT_SUCCESS(Status)) return(Status);
/* Initialize it */
Profile->ImageBase = ImageBase;
Profile->ImageSize = ImageSize;
Profile->Buffer = Buffer;
Profile->BufferSize = BufferSize;
Profile->BucketSize = BucketSize;
Profile->LockedBuffer = NULL;
Profile->Affinity = Affinity;
Profile->Process = pProcess;
/* Insert into the Object Tree */
Status = ObInsertObject ((PVOID)Profile,
NULL,
PROFILE_CONTROL,
0,
NULL,
NULL);
Status = ObCreateObject(KernelMode,
ExProfileObjectType,
&ObjectAttributes,
PreviousMode,
NULL,
sizeof(KPROFILE),
0,
0,
(PVOID*)&Profile);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/*
* Initialize it
*/
Profile->Base = ImageBase;
Profile->Size = ImageSize;
Profile->BucketShift = BucketSize;
Profile->BufferMdl = MmCreateMdl(NULL, Buffer, BufferSize);
if(Profile->BufferMdl == NULL) {
DPRINT("MmCreateMdl: Out of memory!");
ObDereferenceObject (Profile);
return(STATUS_NO_MEMORY);
}
MmProbeAndLockPages(Profile->BufferMdl, UserMode, IoWriteAccess);
Profile->Buffer = MmGetSystemAddressForMdl(Profile->BufferMdl);
Profile->BufferSize = BufferSize;
Profile->ProcessorMask = Affinity;
Profile->Started = FALSE;
Profile->Process = pProcess;
/*
* Insert the profile into the profile list data structures
*/
KiInsertProfile(Profile);
Status = ObInsertObject ((PVOID)Profile,
NULL,
STANDARD_RIGHTS_ALL,
0,
NULL,
&hProfile);
if (!NT_SUCCESS(Status))
{
ObDereferenceObject (Profile);
return Status;
}
/*
* Copy the created handle back to the caller
*/
_SEH_TRY
{
*ProfileHandle = hProfile;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
ObDereferenceObject(Profile);
return Status;
}
NTSTATUS STDCALL
NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
OUT PULONG Interval)
{
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
if(PreviousMode != KernelMode)
{
_SEH_TRY
{
ProbeForWrite(Interval,
sizeof(ULONG),
sizeof(ULONG));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
&hProfile);
ObDereferenceObject(Profile);
if(!NT_SUCCESS(Status))
{
return Status;
/* Check for Success */
if (!NT_SUCCESS(Status)) {
/* Dereference Process on failure */
if (pProcess) ObDereferenceObject(pProcess);
return Status;
}
}
if (ProfileSource == ProfileTime)
{
ULONG ReturnInterval;
/* FIXME: What units does this use, for now nanoseconds */
ReturnInterval = 100;
_SEH_TRY
{
*Interval = ReturnInterval;
}
_SEH_HANDLE
{
/* Copy the created handle back to the caller*/
_SEH_TRY {
*ProfileHandle = hProfile;
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
}
_SEH_END;
return Status;
}
return STATUS_INVALID_PARAMETER_2;
} _SEH_END;
/* Return Status */
return Status;
}
NTSTATUS STDCALL
NtSetIntervalProfile(IN ULONG Interval,
IN KPROFILE_SOURCE Source)
NTSTATUS
STDCALL
NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
{
return(STATUS_NOT_IMPLEMENTED);
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
LARGE_INTEGER PerfFrequency;
NTSTATUS Status = STATUS_SUCCESS;
/* Check the Parameters for validity */
if(PreviousMode != KernelMode) {
_SEH_TRY {
ProbeForWrite(PerformanceCounter,
sizeof(LARGE_INTEGER),
sizeof(ULONG));
ProbeForWrite(PerformanceFrequency,
sizeof(LARGE_INTEGER),
sizeof(ULONG));
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
} _SEH_END;
if(!NT_SUCCESS(Status)) return Status;
}
_SEH_TRY {
/* Query the Kernel */
*PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency);
/* Return Frequency if requested */
if(PerformanceFrequency) {
*PerformanceFrequency = PerfFrequency;
}
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
} _SEH_END;
return Status;
}
NTSTATUS STDCALL
NTSTATUS
STDCALL
NtStartProfile(IN HANDLE ProfileHandle)
{
PKPROFILE Profile;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
PEPROFILE Profile;
PKPROFILE KeProfile;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PVOID TempLockedBuffer;
NTSTATUS Status;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
PAGED_CODE();
Status = ObReferenceObjectByHandle(ProfileHandle,
STANDARD_RIGHTS_ALL,
ExProfileObjectType,
PreviousMode,
(PVOID*)&Profile,
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
/* Get the Object */
Status = ObReferenceObjectByHandle(ProfileHandle,
PROFILE_CONTROL,
ExProfileObjectType,
PreviousMode,
(PVOID*)&Profile,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
/* To avoid a Race, wait on the Mutex */
KeWaitForSingleObject(&ExpProfileMutex,
Executive,
KernelMode,
FALSE,
NULL);
/* The Profile can still be enabled though, so handle that */
if (Profile->LockedBuffer) {
/* Release our lock, dereference and return */
KeReleaseMutex(&ExpProfileMutex, FALSE);
ObDereferenceObject(Profile);
return STATUS_PROFILING_NOT_STOPPED;
}
Profile->Started = TRUE;
ObDereferenceObject(Profile);
return(STATUS_SUCCESS);
/* Allocate a Kernel Profile Object. */
KeProfile = ExAllocatePoolWithTag(NonPagedPool,
sizeof(EPROFILE),
TAG('P', 'r', 'o', 'f'));
/* Allocate the Mdl Structure */
Profile->Mdl = MmCreateMdl(NULL, Profile->Buffer, Profile->BufferSize);
/* Probe and Lock for Write Access */
MmProbeAndLockPages(Profile->Mdl, PreviousMode, IoWriteAccess);
/* Map the pages */
TempLockedBuffer = MmMapLockedPages(Profile->Mdl, KernelMode);
/* Initialize the Kernel Profile Object */
Profile->KeProfile = KeProfile;
KeInitializeProfile(KeProfile,
(PKPROCESS)Profile->Process,
Profile->ImageBase,
Profile->ImageSize,
Profile->BucketSize,
Profile->ProfileSource,
Profile->Affinity);
/* Start the Profiling */
KeStartProfile(KeProfile, TempLockedBuffer);
/* Now it's safe to save this */
Profile->LockedBuffer = TempLockedBuffer;
/* Release mutex, dereference and return */
KeReleaseMutex(&ExpProfileMutex, FALSE);
ObDereferenceObject(Profile);
return STATUS_SUCCESS;
}
NTSTATUS STDCALL
NTSTATUS
STDCALL
NtStopProfile(IN HANDLE ProfileHandle)
{
PKPROFILE Profile;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status;
PEPROFILE Profile;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
PAGED_CODE();
PreviousMode = ExGetPreviousMode();
PAGED_CODE();
Status = ObReferenceObjectByHandle(ProfileHandle,
STANDARD_RIGHTS_ALL,
ExProfileObjectType,
PreviousMode,
(PVOID*)&Profile,
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
/* Get the Object */
Status = ObReferenceObjectByHandle(ProfileHandle,
PROFILE_CONTROL,
ExProfileObjectType,
PreviousMode,
(PVOID*)&Profile,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
/* Get the Mutex */
KeWaitForSingleObject(&ExpProfileMutex,
Executive,
KernelMode,
FALSE,
NULL);
/* Make sure the Profile Object is really Started */
if (!Profile->LockedBuffer) {
Status = STATUS_PROFILING_NOT_STARTED;
goto Exit;
}
Profile->Started = FALSE;
ObDereferenceObject(Profile);
return(STATUS_SUCCESS);
/* Stop the Profile */
KeStopProfile(Profile->KeProfile);
/* Unlock the Buffer */
MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
MmUnlockPages(Profile->Mdl);
ExFreePool(Profile->KeProfile);
/* Clear the Locked Buffer pointer, meaning the Object is Stopped */
Profile->LockedBuffer = NULL;
Exit:
/* Release Mutex, Dereference and Return */
KeReleaseMutex(&ExpProfileMutex, FALSE);
ObDereferenceObject(Profile);
return Status;
}
NTSTATUS
STDCALL
NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
OUT PULONG Interval)
{
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
ULONG ReturnInterval;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
/* Check the Parameters for validity */
if(PreviousMode != KernelMode) {
_SEH_TRY {
ProbeForWrite(Interval,
sizeof(ULONG),
sizeof(ULONG));
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
} _SEH_END;
if(!NT_SUCCESS(Status)) return Status;
}
/* Query the Interval */
ReturnInterval = KeQueryIntervalProfile(ProfileSource);
/* Return the data */
_SEH_TRY {
*Interval = ReturnInterval;
} _SEH_HANDLE {
Status = _SEH_GetExceptionCode();
} _SEH_END;
/* Return Success */
return STATUS_SUCCESS;
}
NTSTATUS
STDCALL
NtSetIntervalProfile(IN ULONG Interval,
IN KPROFILE_SOURCE Source)
{
/* Let the Kernel do the job */
KeSetIntervalProfile(Interval, Source);
/* Nothing can go wrong */
return STATUS_SUCCESS;
}

File diff suppressed because it is too large Load diff

View file

@ -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);

View file

@ -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)

View file

@ -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;
}

View file

@ -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

View file

@ -1,5 +1,4 @@
/* $Id$
*
/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/profile.c
@ -8,335 +7,294 @@
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
extern LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
extern LIST_ENTRY SystemProfileList;
extern KSPIN_LOCK ProfileListLock;
extern BOOLEAN ProfileInitDone;
/* GLOBALS *******************************************************************/
KIRQL KiProfileIrql = PROFILE_LEVEL;
LIST_ENTRY KiProfileListHead;
LIST_ENTRY KiProfileSourceListHead;
KSPIN_LOCK KiProfileLock;
ULONG KiProfileTimeInterval = 78125; /* Default resolution 7.8ms (sysinternals) */
/* FUNCTIONS *****************************************************************/
STDCALL
VOID
KiAddProfileEventToProcess(PLIST_ENTRY ListHead, PVOID Eip)
/*
* Add a profile event to the profile objects for a particular process
* or the system
*/
KeInitializeProfile(PKPROFILE Profile,
PKPROCESS Process,
PVOID ImageBase,
ULONG ImageSize,
ULONG BucketSize,
KPROFILE_SOURCE ProfileSource,
KAFFINITY Affinity)
{
PKPROFILE current;
PLIST_ENTRY current_entry;
current_entry = ListHead->Flink;
while (current_entry != ListHead)
{
current = CONTAINING_RECORD(current_entry, KPROFILE, ListEntry);
if (current->Base > Eip)
{
return;
}
if (current->Base <= Eip && ((char*)current->Base + current->Size) > (char*)Eip &&
current->Started)
{
ULONG Bucket;
Bucket = ((ULONG)((char*)Eip - (char*)current->Base)) >> current->BucketShift;
if ((Bucket*4) < current->BufferSize)
{
current->Buffer[Bucket]++;
}
}
current_entry = current_entry->Flink;
}
}
VOID
KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Eip)
/*
* Add a profile event
*/
{
HANDLE Pid;
PKPROCESS_PROFILE current;
PLIST_ENTRY current_entry;
PLIST_ENTRY ListHead;
if (!ProfileInitDone)
{
return;
}
Pid = PsGetCurrentProcessId();
ListHead =
ProcessProfileListHashTable[(ULONG)Pid % PROFILE_HASH_TABLE_SIZE].Flink;
KeAcquireSpinLockAtDpcLevel(&ProfileListLock);
current_entry = ListHead;
while (current_entry != ListHead)
{
current = CONTAINING_RECORD(current_entry, KPROCESS_PROFILE, ListEntry);
if (current->Pid == Pid)
{
KiAddProfileEventToProcess(&current->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(&current->ProfileListHead, Profile);
KeReleaseSpinLock(&ProfileListLock, oldIrql);
return;
}
current_entry = current_entry->Flink;
}
current = ExAllocatePool(NonPagedPool, sizeof(KPROCESS_PROFILE));
current->Pid = Pid;
InitializeListHead(&current->ProfileListHead);
InsertTailList(ListHead, &current->ListEntry);
KiInsertProfileIntoProcess(&current->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(&current->ProfileListHead))
{
RemoveEntryList(&current->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;
}

View file

@ -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);

View file

@ -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