/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/*
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/nt/profile.c
- * PURPOSE: Support for profiling
- * PROGRAMMER: Nobody
- * UPDATE HISTORY:
- *
+ * COPYRIGHT: See COPYING in the top level directory
+ * PROJECT: ReactOS Kernel
+ * FILE: ntoskrnl/ex/profile.c
+ * PURPOSE: Support for Executive Profile Objects
+ * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
+ * Thomas Weidenmueller
*/
/* INCLUDES *****************************************************************/
#include <ntoskrnl.h>
-#include <internal/debug.h>
+#define NDEBUG
+#include <debug.h>
+
+#if defined (ALLOC_PRAGMA)
+#pragma alloc_text(INIT, ExpInitializeProfileImplementation)
+#endif
-/* TYPES ********************************************************************/
+#define TAG_PROFILE 'forP'
/* GLOBALS *******************************************************************/
-POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
+POBJECT_TYPE ExProfileObjectType = NULL;
+KMUTEX ExpProfileMutex;
-static GENERIC_MAPPING ExpProfileMapping = {
- STANDARD_RIGHTS_READ,
- STANDARD_RIGHTS_WRITE,
- STANDARD_RIGHTS_EXECUTE,
- STANDARD_RIGHTS_ALL};
+GENERIC_MAPPING ExpProfileMapping =
+{
+ STANDARD_RIGHTS_READ | PROFILE_CONTROL,
+ STANDARD_RIGHTS_WRITE | PROFILE_CONTROL,
+ STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
+ PROFILE_ALL_ACCESS
+};
-/*
- * Size of the profile hash table.
- */
-#define PROFILE_HASH_TABLE_SIZE (32)
+/* FUNCTIONS *****************************************************************/
-/*
- * Table of lists of per-process profiling data structures hashed by PID.
- */
-LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
+VOID
+NTAPI
+ExpDeleteProfile(PVOID ObjectBody)
+{
+ PEPROFILE Profile;
+ ULONG State;
-/*
- * Head of the list of profile data structures for the kernel.
- */
-LIST_ENTRY SystemProfileList;
+ /* Typecast the Object */
+ Profile = (PEPROFILE)ObjectBody;
-/*
- * Lock that protects the profiling data structures.
- */
-KSPIN_LOCK ProfileListLock;
+ /* Check if there if the Profile was started */
+ if (Profile->LockedBufferAddress)
+ {
+ /* Stop the Profile */
+ State = KeStopProfile(Profile->ProfileObject);
+ ASSERT(State != FALSE);
+
+ /* Unmap the Locked Buffer */
+ MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl);
+ MmUnlockPages(Profile->Mdl);
+ ExFreePool(Profile->Mdl);
+ }
-/*
- * Timer interrupts happen before we have initialized the profiling
- * data structures so just ignore them before that.
- */
-BOOLEAN ProfileInitDone = FALSE;
+ /* Check if a Process is associated and reference it */
+ if (Profile->Process) ObDereferenceObject(Profile->Process);
+}
-VOID INIT_FUNCTION
+VOID
+INIT_FUNCTION
+NTAPI
ExpInitializeProfileImplementation(VOID)
{
- ULONG i;
-
- InitializeListHead(&SystemProfileList);
-
- for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++)
- {
- InitializeListHead(&ProcessProfileListHashTable[i]);
- }
-
- KeInitializeSpinLock(&ProfileListLock);
- ProfileInitDone = TRUE;
-
- ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
-
- RtlCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile");
-
- ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
- ExProfileObjectType->PeakObjects = 0;
- ExProfileObjectType->PeakHandles = 0;
- ExProfileObjectType->TotalObjects = 0;
- ExProfileObjectType->TotalHandles = 0;
- ExProfileObjectType->PagedPoolCharge = 0;
- ExProfileObjectType->NonpagedPoolCharge = sizeof(KPROFILE);
- ExProfileObjectType->Mapping = &ExpProfileMapping;
- ExProfileObjectType->Dump = NULL;
- ExProfileObjectType->Open = NULL;
- ExProfileObjectType->Close = NULL;
- ExProfileObjectType->Delete = KiDeleteProfile;
- ExProfileObjectType->Parse = NULL;
- ExProfileObjectType->Security = NULL;
- ExProfileObjectType->QueryName = NULL;
- ExProfileObjectType->OkayToClose = NULL;
- ExProfileObjectType->Create = NULL;
-
- ObpCreateTypeObject(ExProfileObjectType);
+ OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
+ UNICODE_STRING Name;
+ DPRINT("Creating Profile Object Type\n");
+
+ /* Initialize the Mutex to lock the States */
+ KeInitializeMutex(&ExpProfileMutex, 64);
+
+ /* Create the Event Pair Object Type */
+ RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
+ RtlInitUnicodeString(&Name, L"Profile");
+ ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
+ ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KPROFILE);
+ ObjectTypeInitializer.GenericMapping = ExpProfileMapping;
+ ObjectTypeInitializer.PoolType = NonPagedPool;
+ ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
+ ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS;
+ ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExProfileObjectType);
}
-NTSTATUS STDCALL
+NTSTATUS
+NTAPI
NtCreateProfile(OUT PHANDLE ProfileHandle,
- IN HANDLE Process OPTIONAL,
- IN PVOID ImageBase,
- IN ULONG ImageSize,
- IN ULONG BucketSize,
- IN PVOID Buffer,
- IN ULONG BufferSize,
- IN KPROFILE_SOURCE ProfileSource,
- IN KAFFINITY Affinity)
+ IN HANDLE Process OPTIONAL,
+ IN PVOID RangeBase,
+ IN ULONG RangeSize,
+ IN ULONG BucketSize,
+ IN PVOID Buffer,
+ IN ULONG BufferSize,
+ IN KPROFILE_SOURCE ProfileSource,
+ IN KAFFINITY Affinity)
{
- HANDLE hProfile;
- PKPROFILE Profile;
- PEPROCESS pProcess;
- KPROCESSOR_MODE PreviousMode;
- OBJECT_ATTRIBUTES ObjectAttributes;
- NTSTATUS Status = STATUS_SUCCESS;
-
- PreviousMode = ExGetPreviousMode();
-
- if(BufferSize == 0)
- {
- return STATUS_INVALID_PARAMETER_7;
- }
-
- if(PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWrite(ProfileHandle,
- sizeof(HANDLE),
- sizeof(ULONG));
- ProbeForWrite(Buffer,
- BufferSize,
- sizeof(ULONG));
- }
- _SEH_HANDLE
+ HANDLE hProfile;
+ PEPROFILE Profile;
+ PEPROCESS pProcess;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ NTSTATUS Status;
+ ULONG Log2 = 0;
+ ULONG_PTR Segment = 0;
+ PAGED_CODE();
+
+ /* Easy way out */
+ if(!BufferSize) return STATUS_INVALID_PARAMETER_7;
+
+ /* Check if this is a low-memory profile */
+ if ((!BucketSize) && (RangeBase < (PVOID)(0x10000)))
{
- Status = _SEH_GetExceptionCode();
+ /* Validate size */
+ if (BufferSize < sizeof(ULONG)) return STATUS_INVALID_PARAMETER_7;
+
+ /* This will become a segmented profile object */
+ Segment = (ULONG_PTR)RangeBase;
+ RangeBase = 0;
+
+ /* Recalculate the bucket size */
+ BucketSize = RangeSize / (BufferSize / sizeof(ULONG));
+
+ /* Convert it to log2 */
+ BucketSize--;
+ while (BucketSize >>= 1) Log2++;
+ BucketSize += Log2 + 1;
}
- _SEH_END;
-
- if(!NT_SUCCESS(Status))
+
+ /* Validate bucket size */
+ if ((BucketSize > 31) || (BucketSize < 2))
{
- return Status;
+ DPRINT1("Bucket size invalid\n");
+ return STATUS_INVALID_PARAMETER;
}
- }
- /*
- * Reference the associated process
- */
- if (Process != NULL)
+ /* Make sure that the buckets can map the range */
+ if ((RangeSize >> (BucketSize - 2)) > BufferSize)
{
- Status = ObReferenceObjectByHandle(Process,
- PROCESS_QUERY_INFORMATION,
- PsProcessType,
- PreviousMode,
- (PVOID*)&pProcess,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
+ DPRINT1("Bucket size too small\n");
+ return STATUS_BUFFER_TOO_SMALL;
}
- else
+
+ /* Make sure that the range isn't too gigantic */
+ if (((ULONG_PTR)RangeBase + RangeSize) < RangeSize)
{
- pProcess = NULL;
- if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege,
- PreviousMode))
- {
- DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
- return STATUS_PRIVILEGE_NOT_HELD;
- }
+ DPRINT1("Range too big\n");
+ return STATUS_BUFFER_OVERFLOW;
}
- /*
- * Check the parameters
- */
- if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) ||
- (pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE))
+ /* Check if we were called from user-mode */
+ if(PreviousMode != KernelMode)
{
- return(STATUS_INVALID_PARAMETER_3);
+ /* Entry SEH */
+ _SEH2_TRY
+ {
+ /* Make sure that the handle pointer is valid */
+ ProbeForWriteHandle(ProfileHandle);
+
+ /* Check if the buffer is valid */
+ ProbeForWrite(Buffer,
+ BufferSize,
+ sizeof(ULONG));
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
}
- if (((ImageSize >> BucketSize) * 4) >= BufferSize)
+
+ /* Check if a process was specified */
+ if (Process)
{
- return(STATUS_BUFFER_TOO_SMALL);
+ /* Reference it */
+ Status = ObReferenceObjectByHandle(Process,
+ PROCESS_QUERY_INFORMATION,
+ PsProcessType,
+ PreviousMode,
+ (PVOID*)&pProcess,
+ NULL);
+ if (!NT_SUCCESS(Status)) return(Status);
}
- if (ProfileSource != ProfileTime)
+ else
{
- return(STATUS_INVALID_PARAMETER_9);
+ /* Segmented profile objects cannot be used system-wide */
+ if (Segment) return STATUS_INVALID_PARAMETER;
+
+ /* No process was specified, which means a System-Wide Profile */
+ pProcess = NULL;
+
+ /* For this, we need to check the Privilege */
+ if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode))
+ {
+ DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
+ return STATUS_PRIVILEGE_NOT_HELD;
+ }
}
- if (Affinity != 0)
+
+ /* Create the object */
+ InitializeObjectAttributes(&ObjectAttributes,
+ NULL,
+ 0,
+ NULL,
+ NULL);
+ Status = ObCreateObject(KernelMode,
+ ExProfileObjectType,
+ &ObjectAttributes,
+ PreviousMode,
+ NULL,
+ sizeof(EPROFILE),
+ 0,
+ sizeof(EPROFILE) + sizeof(KPROFILE),
+ (PVOID*)&Profile);
+ if (!NT_SUCCESS(Status))
{
- return(STATUS_INVALID_PARAMETER_10);
+ /* Dereference the process object if it was specified */
+ if (pProcess) ObDereferenceObject(pProcess);
+
+ /* Return Status */
+ return Status;
}
- /*
- * Create the object
- */
- InitializeObjectAttributes(&ObjectAttributes,
+ /* Initialize it */
+ Profile->RangeBase = RangeBase;
+ Profile->RangeSize = RangeSize;
+ Profile->Buffer = Buffer;
+ Profile->BufferSize = BufferSize;
+ Profile->BucketSize = BucketSize;
+ Profile->LockedBufferAddress = NULL;
+ Profile->Segment = Segment;
+ Profile->ProfileSource = ProfileSource;
+ Profile->Affinity = Affinity;
+ Profile->Process = pProcess;
+
+ /* Insert into the Object Tree */
+ Status = ObInsertObject ((PVOID)Profile,
NULL,
+ PROFILE_CONTROL,
0,
NULL,
- NULL);
-
- Status = ObCreateObject(KernelMode,
- ExProfileObjectType,
- &ObjectAttributes,
- PreviousMode,
- NULL,
- sizeof(KPROFILE),
- 0,
- 0,
- (PVOID*)&Profile);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- /*
- * Initialize it
- */
- Profile->Base = ImageBase;
- Profile->Size = ImageSize;
- Profile->BucketShift = BucketSize;
- Profile->BufferMdl = MmCreateMdl(NULL, Buffer, BufferSize);
- if(Profile->BufferMdl == NULL) {
- DPRINT("MmCreateMdl: Out of memory!");
- ObDereferenceObject (Profile);
- return(STATUS_NO_MEMORY);
- }
- MmProbeAndLockPages(Profile->BufferMdl, UserMode, IoWriteAccess);
- Profile->Buffer = MmGetSystemAddressForMdl(Profile->BufferMdl);
- Profile->BufferSize = BufferSize;
- Profile->ProcessorMask = Affinity;
- Profile->Started = FALSE;
- Profile->Process = pProcess;
-
- /*
- * Insert the profile into the profile list data structures
- */
- KiInsertProfile(Profile);
-
- Status = ObInsertObject ((PVOID)Profile,
- NULL,
- STANDARD_RIGHTS_ALL,
- 0,
- NULL,
- &hProfile);
- if (!NT_SUCCESS(Status))
+ &hProfile);
+ ObDereferenceObject(Profile);
+
+ /* Check for Success */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Dereference Process on failure */
+ if (pProcess) ObDereferenceObject(pProcess);
+ return Status;
+ }
+
+ /* Enter SEH */
+ _SEH2_TRY
+ {
+ /* Copy the created handle back to the caller*/
+ *ProfileHandle = hProfile;
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
{
- ObDereferenceObject (Profile);
- return Status;
+ Status = _SEH2_GetExceptionCode();
}
+ _SEH2_END;
- /*
- * Copy the created handle back to the caller
- */
- _SEH_TRY
- {
- *ProfileHandle = hProfile;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- ObDereferenceObject(Profile);
-
- return Status;
+ /* Return Status */
+ return Status;
}
-NTSTATUS STDCALL
-NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
- OUT PULONG Interval)
+NTSTATUS
+NTAPI
+NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
+ OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
{
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
-
- PreviousMode = ExGetPreviousMode();
-
- if(PreviousMode != KernelMode)
- {
- _SEH_TRY
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ LARGE_INTEGER PerfFrequency;
+ NTSTATUS Status = STATUS_SUCCESS;
+
+ /* Check if we were called from user-mode */
+ if (PreviousMode != KernelMode)
{
- ProbeForWrite(Interval,
- sizeof(ULONG),
- sizeof(ULONG));
+ /* Entry SEH Block */
+ _SEH2_TRY
+ {
+ /* Make sure the counter and frequency are valid */
+ ProbeForWriteLargeInteger(PerformanceCounter);
+ if (PerformanceFrequency)
+ {
+ ProbeForWriteLargeInteger(PerformanceFrequency);
+ }
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
}
- _SEH_HANDLE
+
+ /* Enter a new SEH Block */
+ _SEH2_TRY
{
- Status = _SEH_GetExceptionCode();
+ /* Query the Kernel */
+ *PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency);
+
+ /* Return Frequency if requested */
+ if (PerformanceFrequency) *PerformanceFrequency = PerfFrequency;
}
- _SEH_END;
-
- if(!NT_SUCCESS(Status))
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
{
- return Status;
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
}
- }
+ _SEH2_END;
+
+ /* Return status to caller */
+ return Status;
+}
- if (ProfileSource == ProfileTime)
+NTSTATUS
+NTAPI
+NtStartProfile(IN HANDLE ProfileHandle)
+{
+ PEPROFILE Profile;
+ PKPROFILE ProfileObject;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ PVOID TempLockedBufferAddress;
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Get the Object */
+ Status = ObReferenceObjectByHandle(ProfileHandle,
+ PROFILE_CONTROL,
+ ExProfileObjectType,
+ PreviousMode,
+ (PVOID*)&Profile,
+ NULL);
+ if (!NT_SUCCESS(Status)) return(Status);
+
+ /* To avoid a Race, wait on the Mutex */
+ KeWaitForSingleObject(&ExpProfileMutex,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ /* The Profile can still be enabled though, so handle that */
+ if (Profile->LockedBufferAddress)
{
- ULONG ReturnInterval;
+ /* Release our lock, dereference and return */
+ KeReleaseMutex(&ExpProfileMutex, FALSE);
+ ObDereferenceObject(Profile);
+ return STATUS_PROFILING_NOT_STOPPED;
+ }
- /* FIXME: What units does this use, for now nanoseconds */
- ReturnInterval = 100;
+ /* Allocate a Kernel Profile Object. */
+ ProfileObject = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(EPROFILE),
+ TAG_PROFILE);
+ if (!ProfileObject)
+ {
+ /* Out of memory, fail */
+ KeReleaseMutex(&ExpProfileMutex, FALSE);
+ ObDereferenceObject(Profile);
+ return STATUS_INSUFFICIENT_RESOURCES;
+ }
- _SEH_TRY
- {
- *Interval = ReturnInterval;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- return Status;
+ /* Allocate the Mdl Structure */
+ Profile->Mdl = MmCreateMdl(NULL, Profile->Buffer, Profile->BufferSize);
+
+ /* Protect this in SEH as we might raise an exception */
+ _SEH2_TRY
+ {
+ /* Probe and Lock for Write Access */
+ MmProbeAndLockPages(Profile->Mdl, PreviousMode, IoWriteAccess);
}
- return STATUS_INVALID_PARAMETER_2;
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ /* Release our lock, free the buffer, dereference and return */
+ KeReleaseMutex(&ExpProfileMutex, FALSE);
+ ObDereferenceObject(Profile);
+ ExFreePool(ProfileObject);
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+
+ /* Map the pages */
+ TempLockedBufferAddress = MmMapLockedPages(Profile->Mdl, KernelMode);
+
+ /* Initialize the Kernel Profile Object */
+ Profile->ProfileObject = ProfileObject;
+ KeInitializeProfile(ProfileObject,
+ (PKPROCESS)Profile->Process,
+ Profile->RangeBase,
+ Profile->RangeSize,
+ Profile->BucketSize,
+ Profile->ProfileSource,
+ Profile->Affinity);
+
+ /* Start the Profiling */
+ KeStartProfile(ProfileObject, TempLockedBufferAddress);
+
+ /* Now it's safe to save this */
+ Profile->LockedBufferAddress = TempLockedBufferAddress;
+
+ /* Release mutex, dereference and return */
+ KeReleaseMutex(&ExpProfileMutex, FALSE);
+ ObDereferenceObject(Profile);
+ return STATUS_SUCCESS;
}
-NTSTATUS STDCALL
-NtSetIntervalProfile(IN ULONG Interval,
- IN KPROFILE_SOURCE Source)
+NTSTATUS
+NTAPI
+NtStopProfile(IN HANDLE ProfileHandle)
{
- return(STATUS_NOT_IMPLEMENTED);
+ PEPROFILE Profile;
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ NTSTATUS Status;
+ PAGED_CODE();
+
+ /* Get the Object */
+ Status = ObReferenceObjectByHandle(ProfileHandle,
+ PROFILE_CONTROL,
+ ExProfileObjectType,
+ PreviousMode,
+ (PVOID*)&Profile,
+ NULL);
+ if (!NT_SUCCESS(Status)) return(Status);
+
+ /* Get the Mutex */
+ KeWaitForSingleObject(&ExpProfileMutex,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ /* Make sure the Profile Object is really Started */
+ if (!Profile->LockedBufferAddress)
+ {
+ Status = STATUS_PROFILING_NOT_STARTED;
+ goto Exit;
+ }
+
+ /* Stop the Profile */
+ KeStopProfile(Profile->ProfileObject);
+
+ /* Unlock the Buffer */
+ MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl);
+ MmUnlockPages(Profile->Mdl);
+ ExFreePool(Profile->ProfileObject);
+
+ /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
+ Profile->LockedBufferAddress = NULL;
+
+Exit:
+ /* Release Mutex, Dereference and Return */
+ KeReleaseMutex(&ExpProfileMutex, FALSE);
+ ObDereferenceObject(Profile);
+ return Status;
}
-NTSTATUS STDCALL
-NtStartProfile(IN HANDLE ProfileHandle)
+NTSTATUS
+NTAPI
+NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
+ OUT PULONG Interval)
{
- PKPROFILE Profile;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status;
-
- PreviousMode = ExGetPreviousMode();
-
- Status = ObReferenceObjectByHandle(ProfileHandle,
- STANDARD_RIGHTS_ALL,
- ExProfileObjectType,
- PreviousMode,
- (PVOID*)&Profile,
- NULL);
- if (!NT_SUCCESS(Status))
+ KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+ ULONG ReturnInterval;
+ NTSTATUS Status = STATUS_SUCCESS;
+ PAGED_CODE();
+
+ /* Check if we were called from user-mode */
+ if (PreviousMode != KernelMode)
{
- return(Status);
+ /* Enter SEH Block */
+ _SEH2_TRY
+ {
+ /* Validate interval */
+ ProbeForWriteUlong(Interval);
+ }
+ _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+ {
+ /* Return the exception code */
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
}
- Profile->Started = TRUE;
- ObDereferenceObject(Profile);
- return(STATUS_SUCCESS);
-}
-NTSTATUS STDCALL
-NtStopProfile(IN HANDLE ProfileHandle)
-{
- PKPROFILE Profile;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status;
-
- PreviousMode = ExGetPreviousMode();
-
- Status = ObReferenceObjectByHandle(ProfileHandle,
- STANDARD_RIGHTS_ALL,
- ExProfileObjectType,
- PreviousMode,
- (PVOID*)&Profile,
- NULL);
- if (!NT_SUCCESS(Status))
+ /* Query the Interval */
+ ReturnInterval = KeQueryIntervalProfile(ProfileSource);
+
+ /* Enter SEH block for return */
+ _SEH2_TRY
+ {
+ /* Return the data */
+ *Interval = ReturnInterval;
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
{
- return(Status);
+ /* Get the exception code */
+ Status = _SEH2_GetExceptionCode();
}
- Profile->Started = FALSE;
- ObDereferenceObject(Profile);
- return(STATUS_SUCCESS);
+ _SEH2_END;
+
+ /* Return Success */
+ return Status;
}
+NTSTATUS
+NTAPI
+NtSetIntervalProfile(IN ULONG Interval,
+ IN KPROFILE_SOURCE Source)
+{
+ /* Let the Kernel do the job */
+ KeSetIntervalProfile(Interval, Source);
+ /* Nothing can go wrong */
+ return STATUS_SUCCESS;
+}