3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/nt/profile.c
22 * PURPOSE: Support for profiling
28 /* INCLUDES *****************************************************************/
31 #include <internal/debug.h>
33 /* TYPES ********************************************************************/
35 /* GLOBALS *******************************************************************/
37 POBJECT_TYPE EXPORTED ExProfileObjectType
= NULL
;
39 static GENERIC_MAPPING ExpProfileMapping
= {
41 STANDARD_RIGHTS_WRITE
,
42 STANDARD_RIGHTS_EXECUTE
,
46 * Size of the profile hash table.
48 #define PROFILE_HASH_TABLE_SIZE (32)
51 * Table of lists of per-process profiling data structures hashed by PID.
53 LIST_ENTRY ProcessProfileListHashTable
[PROFILE_HASH_TABLE_SIZE
];
56 * Head of the list of profile data structures for the kernel.
58 LIST_ENTRY SystemProfileList
;
61 * Lock that protects the profiling data structures.
63 KSPIN_LOCK ProfileListLock
;
66 * Timer interrupts happen before we have initialized the profiling
67 * data structures so just ignore them before that.
69 BOOLEAN ProfileInitDone
= FALSE
;
72 ExpInitializeProfileImplementation(VOID
)
76 InitializeListHead(&SystemProfileList
);
78 for (i
= 0; i
< PROFILE_HASH_TABLE_SIZE
; i
++)
80 InitializeListHead(&ProcessProfileListHashTable
[i
]);
83 KeInitializeSpinLock(&ProfileListLock
);
84 ProfileInitDone
= TRUE
;
86 ExProfileObjectType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
88 RtlCreateUnicodeString(&ExProfileObjectType
->TypeName
, L
"Profile");
90 ExProfileObjectType
->Tag
= TAG('P', 'R', 'O', 'F');
91 ExProfileObjectType
->PeakObjects
= 0;
92 ExProfileObjectType
->PeakHandles
= 0;
93 ExProfileObjectType
->TotalObjects
= 0;
94 ExProfileObjectType
->TotalHandles
= 0;
95 ExProfileObjectType
->PagedPoolCharge
= 0;
96 ExProfileObjectType
->NonpagedPoolCharge
= sizeof(KPROFILE
);
97 ExProfileObjectType
->Mapping
= &ExpProfileMapping
;
98 ExProfileObjectType
->Dump
= NULL
;
99 ExProfileObjectType
->Open
= NULL
;
100 ExProfileObjectType
->Close
= NULL
;
101 ExProfileObjectType
->Delete
= KiDeleteProfile
;
102 ExProfileObjectType
->Parse
= NULL
;
103 ExProfileObjectType
->Security
= NULL
;
104 ExProfileObjectType
->QueryName
= NULL
;
105 ExProfileObjectType
->OkayToClose
= NULL
;
106 ExProfileObjectType
->Create
= NULL
;
108 ObpCreateTypeObject(ExProfileObjectType
);
112 NtCreateProfile(OUT PHANDLE ProfileHandle
,
113 IN HANDLE Process OPTIONAL
,
119 IN KPROFILE_SOURCE ProfileSource
,
120 IN KAFFINITY Affinity
)
125 KPROCESSOR_MODE PreviousMode
;
126 OBJECT_ATTRIBUTES ObjectAttributes
;
127 NTSTATUS Status
= STATUS_SUCCESS
;
129 PreviousMode
= ExGetPreviousMode();
133 return STATUS_INVALID_PARAMETER_7
;
136 if(PreviousMode
!= KernelMode
)
140 ProbeForWrite(ProfileHandle
,
143 ProbeForWrite(Buffer
,
149 Status
= _SEH_GetExceptionCode();
153 if(!NT_SUCCESS(Status
))
160 * Reference the associated process
164 Status
= ObReferenceObjectByHandle(Process
,
165 PROCESS_QUERY_INFORMATION
,
170 if (!NT_SUCCESS(Status
))
178 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege
,
181 return STATUS_PRIVILEGE_NOT_HELD
;
186 * Check the parameters
188 if ((pProcess
== NULL
&& ImageBase
< (PVOID
)KERNEL_BASE
) ||
189 (pProcess
!= NULL
&& ImageBase
>= (PVOID
)KERNEL_BASE
))
191 return(STATUS_INVALID_PARAMETER_3
);
193 if (((ImageSize
>> BucketSize
) * 4) >= BufferSize
)
195 return(STATUS_BUFFER_TOO_SMALL
);
197 if (ProfileSource
!= ProfileTime
)
199 return(STATUS_INVALID_PARAMETER_9
);
203 return(STATUS_INVALID_PARAMETER_10
);
209 InitializeObjectAttributes(&ObjectAttributes
,
215 Status
= ObCreateObject(KernelMode
,
224 if (!NT_SUCCESS(Status
))
232 Profile
->Base
= ImageBase
;
233 Profile
->Size
= ImageSize
;
234 Profile
->BucketShift
= BucketSize
;
235 Profile
->BufferMdl
= MmCreateMdl(NULL
, Buffer
, BufferSize
);
236 if(Profile
->BufferMdl
== NULL
) {
237 DPRINT("MmCreateMdl: Out of memory!");
238 ObDereferenceObject (Profile
);
239 return(STATUS_NO_MEMORY
);
241 MmProbeAndLockPages(Profile
->BufferMdl
, UserMode
, IoWriteAccess
);
242 Profile
->Buffer
= MmGetSystemAddressForMdl(Profile
->BufferMdl
);
243 Profile
->BufferSize
= BufferSize
;
244 Profile
->ProcessorMask
= Affinity
;
245 Profile
->Started
= FALSE
;
246 Profile
->Process
= pProcess
;
249 * Insert the profile into the profile list data structures
251 KiInsertProfile(Profile
);
253 Status
= ObInsertObject ((PVOID
)Profile
,
259 if (!NT_SUCCESS(Status
))
261 ObDereferenceObject (Profile
);
266 * Copy the created handle back to the caller
270 *ProfileHandle
= hProfile
;
274 Status
= _SEH_GetExceptionCode();
278 ObDereferenceObject(Profile
);
284 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource
,
287 KPROCESSOR_MODE PreviousMode
;
288 NTSTATUS Status
= STATUS_SUCCESS
;
290 PreviousMode
= ExGetPreviousMode();
292 if(PreviousMode
!= KernelMode
)
296 ProbeForWrite(Interval
,
302 Status
= _SEH_GetExceptionCode();
306 if(!NT_SUCCESS(Status
))
312 if (ProfileSource
== ProfileTime
)
314 ULONG ReturnInterval
;
316 /* FIXME: What units does this use, for now nanoseconds */
317 ReturnInterval
= 100;
321 *Interval
= ReturnInterval
;
325 Status
= _SEH_GetExceptionCode();
331 return STATUS_INVALID_PARAMETER_2
;
335 NtSetIntervalProfile(IN ULONG Interval
,
336 IN KPROFILE_SOURCE Source
)
338 return(STATUS_NOT_IMPLEMENTED
);
342 NtStartProfile(IN HANDLE ProfileHandle
)
345 KPROCESSOR_MODE PreviousMode
;
348 PreviousMode
= ExGetPreviousMode();
350 Status
= ObReferenceObjectByHandle(ProfileHandle
,
356 if (!NT_SUCCESS(Status
))
360 Profile
->Started
= TRUE
;
361 ObDereferenceObject(Profile
);
362 return(STATUS_SUCCESS
);
366 NtStopProfile(IN HANDLE ProfileHandle
)
369 KPROCESSOR_MODE PreviousMode
;
372 PreviousMode
= ExGetPreviousMode();
374 Status
= ObReferenceObjectByHandle(ProfileHandle
,
380 if (!NT_SUCCESS(Status
))
384 Profile
->Started
= FALSE
;
385 ObDereferenceObject(Profile
);
386 return(STATUS_SUCCESS
);