Move some profile stuff to NDK and fix some bugs in the executive
implementation, as well as support segmented profile objects
Modified: trunk/reactos/include/ndk/extypes.h
Modified: trunk/reactos/ntoskrnl/ex/profile.c
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
_____
Modified: trunk/reactos/include/ndk/extypes.h
--- trunk/reactos/include/ndk/extypes.h 2005-12-29 15:14:50 UTC (rev
20425)
+++ trunk/reactos/include/ndk/extypes.h 2005-12-29 17:55:31 UTC (rev
20426)
@@ -55,46 +55,58 @@
//
// Invalid Handle Value Constant
//
-#define INVALID_HANDLE_VALUE (HANDLE)-1
+#define INVALID_HANDLE_VALUE (HANDLE)-1
#endif
//
// Increments
//
-#define MUTANT_INCREMENT 1
+#define MUTANT_INCREMENT 1
//
// Callback Object Access Mask
//
-#define CALLBACK_ALL_ACCESS
(STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x0001)
-#define CALLBACK_EXECUTE
(STANDARD_RIGHTS_EXECUTE|SYNCHRONIZE|0x0001)
-#define CALLBACK_WRITE
(STANDARD_RIGHTS_WRITE|SYNCHRONIZE|0x0001)
-#define CALLBACK_READ
(STANDARD_RIGHTS_READ|SYNCHRONIZE|0x0001)
+#define CALLBACK_ALL_ACCESS
(STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|0x0001)
+#define CALLBACK_EXECUTE
(STANDARD_RIGHTS_EXECUTE|SYNCHRONIZE|0x0001)
+#define CALLBACK_WRITE
(STANDARD_RIGHTS_WRITE|SYNCHRONIZE|0x0001)
+#define CALLBACK_READ
(STANDARD_RIGHTS_READ|SYNCHRONIZE|0x0001)
//
// Event Object Access Masks
//
#ifdef NTOS_MODE_USER
-#define EVENT_QUERY_STATE 0x0001
+#define EVENT_QUERY_STATE 0x0001
//
// Semaphore Object Acess Masks
//
-#define SEMAPHORE_QUERY_STATE 0x0001
+#define SEMAPHORE_QUERY_STATE 0x0001
#endif
//
// Event Pair Access Masks
//
-#define EVENT_PAIR_ALL_ACCESS 0x1F0000L
+#define EVENT_PAIR_ALL_ACCESS 0x1F0000L
//
+// Profile Object Access Masks
+//
+#define PROFILE_CONTROL 0x0001
+#define PROFILE_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED |
PROFILE_CONTROL)
+
+//
// Maximum Parameters for NtRaiseHardError
//
-#define MAXIMUM_HARDERROR_PARAMETERS 4
+#define MAXIMUM_HARDERROR_PARAMETERS 4
//
+// Pushlock Wait Block Flags
+//
+#define EX_PUSH_LOCK_FLAGS_EXCLUSIVE 1
+#define EX_PUSH_LOCK_FLAGS_WAIT 2
+
+//
// Shutdown types for NtShutdownSystem
//
typedef enum _SHUTDOWN_ACTION
@@ -271,8 +283,21 @@
} EX_FAST_REF, *PEX_FAST_REF;
//
-// Executive Fast Reference Wait Block
+// Executive Cache-Aware Rundown Reference Descriptor
//
+typedef struct _EX_RUNDOWN_REF_CACHE_AWARE
+{
+ union
+ {
+ ULONG_PTR Count;
+ PVOID Ptr;
+ };
+ PVOID PoolToFree;
+} EX_RUNDOWN_REF_CACHE_AWARE, *PEX_RUNDOWN_REF_CACHE_AWARE;
+
+//
+// Executive Rundown Wait Block
+//
typedef struct _EX_RUNDOWN_WAIT_BLOCK
{
ULONG_PTR Count;
@@ -280,6 +305,32 @@
} EX_RUNDOWN_WAIT_BLOCK, *PEX_RUNDOWN_WAIT_BLOCK;
//
+// Executive Pushlock Wait Block
+//
+#ifndef __GNUC__ // WARNING! PUSHLOCKS WILL NOT WORK IN GCC FOR NOW!!!
+__declspec(align(16))
+#endif
+typedef struct _EX_PUSH_LOCK_WAIT_BLOCK
+{
+ union
+ {
+ KGATE WakeGate;
+ KEVENT WakeEvent;
+ };
+ struct _EX_PUSH_LOCK_WAIT_BLOCK *Next;
+ struct _EX_PUSH_LOCK_WAIT_BLOCK *Last;
+ struct _EX_PUSH_LOCK_WAIT_BLOCK *Previous;
+ LONG ShareCount;
+ LONG Flags;
+#if DBG
+ BOOL Signaled;
+ EX_PUSH_LOCK NewValue;
+ EX_PUSH_LOCK OldValue;
+ PEX_PUSH_LOCK PushLock;
+#endif
+} EX_PUSH_LOCK_WAIT_BLOCK, *PEX_PUSH_LOCK_WAIT_BLOCK;
+
+//
// Callback Object
//
typedef struct _CALLBACK_OBJECT
@@ -291,6 +342,25 @@
} CALLBACK_OBJECT , *PCALLBACK_OBJECT;
//
+// Profile OBject
+//
+typedef struct _EPROFILE
+{
+ PEPROCESS Process;
+ PVOID ImageBase;
+ SIZE_T ImageSize;
+ PVOID Buffer;
+ ULONG BufferSize;
+ ULONG BucketSize;
+ PKPROFILE KeProfile;
+ PVOID LockedBuffer;
+ PMDL Mdl;
+ ULONG Segment;
+ KPROFILE_SOURCE ProfileSource;
+ KAFFINITY Affinity;
+} EPROFILE, *PEPROFILE;
+
+//
// Handle Table Structures
//
typedef struct _HANDLE_TABLE_ENTRY_INFO
_____
Modified: trunk/reactos/ntoskrnl/ex/profile.c
--- trunk/reactos/ntoskrnl/ex/profile.c 2005-12-29 15:14:50 UTC (rev
20425)
+++ trunk/reactos/ntoskrnl/ex/profile.c 2005-12-29 17:55:31 UTC (rev
20426)
@@ -1,65 +1,55 @@
/*
* COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
+ * PROJECT: ReactOS Kernel
* FILE: ntoskrnl/ex/profile.c
* PURPOSE: Support for Executive Profile Objects
- *
- * PROGRAMMERS: Alex Ionescu
+ * PROGRAMMERS: Alex Ionescu (alex(a)relsoft.net)
+ * Thomas Weidenmueller
*/
/* INCLUDES
*****************************************************************/
+#include <ntoskrnl.h>
#define NDEBUG
-#include <ntoskrnl.h>
#include <internal/debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, ExpInitializeProfileImplementation)
#endif
-/* FIXME: NDK 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;
+#define TAG_PROFILE TAG('P', 'r', 'o', 'f')
/* GLOBALS
*******************************************************************/
POBJECT_TYPE ExProfileObjectType = NULL;
+KMUTEX ExpProfileMutex;
-static KMUTEX ExpProfileMutex;
-
-#define PROFILE_CONTROL 1
-
-static GENERIC_MAPPING ExpProfileMapping = {
+GENERIC_MAPPING ExpProfileMapping =
+{
STANDARD_RIGHTS_READ | PROFILE_CONTROL,
STANDARD_RIGHTS_WRITE | PROFILE_CONTROL,
STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
- STANDARD_RIGHTS_ALL};
+ PROFILE_ALL_ACCESS
+};
+/* FUNCTIONS
*****************************************************************/
+
VOID
-STDCALL
+NTAPI
ExpDeleteProfile(PVOID ObjectBody)
{
PEPROFILE Profile;
+ ULONG State;
/* Typecast the Object */
Profile = (PEPROFILE)ObjectBody;
/* Check if there if the Profile was started */
- if (Profile->LockedBuffer) {
-
+ if (Profile->LockedBuffer)
+ {
/* Stop the Profile */
- KeStopProfile(Profile->KeProfile);
+ State = KeStopProfile(Profile->KeProfile);
+ ASSERT(State != FALSE);
/* Unmap the Locked Buffer */
MmUnmapLockedPages(Profile->LockedBuffer, Profile->Mdl);
@@ -67,28 +57,22 @@
ExFreePool(Profile->Mdl);
}
- /* Check if a Process is associated */
- if (Profile->Process != NULL) {
-
- /* Dereference it */
- ObDereferenceObject(Profile->Process);
- Profile->Process = NULL;
- }
+ /* Check if a Process is associated and reference it */
+ if (Profile->Process) ObDereferenceObject(Profile->Process);
}
VOID
INIT_FUNCTION
-STDCALL
+NTAPI
ExpInitializeProfileImplementation(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING Name;
-
+ DPRINT("Creating Profile Object Type\n");
+
/* Initialize the Mutex to lock the States */
- KeInitializeMutex(&ExpProfileMutex, 0x40);
+ KeInitializeMutex(&ExpProfileMutex, 64);
- DPRINT("Creating Profile Object Type\n");
-
/* Create the Event Pair Object Type */
RtlZeroMemory(&ObjectTypeInitializer,
sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Profile");
@@ -97,12 +81,12 @@
ObjectTypeInitializer.GenericMapping = ExpProfileMapping;
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
- ObjectTypeInitializer.ValidAccessMask = STANDARD_RIGHTS_ALL;
+ ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS;
ObpCreateTypeObject(&ObjectTypeInitializer, &Name,
&ExProfileObjectType);
}
NTSTATUS
-STDCALL
+NTAPI
NtCreateProfile(OUT PHANDLE ProfileHandle,
IN HANDLE Process OPTIONAL,
IN PVOID ImageBase,
@@ -119,33 +103,79 @@
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status = STATUS_SUCCESS;
-
+ ULONG Segment = 0, Log2 = 0;
PAGED_CODE();
/* Easy way out */
- if(BufferSize == 0) return STATUS_INVALID_PARAMETER_7;
+ if(!BufferSize) return STATUS_INVALID_PARAMETER_7;
- /* Check the Parameters for validity */
- if(PreviousMode != KernelMode) {
+ /* Check if this is a low-memory profile */
+ if ((!BucketSize) && (ImageBase < (PVOID)(0x10000)))
+ {
+ /* Validate size */
+ if (BufferSize < sizeof(ULONG)) return
STATUS_INVALID_PARAMETER_7;
- _SEH_TRY {
+ /* This will become a segmented profile object */
+ Segment = (ULONG)ImageBase;
+ ImageBase = 0;
+ /* Recalculate the bucket size */
+ BucketSize = ImageSize / (BufferSize / sizeof(ULONG));
+
+ /* Convert it to log2 */
+ BucketSize--;
+ while (BucketSize >>= 1) Log2++;
+ BucketSize += Log2 + 1;
+ }
+
+ /* Validate bucket size */
+ if ((BucketSize > 31) || (BucketSize < 2))
+ {
+ DPRINT1("Bucket size invalid\n");
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Make sure that the buckets can map the range */
+ if ((ImageSize >> (BucketSize - 2)) > BufferSize)
+ {
+ DPRINT1("Bucket size too small\n");
+ return STATUS_BUFFER_TOO_SMALL;
+ }
+
+ /* Make sure that the range isn't too gigantic */
+ if (((ULONG_PTR)ImageBase + ImageSize) < ImageSize)
+ {
+ DPRINT1("Range too big\n");
+ return STATUS_BUFFER_OVERFLOW;
+ }
+
+ /* Check if we were called from user-mode */
+ if(PreviousMode != KernelMode)
+ {
+ /* Entry SEH */
+ _SEH_TRY
+ {
+ /* Make sure that the handle pointer is valid */
ProbeForWriteHandle(ProfileHandle);
+ /* Check if the buffer is valid */
ProbeForWrite(Buffer,
BufferSize,
sizeof(ULONG));
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
+ }
+ _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+ {
Status = _SEH_GetExceptionCode();
- } _SEH_END;
+ }
+ _SEH_END;
+ /* Bail out if we failed */
if(!NT_SUCCESS(Status)) return Status;
}
/* Check if a process was specified */
- if (Process) {
-
+ if (Process)
+ {
/* Reference it */
Status = ObReferenceObjectByHandle(Process,
PROCESS_QUERY_INFORMATION,
@@ -154,15 +184,18 @@
(PVOID*)&pProcess,
NULL);
if (!NT_SUCCESS(Status)) return(Status);
+ }
+ else
+ {
+ /* Segmented profile objects cannot be used system-wide */
+ if (Segment) return STATUS_INVALID_PARAMETER;
- } 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)) {
-
+ if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege,
PreviousMode))
+ {
DPRINT1("NtCreateProfile: Caller requires the
SeSystemProfilePrivilege privilege!\n");
return STATUS_PRIVILEGE_NOT_HELD;
}
@@ -181,7 +214,7 @@
NULL,
sizeof(EPROFILE),
0,
- 0,
+ sizeof(EPROFILE) + sizeof(KPROFILE),
(PVOID*)&Profile);
if (!NT_SUCCESS(Status)) return(Status);
@@ -192,6 +225,8 @@
Profile->BufferSize = BufferSize;
Profile->BucketSize = BucketSize;
Profile->LockedBuffer = NULL;
+ Profile->Segment = Segment;
+ Profile->ProfileSource = ProfileSource;
Profile->Affinity = Affinity;
Profile->Process = pProcess;
@@ -205,29 +240,31 @@
ObDereferenceObject(Profile);
/* Check for Success */
- if (!NT_SUCCESS(Status)) {
-
+ if (!NT_SUCCESS(Status))
+ {
/* Dereference Process on failure */
if (pProcess) ObDereferenceObject(pProcess);
return Status;
}
- /* Copy the created handle back to the caller*/
- _SEH_TRY {
-
+ /* Enter SEH */
+ _SEH_TRY
+ {
+ /* Copy the created handle back to the caller*/
*ProfileHandle = hProfile;
-
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
+ }
+ _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+ {
Status = _SEH_GetExceptionCode();
- } _SEH_END;
+ }
+ _SEH_END;
/* Return Status */
return Status;
}
NTSTATUS
-STDCALL
+NTAPI
NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
OUT PLARGE_INTEGER PerformanceFrequency
OPTIONAL)
{
@@ -235,43 +272,50 @@
LARGE_INTEGER PerfFrequency;
NTSTATUS Status = STATUS_SUCCESS;
- /* Check the Parameters for validity */
- if(PreviousMode != KernelMode) {
-
- _SEH_TRY {
-
+ /* Check if we were called from user-mode */
+ if(PreviousMode != KernelMode)
+ {
+ /* Entry SEH Block */
+ _SEH_TRY
+ {
+ /* Make sure the counter and frequency are valid */
ProbeForWriteLargeInteger(PerformanceCounter);
-
- ProbeForWriteLargeInteger(PerformanceFrequency);
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
+ if (PerformanceFrequency)
+ {
+ ProbeForWriteLargeInteger(PerformanceFrequency);
+ }
+ }
+ _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+ {
Status = _SEH_GetExceptionCode();
- } _SEH_END;
+ }
+ _SEH_END;
+ /* If the pointers are invalid, bail out */
if(!NT_SUCCESS(Status)) return Status;
}
- _SEH_TRY {
-
+ /* Enter a new SEH Block */
+ _SEH_TRY
+ {
/* Query the Kernel */
*PerformanceCounter =
KeQueryPerformanceCounter(&PerfFrequency);
/* Return Frequency if requested */
- if(PerformanceFrequency) {
-
- *PerformanceFrequency = PerfFrequency;
- }
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
+ if(PerformanceFrequency) *PerformanceFrequency = PerfFrequency;
+ }
+ _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+ {
Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
- } _SEH_END;
-
+ /* Return status to caller */
return Status;
}
NTSTATUS
-STDCALL
+NTAPI
NtStartProfile(IN HANDLE ProfileHandle)
{
PEPROFILE Profile;
@@ -279,7 +323,6 @@
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
PVOID TempLockedBuffer;
NTSTATUS Status;
-
PAGED_CODE();
/* Get the Object */
@@ -299,8 +342,8 @@
NULL);
/* The Profile can still be enabled though, so handle that */
- if (Profile->LockedBuffer) {
-
+ if (Profile->LockedBuffer)
+ {
/* Release our lock, dereference and return */
KeReleaseMutex(&ExpProfileMutex, FALSE);
ObDereferenceObject(Profile);
@@ -310,7 +353,7 @@
/* Allocate a Kernel Profile Object. */
KeProfile = ExAllocatePoolWithTag(NonPagedPool,
sizeof(EPROFILE),
- TAG('P', 'r', 'o',
'f'));
+ TAG_PROFILE);
/* Allocate the Mdl Structure */
Profile->Mdl = MmCreateMdl(NULL, Profile->Buffer,
Profile->BufferSize);
@@ -344,13 +387,12 @@
}
NTSTATUS
-STDCALL
+NTAPI
NtStopProfile(IN HANDLE ProfileHandle)
{
PEPROFILE Profile;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
-
PAGED_CODE();
/* Get the Object */
@@ -370,8 +412,8 @@
NULL);
/* Make sure the Profile Object is really Started */
- if (!Profile->LockedBuffer) {
-
+ if (!Profile->LockedBuffer)
+ {
Status = STATUS_PROFILING_NOT_STARTED;
goto Exit;
}
@@ -395,51 +437,55 @@
}
NTSTATUS
-STDCALL
-NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
+NTAPI
+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 {
-
+ /* Check if we were called from user-mode */
+ if(PreviousMode != KernelMode)
+ {
+ /* Enter SEH Block */
+ _SEH_TRY
+ {
+ /* Validate interval */
ProbeForWriteUlong(Interval);
-
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
+ }
+ _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+ {
Status = _SEH_GetExceptionCode();
- } _SEH_END;
+ }
+ _SEH_END;
+ /* If pointer was invalid, bail out */
if(!NT_SUCCESS(Status)) return Status;
}
/* Query the Interval */
ReturnInterval = KeQueryIntervalProfile(ProfileSource);
- /* Return the data */
- _SEH_TRY {
-
+ /* Enter SEH block for return */
+ _SEH_TRY
+ {
+ /* Return the data */
*Interval = ReturnInterval;
-
- } _SEH_EXCEPT(_SEH_ExSystemExceptionFilter) {
-
+ }
+ _SEH_EXCEPT(_SEH_ExSystemExceptionFilter)
+ {
Status = _SEH_GetExceptionCode();
+ }
+ _SEH_END;
- } _SEH_END;
-
/* Return Success */
return STATUS_SUCCESS;
}
NTSTATUS
-STDCALL
+NTAPI
NtSetIntervalProfile(IN ULONG Interval,
IN KPROFILE_SOURCE Source)
{
_____
Modified: trunk/reactos/ntoskrnl/include/internal/ke.h
--- trunk/reactos/ntoskrnl/include/internal/ke.h 2005-12-29
15:14:50 UTC (rev 20425)
+++ trunk/reactos/ntoskrnl/include/internal/ke.h 2005-12-29
17:55:31 UTC (rev 20426)
@@ -188,7 +188,7 @@
PVOID Buffer
);
-VOID
+BOOLEAN
STDCALL
KeStopProfile(struct _KPROFILE* Profile);