Standardize comment headers. Patch by Trevor McCort
[reactos.git] / reactos / ntoskrnl / ex / profile.c
1 /* $Id:$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/nt/profile.c
6 * PURPOSE: Support for profiling
7 *
8 * PROGRAMMERS: No programmer listed.
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #include <internal/debug.h>
15
16 /* TYPES ********************************************************************/
17
18 /* GLOBALS *******************************************************************/
19
20 POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
21
22 static GENERIC_MAPPING ExpProfileMapping = {
23 STANDARD_RIGHTS_READ,
24 STANDARD_RIGHTS_WRITE,
25 STANDARD_RIGHTS_EXECUTE,
26 STANDARD_RIGHTS_ALL};
27
28 /*
29 * Size of the profile hash table.
30 */
31 #define PROFILE_HASH_TABLE_SIZE (32)
32
33 /*
34 * Table of lists of per-process profiling data structures hashed by PID.
35 */
36 LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
37
38 /*
39 * Head of the list of profile data structures for the kernel.
40 */
41 LIST_ENTRY SystemProfileList;
42
43 /*
44 * Lock that protects the profiling data structures.
45 */
46 KSPIN_LOCK ProfileListLock;
47
48 /*
49 * Timer interrupts happen before we have initialized the profiling
50 * data structures so just ignore them before that.
51 */
52 BOOLEAN ProfileInitDone = FALSE;
53
54 VOID INIT_FUNCTION
55 ExpInitializeProfileImplementation(VOID)
56 {
57 ULONG i;
58
59 InitializeListHead(&SystemProfileList);
60
61 for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++)
62 {
63 InitializeListHead(&ProcessProfileListHashTable[i]);
64 }
65
66 KeInitializeSpinLock(&ProfileListLock);
67 ProfileInitDone = TRUE;
68
69 ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
70
71 RtlCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile");
72
73 ExProfileObjectType->Tag = TAG('P', 'R', 'O', 'F');
74 ExProfileObjectType->PeakObjects = 0;
75 ExProfileObjectType->PeakHandles = 0;
76 ExProfileObjectType->TotalObjects = 0;
77 ExProfileObjectType->TotalHandles = 0;
78 ExProfileObjectType->PagedPoolCharge = 0;
79 ExProfileObjectType->NonpagedPoolCharge = sizeof(KPROFILE);
80 ExProfileObjectType->Mapping = &ExpProfileMapping;
81 ExProfileObjectType->Dump = NULL;
82 ExProfileObjectType->Open = NULL;
83 ExProfileObjectType->Close = NULL;
84 ExProfileObjectType->Delete = KiDeleteProfile;
85 ExProfileObjectType->Parse = NULL;
86 ExProfileObjectType->Security = NULL;
87 ExProfileObjectType->QueryName = NULL;
88 ExProfileObjectType->OkayToClose = NULL;
89 ExProfileObjectType->Create = NULL;
90
91 ObpCreateTypeObject(ExProfileObjectType);
92 }
93
94 NTSTATUS STDCALL
95 NtCreateProfile(OUT PHANDLE ProfileHandle,
96 IN HANDLE Process OPTIONAL,
97 IN PVOID ImageBase,
98 IN ULONG ImageSize,
99 IN ULONG BucketSize,
100 IN PVOID Buffer,
101 IN ULONG BufferSize,
102 IN KPROFILE_SOURCE ProfileSource,
103 IN KAFFINITY Affinity)
104 {
105 HANDLE hProfile;
106 PKPROFILE Profile;
107 PEPROCESS pProcess;
108 KPROCESSOR_MODE PreviousMode;
109 OBJECT_ATTRIBUTES ObjectAttributes;
110 NTSTATUS Status = STATUS_SUCCESS;
111
112 PreviousMode = ExGetPreviousMode();
113
114 if(BufferSize == 0)
115 {
116 return STATUS_INVALID_PARAMETER_7;
117 }
118
119 if(PreviousMode != KernelMode)
120 {
121 _SEH_TRY
122 {
123 ProbeForWrite(ProfileHandle,
124 sizeof(HANDLE),
125 sizeof(ULONG));
126 ProbeForWrite(Buffer,
127 BufferSize,
128 sizeof(ULONG));
129 }
130 _SEH_HANDLE
131 {
132 Status = _SEH_GetExceptionCode();
133 }
134 _SEH_END;
135
136 if(!NT_SUCCESS(Status))
137 {
138 return Status;
139 }
140 }
141
142 /*
143 * Reference the associated process
144 */
145 if (Process != NULL)
146 {
147 Status = ObReferenceObjectByHandle(Process,
148 PROCESS_QUERY_INFORMATION,
149 PsProcessType,
150 PreviousMode,
151 (PVOID*)&pProcess,
152 NULL);
153 if (!NT_SUCCESS(Status))
154 {
155 return(Status);
156 }
157 }
158 else
159 {
160 pProcess = NULL;
161 if(!SeSinglePrivilegeCheck(SeSystemProfilePrivilege,
162 PreviousMode))
163 {
164 DPRINT1("NtCreateProfile: Caller requires the SeSystemProfilePrivilege privilege!\n");
165 return STATUS_PRIVILEGE_NOT_HELD;
166 }
167 }
168
169 /*
170 * Check the parameters
171 */
172 if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) ||
173 (pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE))
174 {
175 return(STATUS_INVALID_PARAMETER_3);
176 }
177 if (((ImageSize >> BucketSize) * 4) >= BufferSize)
178 {
179 return(STATUS_BUFFER_TOO_SMALL);
180 }
181 if (ProfileSource != ProfileTime)
182 {
183 return(STATUS_INVALID_PARAMETER_9);
184 }
185 if (Affinity != 0)
186 {
187 return(STATUS_INVALID_PARAMETER_10);
188 }
189
190 /*
191 * Create the object
192 */
193 InitializeObjectAttributes(&ObjectAttributes,
194 NULL,
195 0,
196 NULL,
197 NULL);
198
199 Status = ObCreateObject(KernelMode,
200 ExProfileObjectType,
201 &ObjectAttributes,
202 PreviousMode,
203 NULL,
204 sizeof(KPROFILE),
205 0,
206 0,
207 (PVOID*)&Profile);
208 if (!NT_SUCCESS(Status))
209 {
210 return(Status);
211 }
212
213 /*
214 * Initialize it
215 */
216 Profile->Base = ImageBase;
217 Profile->Size = ImageSize;
218 Profile->BucketShift = BucketSize;
219 Profile->BufferMdl = MmCreateMdl(NULL, Buffer, BufferSize);
220 if(Profile->BufferMdl == NULL) {
221 DPRINT("MmCreateMdl: Out of memory!");
222 ObDereferenceObject (Profile);
223 return(STATUS_NO_MEMORY);
224 }
225 MmProbeAndLockPages(Profile->BufferMdl, UserMode, IoWriteAccess);
226 Profile->Buffer = MmGetSystemAddressForMdl(Profile->BufferMdl);
227 Profile->BufferSize = BufferSize;
228 Profile->ProcessorMask = Affinity;
229 Profile->Started = FALSE;
230 Profile->Process = pProcess;
231
232 /*
233 * Insert the profile into the profile list data structures
234 */
235 KiInsertProfile(Profile);
236
237 Status = ObInsertObject ((PVOID)Profile,
238 NULL,
239 STANDARD_RIGHTS_ALL,
240 0,
241 NULL,
242 &hProfile);
243 if (!NT_SUCCESS(Status))
244 {
245 ObDereferenceObject (Profile);
246 return Status;
247 }
248
249 /*
250 * Copy the created handle back to the caller
251 */
252 _SEH_TRY
253 {
254 *ProfileHandle = hProfile;
255 }
256 _SEH_HANDLE
257 {
258 Status = _SEH_GetExceptionCode();
259 }
260 _SEH_END;
261
262 ObDereferenceObject(Profile);
263
264 return Status;
265 }
266
267 NTSTATUS STDCALL
268 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
269 OUT PULONG Interval)
270 {
271 KPROCESSOR_MODE PreviousMode;
272 NTSTATUS Status = STATUS_SUCCESS;
273
274 PreviousMode = ExGetPreviousMode();
275
276 if(PreviousMode != KernelMode)
277 {
278 _SEH_TRY
279 {
280 ProbeForWrite(Interval,
281 sizeof(ULONG),
282 sizeof(ULONG));
283 }
284 _SEH_HANDLE
285 {
286 Status = _SEH_GetExceptionCode();
287 }
288 _SEH_END;
289
290 if(!NT_SUCCESS(Status))
291 {
292 return Status;
293 }
294 }
295
296 if (ProfileSource == ProfileTime)
297 {
298 ULONG ReturnInterval;
299
300 /* FIXME: What units does this use, for now nanoseconds */
301 ReturnInterval = 100;
302
303 _SEH_TRY
304 {
305 *Interval = ReturnInterval;
306 }
307 _SEH_HANDLE
308 {
309 Status = _SEH_GetExceptionCode();
310 }
311 _SEH_END;
312
313 return Status;
314 }
315 return STATUS_INVALID_PARAMETER_2;
316 }
317
318 NTSTATUS STDCALL
319 NtSetIntervalProfile(IN ULONG Interval,
320 IN KPROFILE_SOURCE Source)
321 {
322 return(STATUS_NOT_IMPLEMENTED);
323 }
324
325 NTSTATUS STDCALL
326 NtStartProfile(IN HANDLE ProfileHandle)
327 {
328 PKPROFILE Profile;
329 KPROCESSOR_MODE PreviousMode;
330 NTSTATUS Status;
331
332 PreviousMode = ExGetPreviousMode();
333
334 Status = ObReferenceObjectByHandle(ProfileHandle,
335 STANDARD_RIGHTS_ALL,
336 ExProfileObjectType,
337 PreviousMode,
338 (PVOID*)&Profile,
339 NULL);
340 if (!NT_SUCCESS(Status))
341 {
342 return(Status);
343 }
344 Profile->Started = TRUE;
345 ObDereferenceObject(Profile);
346 return(STATUS_SUCCESS);
347 }
348
349 NTSTATUS STDCALL
350 NtStopProfile(IN HANDLE ProfileHandle)
351 {
352 PKPROFILE Profile;
353 KPROCESSOR_MODE PreviousMode;
354 NTSTATUS Status;
355
356 PreviousMode = ExGetPreviousMode();
357
358 Status = ObReferenceObjectByHandle(ProfileHandle,
359 STANDARD_RIGHTS_ALL,
360 ExProfileObjectType,
361 PreviousMode,
362 (PVOID*)&Profile,
363 NULL);
364 if (!NT_SUCCESS(Status))
365 {
366 return(Status);
367 }
368 Profile->Started = FALSE;
369 ObDereferenceObject(Profile);
370 return(STATUS_SUCCESS);
371 }
372
373