ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

profile.c
Go to the documentation of this file.
00001 /*
00002  * COPYRIGHT:       See COPYING in the top level directory
00003  * PROJECT:         ReactOS Kernel
00004  * FILE:            ntoskrnl/ex/profile.c
00005  * PURPOSE:         Support for Executive Profile Objects
00006  * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
00007  *                  Thomas Weidenmueller
00008  */
00009 
00010 /* INCLUDES *****************************************************************/
00011 
00012 #include <ntoskrnl.h>
00013 #define NDEBUG
00014 #include <debug.h>
00015 
00016 #if defined (ALLOC_PRAGMA)
00017 #pragma alloc_text(INIT, ExpInitializeProfileImplementation)
00018 #endif
00019 
00020 #define TAG_PROFILE 'forP'
00021 
00022 /* GLOBALS *******************************************************************/
00023 
00024 POBJECT_TYPE ExProfileObjectType = NULL;
00025 KMUTEX ExpProfileMutex;
00026 
00027 GENERIC_MAPPING ExpProfileMapping =
00028 {
00029     STANDARD_RIGHTS_READ    | PROFILE_CONTROL,
00030     STANDARD_RIGHTS_WRITE   | PROFILE_CONTROL,
00031     STANDARD_RIGHTS_EXECUTE | PROFILE_CONTROL,
00032     PROFILE_ALL_ACCESS
00033 };
00034 
00035 /* FUNCTIONS *****************************************************************/
00036 
00037 VOID
00038 NTAPI
00039 ExpDeleteProfile(PVOID ObjectBody)
00040 {
00041     PEPROFILE Profile;
00042     ULONG State;
00043 
00044     /* Typecast the Object */
00045     Profile = (PEPROFILE)ObjectBody;
00046 
00047     /* Check if there if the Profile was started */
00048     if (Profile->LockedBufferAddress)
00049     {
00050         /* Stop the Profile */
00051         State = KeStopProfile(Profile->ProfileObject);
00052         ASSERT(State != FALSE);
00053 
00054         /* Unmap the Locked Buffer */
00055         MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl);
00056         MmUnlockPages(Profile->Mdl);
00057         IoFreeMdl(Profile->Mdl);
00058     }
00059 
00060     /* Check if a Process is associated and reference it */
00061     if (Profile->Process) ObDereferenceObject(Profile->Process);
00062 }
00063 
00064 VOID
00065 INIT_FUNCTION
00066 NTAPI
00067 ExpInitializeProfileImplementation(VOID)
00068 {
00069     OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
00070     UNICODE_STRING Name;
00071     DPRINT("Creating Profile Object Type\n");
00072 
00073     /* Initialize the Mutex to lock the States */
00074     KeInitializeMutex(&ExpProfileMutex, 64);
00075 
00076     /* Create the Event Pair Object Type */
00077     RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
00078     RtlInitUnicodeString(&Name, L"Profile");
00079     ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
00080     ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(KPROFILE);
00081     ObjectTypeInitializer.GenericMapping = ExpProfileMapping;
00082     ObjectTypeInitializer.PoolType = NonPagedPool;
00083     ObjectTypeInitializer.DeleteProcedure = ExpDeleteProfile;
00084     ObjectTypeInitializer.ValidAccessMask = PROFILE_ALL_ACCESS;
00085     ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExProfileObjectType);
00086 }
00087 
00088 NTSTATUS
00089 NTAPI
00090 NtCreateProfile(OUT PHANDLE ProfileHandle,
00091                 IN HANDLE Process OPTIONAL,
00092                 IN PVOID RangeBase,
00093                 IN ULONG RangeSize,
00094                 IN ULONG BucketSize,
00095                 IN PVOID Buffer,
00096                 IN ULONG BufferSize,
00097                 IN KPROFILE_SOURCE ProfileSource,
00098                 IN KAFFINITY Affinity)
00099 {
00100     HANDLE hProfile;
00101     PEPROFILE Profile;
00102     PEPROCESS pProcess;
00103     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00104     OBJECT_ATTRIBUTES ObjectAttributes;
00105     NTSTATUS Status;
00106     ULONG Log2 = 0;
00107     ULONG_PTR Segment = 0;
00108     PAGED_CODE();
00109 
00110     /* Easy way out */
00111     if(!BufferSize) return STATUS_INVALID_PARAMETER_7;
00112 
00113     /* Check if this is a low-memory profile */
00114     if ((!BucketSize) && (RangeBase < (PVOID)(0x10000)))
00115     {
00116         /* Validate size */
00117         if (BufferSize < sizeof(ULONG)) return STATUS_INVALID_PARAMETER_7;
00118 
00119         /* This will become a segmented profile object */
00120         Segment = (ULONG_PTR)RangeBase;
00121         RangeBase = 0;
00122 
00123         /* Recalculate the bucket size */
00124         BucketSize = RangeSize / (BufferSize / sizeof(ULONG));
00125 
00126         /* Convert it to log2 */
00127         BucketSize--;
00128         while (BucketSize >>= 1) Log2++;
00129         BucketSize += Log2 + 1;
00130     }
00131 
00132     /* Validate bucket size */
00133     if ((BucketSize > 31) || (BucketSize < 2))
00134     {
00135         DPRINT1("Bucket size invalid\n");
00136         return STATUS_INVALID_PARAMETER;
00137     }
00138 
00139     /* Make sure that the buckets can map the range */
00140     if ((RangeSize >> (BucketSize - 2)) > BufferSize)
00141     {
00142         DPRINT1("Bucket size too small\n");
00143         return STATUS_BUFFER_TOO_SMALL;
00144     }
00145 
00146     /* Make sure that the range isn't too gigantic */
00147     if (((ULONG_PTR)RangeBase + RangeSize) < RangeSize)
00148     {
00149         DPRINT1("Range too big\n");
00150         return STATUS_BUFFER_OVERFLOW;
00151     }
00152 
00153     /* Check if we were called from user-mode */
00154     if(PreviousMode != KernelMode)
00155     {
00156         /* Entry SEH */
00157         _SEH2_TRY
00158         {
00159             /* Make sure that the handle pointer is valid */
00160             ProbeForWriteHandle(ProfileHandle);
00161 
00162             /* Check if the buffer is valid */
00163             ProbeForWrite(Buffer,
00164                           BufferSize,
00165                           sizeof(ULONG));
00166         }
00167         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00168         {
00169             /* Return the exception code */
00170             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00171         }
00172         _SEH2_END;
00173     }
00174 
00175     /* Check if a process was specified */
00176     if (Process)
00177     {
00178         /* Reference it */
00179         Status = ObReferenceObjectByHandle(Process,
00180                                            PROCESS_QUERY_INFORMATION,
00181                                            PsProcessType,
00182                                            PreviousMode,
00183                                            (PVOID*)&pProcess,
00184                                            NULL);
00185         if (!NT_SUCCESS(Status)) return(Status);
00186     }
00187     else
00188     {
00189         /* Segmented profile objects cannot be used system-wide */
00190         if (Segment) return STATUS_INVALID_PARAMETER;
00191 
00192         /* No process was specified, which means a System-Wide Profile */
00193         pProcess = NULL;
00194 
00195         /* For this, we need to check the Privilege */
00196         if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege, PreviousMode))
00197         {
00198             DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
00199             return STATUS_PRIVILEGE_NOT_HELD;
00200         }
00201     }
00202 
00203     /* Create the object */
00204     InitializeObjectAttributes(&ObjectAttributes,
00205                                NULL,
00206                                0,
00207                                NULL,
00208                                NULL);
00209     Status = ObCreateObject(KernelMode,
00210                             ExProfileObjectType,
00211                             &ObjectAttributes,
00212                             PreviousMode,
00213                             NULL,
00214                             sizeof(EPROFILE),
00215                             0,
00216                             sizeof(EPROFILE) + sizeof(KPROFILE),
00217                             (PVOID*)&Profile);
00218     if (!NT_SUCCESS(Status))
00219     {
00220         /* Dereference the process object if it was specified */
00221         if (pProcess) ObDereferenceObject(pProcess);
00222 
00223         /* Return Status */
00224         return Status;
00225     }
00226 
00227     /* Initialize it */
00228     Profile->RangeBase = RangeBase;
00229     Profile->RangeSize = RangeSize;
00230     Profile->Buffer = Buffer;
00231     Profile->BufferSize = BufferSize;
00232     Profile->BucketSize = BucketSize;
00233     Profile->LockedBufferAddress = NULL;
00234     Profile->Segment = Segment;
00235     Profile->ProfileSource = ProfileSource;
00236     Profile->Affinity = Affinity;
00237     Profile->Process = pProcess;
00238 
00239     /* Insert into the Object Tree */
00240     Status = ObInsertObject ((PVOID)Profile,
00241                              NULL,
00242                              PROFILE_CONTROL,
00243                              0,
00244                              NULL,
00245                              &hProfile);
00246     ObDereferenceObject(Profile);
00247 
00248     /* Check for Success */
00249     if (!NT_SUCCESS(Status))
00250     {
00251         /* Dereference Process on failure */
00252         if (pProcess) ObDereferenceObject(pProcess);
00253         return Status;
00254     }
00255 
00256     /* Enter SEH */
00257     _SEH2_TRY
00258     {
00259         /* Copy the created handle back to the caller*/
00260         *ProfileHandle = hProfile;
00261     }
00262     _SEH2_EXCEPT(ExSystemExceptionFilter())
00263     {
00264         Status = _SEH2_GetExceptionCode();
00265     }
00266     _SEH2_END;
00267 
00268     /* Return Status */
00269     return Status;
00270 }
00271 
00272 NTSTATUS
00273 NTAPI
00274 NtQueryPerformanceCounter(OUT PLARGE_INTEGER PerformanceCounter,
00275                           OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL)
00276 {
00277     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00278     LARGE_INTEGER PerfFrequency;
00279     NTSTATUS Status = STATUS_SUCCESS;
00280 
00281     /* Check if we were called from user-mode */
00282     if (PreviousMode != KernelMode)
00283     {
00284         /* Entry SEH Block */
00285         _SEH2_TRY
00286         {
00287             /* Make sure the counter and frequency are valid */
00288             ProbeForWriteLargeInteger(PerformanceCounter);
00289             if (PerformanceFrequency)
00290             {
00291                 ProbeForWriteLargeInteger(PerformanceFrequency);
00292             }
00293         }
00294         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00295         {
00296             /* Return the exception code */
00297             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00298         }
00299         _SEH2_END;
00300     }
00301 
00302     /* Enter a new SEH Block */
00303     _SEH2_TRY
00304     {
00305         /* Query the Kernel */
00306         *PerformanceCounter = KeQueryPerformanceCounter(&PerfFrequency);
00307 
00308         /* Return Frequency if requested */
00309         if (PerformanceFrequency) *PerformanceFrequency = PerfFrequency;
00310     }
00311     _SEH2_EXCEPT(ExSystemExceptionFilter())
00312     {
00313         /* Get the exception code */
00314         Status = _SEH2_GetExceptionCode();
00315     }
00316     _SEH2_END;
00317 
00318     /* Return status to caller */
00319     return Status;
00320 }
00321 
00322 NTSTATUS
00323 NTAPI
00324 NtStartProfile(IN HANDLE ProfileHandle)
00325 {
00326     PEPROFILE Profile;
00327     PKPROFILE ProfileObject;
00328     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00329     PVOID TempLockedBufferAddress;
00330     NTSTATUS Status;
00331     PAGED_CODE();
00332 
00333     /* Get the Object */
00334     Status = ObReferenceObjectByHandle(ProfileHandle,
00335                                        PROFILE_CONTROL,
00336                                        ExProfileObjectType,
00337                                        PreviousMode,
00338                                        (PVOID*)&Profile,
00339                                        NULL);
00340     if (!NT_SUCCESS(Status)) return(Status);
00341 
00342     /* To avoid a Race, wait on the Mutex */
00343     KeWaitForSingleObject(&ExpProfileMutex,
00344                           Executive,
00345                           KernelMode,
00346                           FALSE,
00347                           NULL);
00348 
00349     /* The Profile can still be enabled though, so handle that */
00350     if (Profile->LockedBufferAddress)
00351     {
00352         /* Release our lock, dereference and return */
00353         KeReleaseMutex(&ExpProfileMutex, FALSE);
00354         ObDereferenceObject(Profile);
00355         return STATUS_PROFILING_NOT_STOPPED;
00356     }
00357 
00358     /* Allocate a Kernel Profile Object. */
00359     ProfileObject = ExAllocatePoolWithTag(NonPagedPool,
00360                                           sizeof(EPROFILE),
00361                                           TAG_PROFILE);
00362     if (!ProfileObject)
00363     {
00364         /* Out of memory, fail */
00365         KeReleaseMutex(&ExpProfileMutex, FALSE);
00366         ObDereferenceObject(Profile);
00367         return STATUS_INSUFFICIENT_RESOURCES;
00368     }
00369 
00370     /* Allocate the Mdl Structure */
00371     Profile->Mdl = IoAllocateMdl(Profile->Buffer, Profile->BufferSize, FALSE, FALSE, NULL);
00372 
00373     /* Protect this in SEH as we might raise an exception */
00374     _SEH2_TRY
00375     {
00376         /* Probe and Lock for Write Access */
00377         MmProbeAndLockPages(Profile->Mdl, PreviousMode, IoWriteAccess);
00378     }
00379     _SEH2_EXCEPT(ExSystemExceptionFilter())
00380     {
00381         /* Release our lock, free the buffer, dereference and return */
00382         KeReleaseMutex(&ExpProfileMutex, FALSE);
00383         ObDereferenceObject(Profile);
00384         ExFreePoolWithTag(ProfileObject, TAG_PROFILE);
00385         _SEH2_YIELD(return _SEH2_GetExceptionCode());
00386     }
00387     _SEH2_END;
00388 
00389     /* Map the pages */
00390     TempLockedBufferAddress = MmMapLockedPages(Profile->Mdl, KernelMode);
00391 
00392     /* Initialize the Kernel Profile Object */
00393     Profile->ProfileObject = ProfileObject;
00394     KeInitializeProfile(ProfileObject,
00395                         (PKPROCESS)Profile->Process,
00396                         Profile->RangeBase,
00397                         Profile->RangeSize,
00398                         Profile->BucketSize,
00399                         Profile->ProfileSource,
00400                         Profile->Affinity);
00401 
00402     /* Start the Profiling */
00403     KeStartProfile(ProfileObject, TempLockedBufferAddress);
00404 
00405     /* Now it's safe to save this */
00406     Profile->LockedBufferAddress = TempLockedBufferAddress;
00407 
00408     /* Release mutex, dereference and return */
00409     KeReleaseMutex(&ExpProfileMutex, FALSE);
00410     ObDereferenceObject(Profile);
00411     return STATUS_SUCCESS;
00412 }
00413 
00414 NTSTATUS
00415 NTAPI
00416 NtStopProfile(IN HANDLE ProfileHandle)
00417 {
00418     PEPROFILE Profile;
00419     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00420     NTSTATUS Status;
00421     PAGED_CODE();
00422 
00423     /* Get the Object */
00424     Status = ObReferenceObjectByHandle(ProfileHandle,
00425                                        PROFILE_CONTROL,
00426                                        ExProfileObjectType,
00427                                        PreviousMode,
00428                                        (PVOID*)&Profile,
00429                                        NULL);
00430     if (!NT_SUCCESS(Status)) return(Status);
00431 
00432     /* Get the Mutex */
00433     KeWaitForSingleObject(&ExpProfileMutex,
00434                           Executive,
00435                           KernelMode,
00436                           FALSE,
00437                           NULL);
00438 
00439     /* Make sure the Profile Object is really Started */
00440     if (!Profile->LockedBufferAddress)
00441     {
00442         Status = STATUS_PROFILING_NOT_STARTED;
00443         goto Exit;
00444     }
00445 
00446     /* Stop the Profile */
00447     KeStopProfile(Profile->ProfileObject);
00448 
00449     /* Unlock the Buffer */
00450     MmUnmapLockedPages(Profile->LockedBufferAddress, Profile->Mdl);
00451     MmUnlockPages(Profile->Mdl);
00452     ExFreePoolWithTag(Profile->ProfileObject, TAG_PROFILE);
00453 
00454     /* Clear the Locked Buffer pointer, meaning the Object is Stopped */
00455     Profile->LockedBufferAddress = NULL;
00456 
00457 Exit:
00458     /* Release Mutex, Dereference and Return */
00459     KeReleaseMutex(&ExpProfileMutex, FALSE);
00460     ObDereferenceObject(Profile);
00461     return Status;
00462 }
00463 
00464 NTSTATUS
00465 NTAPI
00466 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
00467                        OUT PULONG Interval)
00468 {
00469     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
00470     ULONG ReturnInterval;
00471     NTSTATUS Status = STATUS_SUCCESS;
00472     PAGED_CODE();
00473 
00474     /* Check if we were called from user-mode */
00475     if (PreviousMode != KernelMode)
00476     {
00477         /* Enter SEH Block */
00478         _SEH2_TRY
00479         {
00480             /* Validate interval */
00481             ProbeForWriteUlong(Interval);
00482         }
00483         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
00484         {
00485             /* Return the exception code */
00486             _SEH2_YIELD(return _SEH2_GetExceptionCode());
00487         }
00488         _SEH2_END;
00489     }
00490 
00491     /* Query the Interval */
00492     ReturnInterval = (ULONG)KeQueryIntervalProfile(ProfileSource);
00493 
00494     /* Enter SEH block for return */
00495     _SEH2_TRY
00496     {
00497         /* Return the data */
00498         *Interval = ReturnInterval;
00499     }
00500     _SEH2_EXCEPT(ExSystemExceptionFilter())
00501     {
00502         /* Get the exception code */
00503         Status = _SEH2_GetExceptionCode();
00504     }
00505     _SEH2_END;
00506 
00507     /* Return Success */
00508     return Status;
00509 }
00510 
00511 NTSTATUS
00512 NTAPI
00513 NtSetIntervalProfile(IN ULONG Interval,
00514                      IN KPROFILE_SOURCE Source)
00515 {
00516     /* Let the Kernel do the job */
00517     KeSetIntervalProfile(Interval, Source);
00518 
00519     /* Nothing can go wrong */
00520     return STATUS_SUCCESS;
00521 }

Generated on Thu May 24 2012 04:24:25 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.