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