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 := OBJECTS_KDBG :=
endif endif
ifeq ($(DBG_OR_KDBG), 1) 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 endif
TARGET_ASFLAGS = -I./include TARGET_ASFLAGS = -I./include
@ -233,14 +233,12 @@ OBJECTS_PS = \
# Executive Subsystem (Ex) # Executive Subsystem (Ex)
OBJECTS_EX = \ OBJECTS_EX = \
ex/btree.o \
ex/callback.o \ ex/callback.o \
ex/error.o \ ex/error.o \
ex/event.o \ ex/event.o \
ex/evtpair.o \ ex/evtpair.o \
ex/fmutex.o \ ex/fmutex.o \
ex/handle.o \ ex/handle.o \
ex/hashtab.o \
ex/init.o \ ex/init.o \
ex/interlck.o \ ex/interlck.o \
ex/list.o \ ex/list.o \
@ -250,7 +248,6 @@ OBJECTS_EX = \
ex/profile.o \ ex/profile.o \
ex/resource.o \ ex/resource.o \
ex/rundown.o \ ex/rundown.o \
ex/stree.o \
ex/sem.o \ ex/sem.o \
ex/synch.o \ ex/synch.o \
ex/sysinfo.o \ ex/sysinfo.o \

View file

@ -255,19 +255,6 @@ BOOLEAN
KdbpAttachToProcess( KdbpAttachToProcess(
PVOID ProcessId); PVOID ProcessId);
/* from profile.c */
VOID
KdbInitProfiling();
VOID
KdbInitProfiling2();
VOID
KdbDisableProfiling();
VOID
KdbEnableProfiling();
VOID
KdbProfileInterrupt(ULONG_PTR Eip);
/* other functions */ /* other functions */
#define KdbpSafeReadMemory(dst, src, size) MmSafeCopyFromUser(dst, src, size) #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 * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/nt/profile.c * FILE: ntoskrnl/ex/profile.c
* PURPOSE: Support for profiling * PURPOSE: Support for Executive Profile Objects
* *
* PROGRAMMERS: No programmer listed. * PROGRAMMERS: Alex Ionescu
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
@ -13,369 +12,448 @@
#include <ntoskrnl.h> #include <ntoskrnl.h>
#include <internal/debug.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 *******************************************************************/ /* GLOBALS *******************************************************************/
POBJECT_TYPE EXPORTED ExProfileObjectType = NULL; POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
static KMUTEX ExpProfileMutex;
#define PROFILE_CONTROL 1
static GENERIC_MAPPING ExpProfileMapping = { static GENERIC_MAPPING ExpProfileMapping = {
STANDARD_RIGHTS_READ, STANDARD_RIGHTS_READ | PROFILE_CONTROL,
STANDARD_RIGHTS_WRITE, STANDARD_RIGHTS_WRITE | PROFILE_CONTROL,
STANDARD_RIGHTS_EXECUTE, STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
STANDARD_RIGHTS_ALL}; STANDARD_RIGHTS_ALL};
/* VOID
* Size of the profile hash table. STDCALL
*/ ExpDeleteProfile(PVOID ObjectBody)
#define PROFILE_HASH_TABLE_SIZE (32) {
PEPROFILE Profile;
/* /* Typecast the Object */
* Table of lists of per-process profiling data structures hashed by PID. Profile = (PEPROFILE)ObjectBody;
*/
LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
/* /* Check if there if the Profile was started */
* Head of the list of profile data structures for the kernel. if (Profile->LockedBuffer) {
*/
LIST_ENTRY SystemProfileList;
/* /* Stop the Profile */
* Lock that protects the profiling data structures. KeStopProfile(Profile->KeProfile);
*/
KSPIN_LOCK ProfileListLock;
/* /* Unmap the Locked Buffer */
* Timer interrupts happen before we have initialized the profiling MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
* data structures so just ignore them before that. MmUnlockPages(Profile->Mdl);
*/ ExFreePool(Profile->Mdl);
BOOLEAN ProfileInitDone = FALSE; }
VOID INIT_FUNCTION /* Check if a Process is associated */
if (Profile->Process != NULL) {
/* Dereference it */
ObDereferenceObject(Profile->Process);
Profile->Process = NULL;
}
}
VOID
INIT_FUNCTION
ExpInitializeProfileImplementation(VOID) ExpInitializeProfileImplementation(VOID)
{ {
ULONG i; /* Initialize the Mutex to lock the States */
KeInitializeMutex(&ExpProfileMutex, 0x40);
InitializeListHead(&SystemProfileList); /* Create the Object Type */
ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++) RtlInitUnicodeString(&ExProfileObjectType->TypeName, L"Profile");
{ ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
InitializeListHead(&ProcessProfileListHashTable[i]); ExProfileObjectType->PeakObjects = 0;
} ExProfileObjectType->PeakHandles = 0;
ExProfileObjectType->TotalObjects = 0;
KeInitializeSpinLock(&ProfileListLock); ExProfileObjectType->TotalHandles = 0;
ProfileInitDone = TRUE; ExProfileObjectType->PagedPoolCharge = 0;
ExProfileObjectType->NonpagedPoolCharge = sizeof(EPROFILE);
ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE)); ExProfileObjectType->Mapping = &ExpProfileMapping;
ExProfileObjectType->Dump = NULL;
RtlpCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile", NonPagedPool); ExProfileObjectType->Open = NULL;
ExProfileObjectType->Close = NULL;
ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F'); ExProfileObjectType->Delete = ExpDeleteProfile;
ExProfileObjectType->PeakObjects = 0; ExProfileObjectType->Parse = NULL;
ExProfileObjectType->PeakHandles = 0; ExProfileObjectType->Security = NULL;
ExProfileObjectType->TotalObjects = 0; ExProfileObjectType->QueryName = NULL;
ExProfileObjectType->TotalHandles = 0; ExProfileObjectType->OkayToClose = NULL;
ExProfileObjectType->PagedPoolCharge = 0; ExProfileObjectType->Create = NULL;
ExProfileObjectType->NonpagedPoolCharge = sizeof(KPROFILE); ObpCreateTypeObject(ExProfileObjectType);
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);
} }
NTSTATUS STDCALL NTSTATUS
STDCALL
NtCreateProfile(OUT PHANDLE ProfileHandle, NtCreateProfile(OUT PHANDLE ProfileHandle,
IN HANDLE Process OPTIONAL, IN HANDLE Process OPTIONAL,
IN PVOID ImageBase, IN PVOID ImageBase,
IN ULONG ImageSize, IN ULONG ImageSize,
IN ULONG BucketSize, IN ULONG BucketSize,
IN PVOID Buffer, IN PVOID Buffer,
IN ULONG BufferSize, IN ULONG BufferSize,
IN KPROFILE_SOURCE ProfileSource, IN KPROFILE_SOURCE ProfileSource,
IN KAFFINITY Affinity) IN KAFFINITY Affinity)
{ {
HANDLE hProfile; HANDLE hProfile;
PKPROFILE Profile; PEPROFILE Profile;
PEPROCESS pProcess; PEPROCESS pProcess;
KPROCESSOR_MODE PreviousMode; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status = STATUS_SUCCESS; NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE(); PAGED_CODE();
PreviousMode = ExGetPreviousMode(); /* Easy way out */
if(BufferSize == 0) return STATUS_INVALID_PARAMETER_7;
if(BufferSize == 0) /* Check the Parameters for validity */
{ if(PreviousMode != KernelMode) {
return STATUS_INVALID_PARAMETER_7;
}
if(PreviousMode != KernelMode) _SEH_TRY {
{
_SEH_TRY
{
ProbeForWrite(ProfileHandle,
sizeof(HANDLE),
sizeof(ULONG));
ProbeForWrite(Buffer,
BufferSize,
sizeof(ULONG));
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if(!NT_SUCCESS(Status)) ProbeForWrite(ProfileHandle,
{ sizeof(HANDLE),
return Status; sizeof(ULONG));
}
}
/* ProbeForWrite(Buffer,
* Reference the associated process BufferSize,
*/ sizeof(ULONG));
if (Process != NULL) } _SEH_HANDLE {
{
Status = ObReferenceObjectByHandle(Process, Status = _SEH_GetExceptionCode();
PROCESS_QUERY_INFORMATION, } _SEH_END;
PsProcessType,
PreviousMode, if(!NT_SUCCESS(Status)) return Status;
(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;
}
} }
/* /* Check if a process was specified */
* Check the parameters if (Process) {
*/
if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) || /* Reference it */
(pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE)) Status = ObReferenceObjectByHandle(Process,
{ PROCESS_QUERY_INFORMATION,
return(STATUS_INVALID_PARAMETER_3); PsProcessType,
} PreviousMode,
if (((ImageSize >> BucketSize) * 4) >= BufferSize) (PVOID*)&pProcess,
{ NULL);
return(STATUS_BUFFER_TOO_SMALL); if (!NT_SUCCESS(Status)) return(Status);
}
if (ProfileSource != ProfileTime) } else {
{
return(STATUS_INVALID_PARAMETER_9); /* No process was specified, which means a System-Wide Profile */
} pProcess = NULL;
if (Affinity != 0)
{ /* For this, we need to check the Privilege */
return(STATUS_INVALID_PARAMETER_10); if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode)) {
DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
} }
/* /* Create the object */
* Create the object InitializeObjectAttributes(&ObjectAttributes,
*/ NULL,
InitializeObjectAttributes(&ObjectAttributes, 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, NULL,
PROFILE_CONTROL,
0, 0,
NULL, NULL,
NULL); &hProfile);
ObDereferenceObject(Profile);
Status = ObCreateObject(KernelMode, /* Check for Success */
ExProfileObjectType, if (!NT_SUCCESS(Status)) {
&ObjectAttributes,
PreviousMode,
NULL,
sizeof(KPROFILE),
0,
0,
(PVOID*)&Profile);
if (!NT_SUCCESS(Status))
{
return(Status);
}
/* /* Dereference Process on failure */
* Initialize it if (pProcess) ObDereferenceObject(pProcess);
*/ return Status;
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*/
* Copy the created handle back to the caller _SEH_TRY {
*/
_SEH_TRY
{
*ProfileHandle = hProfile;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
ObDereferenceObject(Profile); *ProfileHandle = hProfile;
return Status; } _SEH_HANDLE {
}
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;
if(!NT_SUCCESS(Status))
{
return Status;
}
}
if (ProfileSource == ProfileTime)
{
ULONG ReturnInterval;
/* FIXME: What units does this use, for now nanoseconds */
ReturnInterval = 100;
_SEH_TRY
{
*Interval = ReturnInterval;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode(); Status = _SEH_GetExceptionCode();
} } _SEH_END;
_SEH_END;
return Status; /* Return Status */
} return Status;
return STATUS_INVALID_PARAMETER_2;
} }
NTSTATUS STDCALL NTSTATUS
NtSetIntervalProfile(IN ULONG Interval, STDCALL
IN KPROFILE_SOURCE Source) 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) NtStartProfile(IN HANDLE ProfileHandle)
{ {
PKPROFILE Profile; PEPROFILE Profile;
KPROCESSOR_MODE PreviousMode; PKPROFILE KeProfile;
NTSTATUS Status; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PVOID TempLockedBuffer;
NTSTATUS Status;
PAGED_CODE(); PAGED_CODE();
PreviousMode = ExGetPreviousMode(); /* Get the Object */
Status = ObReferenceObjectByHandle(ProfileHandle,
PROFILE_CONTROL,
ExProfileObjectType,
PreviousMode,
(PVOID*)&Profile,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
Status = ObReferenceObjectByHandle(ProfileHandle, /* To avoid a Race, wait on the Mutex */
STANDARD_RIGHTS_ALL, KeWaitForSingleObject(&ExpProfileMutex,
ExProfileObjectType, Executive,
PreviousMode, KernelMode,
(PVOID*)&Profile, FALSE,
NULL); NULL);
if (!NT_SUCCESS(Status))
{ /* The Profile can still be enabled though, so handle that */
return(Status); if (Profile->LockedBuffer) {
/* Release our lock, dereference and return */
KeReleaseMutex(&ExpProfileMutex, FALSE);
ObDereferenceObject(Profile);
return STATUS_PROFILING_NOT_STOPPED;
} }
Profile->Started = TRUE;
ObDereferenceObject(Profile); /* Allocate a Kernel Profile Object. */
return(STATUS_SUCCESS); 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) NtStopProfile(IN HANDLE ProfileHandle)
{ {
PKPROFILE Profile; PEPROFILE Profile;
KPROCESSOR_MODE PreviousMode; KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status; NTSTATUS Status;
PAGED_CODE(); PAGED_CODE();
PreviousMode = ExGetPreviousMode(); /* Get the Object */
Status = ObReferenceObjectByHandle(ProfileHandle,
PROFILE_CONTROL,
ExProfileObjectType,
PreviousMode,
(PVOID*)&Profile,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
Status = ObReferenceObjectByHandle(ProfileHandle, /* Get the Mutex */
STANDARD_RIGHTS_ALL, KeWaitForSingleObject(&ExpProfileMutex,
ExProfileObjectType, Executive,
PreviousMode, KernelMode,
(PVOID*)&Profile, FALSE,
NULL); NULL);
if (!NT_SUCCESS(Status))
{ /* Make sure the Profile Object is really Started */
return(Status); if (!Profile->LockedBuffer) {
Status = STATUS_PROFILING_NOT_STARTED;
goto Exit;
} }
Profile->Started = FALSE;
ObDereferenceObject(Profile); /* Stop the Profile */
return(STATUS_SUCCESS); 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 ***************************************************************/ /* next file ***************************************************************/
typedef struct _KPROCESS_PROFILE typedef struct _KPROFILE_SOURCE_OBJECT {
/* KPROFILE_SOURCE Source;
* List of the profile data structures associated with a process. LIST_ENTRY ListEntry;
*/ } KPROFILE_SOURCE_OBJECT, *PKPROFILE_SOURCE_OBJECT;
{
LIST_ENTRY ProfileListHead;
LIST_ENTRY ListEntry;
HANDLE Pid;
} KPROCESS_PROFILE, *PKPROCESS_PROFILE;
typedef struct _KPROFILE typedef struct _KPROFILE {
/* CSHORT Type;
* Describes a contiguous region of process memory that is being profiled. CSHORT Size;
*/ LIST_ENTRY ListEntry;
{ PVOID RegionStart;
CSHORT Type; PVOID RegionEnd;
CSHORT Name; ULONG BucketShift;
PVOID Buffer;
/* Entry in the list of profile data structures for this process. */ CSHORT Source;
LIST_ENTRY ListEntry; ULONG Affinity;
BOOLEAN Active;
/* Base of the region being profiled. */ struct _KPROCESS *Process;
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;
} KPROFILE, *PKPROFILE; } KPROFILE, *PKPROFILE;
/* Cached modules from the loader block */ /* Cached modules from the loader block */
@ -131,6 +98,34 @@ extern PLOADER_MODULE CachedModules[MaximumCachedModuleType];
VOID STDCALL VOID STDCALL
DbgBreakPointNoBugCheck(VOID); 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 VOID
STDCALL STDCALL
KeProfileInterrupt( KeProfileInterrupt(
@ -144,8 +139,6 @@ KeProfileInterruptWithSource(
IN KPROFILE_SOURCE Source 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 KiInsertProfileIntoProcess(PLIST_ENTRY ListHead, PKPROFILE Profile);
VOID KiInsertProfile(PKPROFILE Profile); VOID KiInsertProfile(PKPROFILE Profile);
VOID KiRemoveProfile(PKPROFILE Profile); VOID KiRemoveProfile(PKPROFILE Profile);

View file

@ -410,7 +410,16 @@ IofCompleteRequest(PIRP Irp,
if (Irp->UserIosb) 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) 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; p1 = p2;
} }

View file

@ -340,9 +340,6 @@ KiInterruptDispatch (ULONG vector, PKIRQ_TRAPFRAME Trapframe)
{ {
KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame); KeIRQTrapFrameToTrapFrame(Trapframe, &KernelTrapFrame);
KeUpdateSystemTime(&KernelTrapFrame, old_level); KeUpdateSystemTime(&KernelTrapFrame, old_level);
#if defined(KDBG) || defined(DBG)
KdbProfileInterrupt(Trapframe->Eip);
#endif /* KDBG */
} }
else else
#endif #endif

View file

@ -1,5 +1,4 @@
/* $Id$ /*
*
* COPYRIGHT: See COPYING in the top level directory * COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel * PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/profile.c * FILE: ntoskrnl/ke/profile.c
@ -8,335 +7,294 @@
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net) * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
*/ */
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h> #include <ntoskrnl.h>
#define NDEBUG #define NDEBUG
#include <internal/debug.h> #include <internal/debug.h>
extern LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE]; /* GLOBALS *******************************************************************/
extern LIST_ENTRY SystemProfileList;
extern KSPIN_LOCK ProfileListLock; KIRQL KiProfileIrql = PROFILE_LEVEL;
extern BOOLEAN ProfileInitDone; LIST_ENTRY KiProfileListHead;
LIST_ENTRY KiProfileSourceListHead;
KSPIN_LOCK KiProfileLock;
ULONG KiProfileTimeInterval = 78125; /* Default resolution 7.8ms (sysinternals) */
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
STDCALL
VOID VOID
KiAddProfileEventToProcess(PLIST_ENTRY ListHead, PVOID Eip) KeInitializeProfile(PKPROFILE Profile,
/* PKPROCESS Process,
* Add a profile event to the profile objects for a particular process PVOID ImageBase,
* or the system ULONG ImageSize,
*/ ULONG BucketSize,
KPROFILE_SOURCE ProfileSource,
KAFFINITY Affinity)
{ {
PKPROFILE current; /* Initialize the Header */
PLIST_ENTRY current_entry; Profile->Type = ProfileObject;
Profile->Size = sizeof(KPROFILE);
current_entry = ListHead->Flink; /* Copy all the settings we were given */
while (current_entry != ListHead) Profile->Process = Process;
{ Profile->RegionStart = ImageBase;
current = CONTAINING_RECORD(current_entry, KPROFILE, ListEntry); Profile->BucketShift = BucketSize - 2; /* See ntinternals.net -- Alex */
Profile->RegionEnd = (PVOID)(ULONG_PTR)ImageBase + ImageSize;
if (current->Base > Eip) Profile->Active = FALSE;
{ Profile->Source = ProfileSource;
return; Profile->Affinity = Affinity;
}
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;
}
} }
STDCALL
VOID VOID
KiAddProfileEvent(KPROFILE_SOURCE Source, ULONG Eip) KeStartProfile(PKPROFILE Profile,
/* PVOID Buffer)
* Add a profile event
*/
{ {
HANDLE Pid; KIRQL OldIrql;
PKPROCESS_PROFILE current; PKPROFILE_SOURCE_OBJECT SourceBuffer;
PLIST_ENTRY current_entry; PKPROFILE_SOURCE_OBJECT Source = NULL;
PLIST_ENTRY ListHead; PKPROFILE_SOURCE_OBJECT CurrentSource;
BOOLEAN FreeBuffer = TRUE;
PKPROCESS ProfileProcess;
PLIST_ENTRY ListEntry;
if (!ProfileInitDone) /* Allocate a buffer first, before we raise IRQL */
{ SourceBuffer = ExAllocatePoolWithTag(NonPagedPool,
return; 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;
}
} }
Pid = PsGetCurrentProcessId(); /* Lower the IRQL */
ListHead = KeReleaseSpinLockFromDpcLevel(&KiProfileLock);
ProcessProfileListHashTable[(ULONG)Pid % PROFILE_HASH_TABLE_SIZE].Flink; KeLowerIrql(OldIrql);
KeAcquireSpinLockAtDpcLevel(&ProfileListLock); /* FIXME: Tell HAL to Start the Profile Interrupt */
//HalStartProfileInterrupt(Profile->Source);
current_entry = ListHead; /* Free the pool */
while (current_entry != ListHead) if (!FreeBuffer) ExFreePool(SourceBuffer);
{
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);
} }
STDCALL
VOID VOID
KiInsertProfileIntoProcess(PLIST_ENTRY ListHead, PKPROFILE Profile) KeStopProfile(PKPROFILE Profile)
/*
* Insert a profile object into the list for a process or the system
*/
{ {
PKPROFILE current; KIRQL OldIrql;
PLIST_ENTRY current_entry; PLIST_ENTRY ListEntry;
PKPROFILE_SOURCE_OBJECT CurrentSource = NULL;
current_entry = ListHead; /* Raise to PROFILE_LEVEL and acquire spinlock */
while (current_entry != ListHead) KeRaiseIrql(PROFILE_LEVEL, &OldIrql);
{ KeAcquireSpinLockAtDpcLevel(&KiProfileLock);
current = CONTAINING_RECORD(current_entry, KPROFILE, ListEntry);
if (current->Base > Profile->Base) /* Make sure it's running */
{ if (Profile->Active) {
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; /* 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);
} }
InsertTailList(ListHead, &Profile->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 VOID
KiInsertProfile(PKPROFILE Profile) KeSetIntervalProfile(KPROFILE_SOURCE ProfileSource,
/* ULONG Interval)
* Insert a profile into the relevant data structures
*/
{ {
KIRQL oldIrql; /* Check if this is the timer profile */
if (ProfileSource == ProfileTime) {
KeAcquireSpinLock(&ProfileListLock, &oldIrql); /* Set the good old 100ns sampling interval */
KiProfileTimeInterval = Interval;
} else {
/* Set it with HAL. FIXME: What structure is used? */
HalSetSystemInformation(HalProfileSourceInformation,
sizeof(NULL),
NULL);
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 * @implemented
*/ */
STDCALL STDCALL
VOID VOID
KeProfileInterrupt( KeProfileInterrupt(PKTRAP_FRAME TrapFrame)
PKTRAP_FRAME TrapFrame
)
{ {
UNIMPLEMENTED; /* 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;
}
} }
/* /*
* @unimplemented * @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 STDCALL
VOID VOID
KeProfileInterruptWithSource( KeProfileInterruptWithSource(IN PKTRAP_FRAME TrapFrame,
IN PKTRAP_FRAME TrapFrame, IN KPROFILE_SOURCE Source)
IN KPROFILE_SOURCE Source
)
{ {
UNIMPLEMENTED; 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);
} }
/* /*
* @unimplemented * @implemented
*/ */
STDCALL STDCALL
VOID VOID
KeSetProfileIrql( KeSetProfileIrql(IN KIRQL ProfileIrql)
IN KIRQL ProfileIrql
)
{ {
UNIMPLEMENTED; /* Set the IRQL at which Profiling will run */
} KiProfileIrql = ProfileIrql;
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;
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;
} }

View file

@ -219,7 +219,6 @@ KiExpireTimers(PKDPC Dpc,
PVOID SystemArgument1, PVOID SystemArgument1,
PVOID SystemArgument2) PVOID SystemArgument2)
{ {
ULONG Eip = (ULONG)SystemArgument1;
PKTIMER Timer; PKTIMER Timer;
ULONGLONG InterruptTime; ULONGLONG InterruptTime;
LIST_ENTRY ExpiredTimerList; LIST_ENTRY ExpiredTimerList;
@ -267,8 +266,6 @@ KiExpireTimers(PKDPC Dpc,
} }
DPRINT("Timers expired\n"); DPRINT("Timers expired\n");
/* Add a Profile Event */
KiAddProfileEvent(ProfileTime, Eip);
/* Release Dispatcher Lock */ /* Release Dispatcher Lock */
KeReleaseDispatcherDatabaseLock(OldIrql); KeReleaseDispatcherDatabaseLock(OldIrql);

View file

@ -152,24 +152,6 @@ ExUuidCreate@4
ExVerifySuite@4 ExVerifySuite@4
@ExWaitForRundownProtectionRelease@4 @ExWaitForRundownProtectionRelease@4
ExWindowStationObjectType DATA 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 @ExfAcquirePushLockExclusive@4
@ExfAcquirePushLockShared@4 @ExfAcquirePushLockShared@4
@ExfReleasePushLock@4 @ExfReleasePushLock@4