Remove /nt directory
[reactos.git] / reactos / ntoskrnl / ex / profile.c
1 /*
2 * ReactOS kernel
3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
4 *
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.
9 *
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.
14 *
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.
18 */
19 /*
20 * PROJECT: ReactOS kernel
21 * FILE: ntoskrnl/nt/profile.c
22 * PURPOSE: Support for profiling
23 * PROGRAMMER: Nobody
24 * UPDATE HISTORY:
25 *
26 */
27
28 /* INCLUDES *****************************************************************/
29
30 #include <ntoskrnl.h>
31 #include <internal/debug.h>
32
33 /* TYPES ********************************************************************/
34
35 /* GLOBALS *******************************************************************/
36
37 POBJECT_TYPE EXPORTED ExProfileObjectType = NULL;
38
39 static GENERIC_MAPPING ExpProfileMapping = {
40 STANDARD_RIGHTS_READ,
41 STANDARD_RIGHTS_WRITE,
42 STANDARD_RIGHTS_EXECUTE,
43 STANDARD_RIGHTS_ALL};
44
45 /*
46 * Size of the profile hash table.
47 */
48 #define PROFILE_HASH_TABLE_SIZE (32)
49
50 /*
51 * Table of lists of per-process profiling data structures hashed by PID.
52 */
53 LIST_ENTRY ProcessProfileListHashTable[PROFILE_HASH_TABLE_SIZE];
54
55 /*
56 * Head of the list of profile data structures for the kernel.
57 */
58 LIST_ENTRY SystemProfileList;
59
60 /*
61 * Lock that protects the profiling data structures.
62 */
63 KSPIN_LOCK ProfileListLock;
64
65 /*
66 * Timer interrupts happen before we have initialized the profiling
67 * data structures so just ignore them before that.
68 */
69 BOOLEAN ProfileInitDone = FALSE;
70
71 VOID INIT_FUNCTION
72 ExpInitializeProfileImplementation(VOID)
73 {
74 ULONG i;
75
76 InitializeListHead(&SystemProfileList);
77
78 for (i = 0; i < PROFILE_HASH_TABLE_SIZE; i++)
79 {
80 InitializeListHead(&ProcessProfileListHashTable[i]);
81 }
82
83 KeInitializeSpinLock(&ProfileListLock);
84 ProfileInitDone = TRUE;
85
86 ExProfileObjectType = ExAllocatePool(NonPagedPool,sizeof(OBJECT_TYPE));
87
88 RtlCreateUnicodeString(&ExProfileObjectType->TypeName, L"Profile");
89
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;
107
108 ObpCreateTypeObject(ExProfileObjectType);
109 }
110
111 NTSTATUS STDCALL
112 NtCreateProfile(OUT PHANDLE ProfileHandle,
113 IN HANDLE Process OPTIONAL,
114 IN PVOID ImageBase,
115 IN ULONG ImageSize,
116 IN ULONG BucketSize,
117 IN PVOID Buffer,
118 IN ULONG BufferSize,
119 IN KPROFILE_SOURCE ProfileSource,
120 IN KAFFINITY Affinity)
121 {
122 HANDLE SafeProfileHandle;
123 NTSTATUS Status;
124 PKPROFILE Profile;
125 PEPROCESS pProcess;
126
127 /*
128 * Reference the associated process
129 */
130 if (Process != NULL)
131 {
132 Status = ObReferenceObjectByHandle(Process,
133 PROCESS_QUERY_INFORMATION,
134 PsProcessType,
135 UserMode,
136 (PVOID*)&pProcess,
137 NULL);
138 if (!NT_SUCCESS(Status))
139 {
140 return(Status);
141 }
142 }
143 else
144 {
145 pProcess = NULL;
146 /* FIXME: Check privilege. */
147 }
148
149 /*
150 * Check the parameters
151 */
152 if ((pProcess == NULL && ImageBase < (PVOID)KERNEL_BASE) ||
153 (pProcess != NULL && ImageBase >= (PVOID)KERNEL_BASE))
154 {
155 return(STATUS_INVALID_PARAMETER_3);
156 }
157 if (((ImageSize >> BucketSize) * 4) >= BufferSize)
158 {
159 return(STATUS_BUFFER_TOO_SMALL);
160 }
161 if (ProfileSource != ProfileTime)
162 {
163 return(STATUS_INVALID_PARAMETER_9);
164 }
165 if (Affinity != 0)
166 {
167 return(STATUS_INVALID_PARAMETER_10);
168 }
169
170 /*
171 * Create the object
172 */
173 Status = ObCreateObject(ExGetPreviousMode(),
174 ExProfileObjectType,
175 NULL,
176 ExGetPreviousMode(),
177 NULL,
178 sizeof(KPROFILE),
179 0,
180 0,
181 (PVOID*)&Profile);
182 if (!NT_SUCCESS(Status))
183 {
184 return(Status);
185 }
186
187 /*
188 * Initialize it
189 */
190 Profile->Base = ImageBase;
191 Profile->Size = ImageSize;
192 Profile->BucketShift = BucketSize;
193 Profile->BufferMdl = MmCreateMdl(NULL, Buffer, BufferSize);
194 if(Profile->BufferMdl == NULL) {
195 DPRINT("MmCreateMdl: Out of memory!");
196 return(STATUS_NO_MEMORY);
197 }
198 MmProbeAndLockPages(Profile->BufferMdl, UserMode, IoWriteAccess);
199 Profile->Buffer = MmGetSystemAddressForMdl(Profile->BufferMdl);
200 Profile->BufferSize = BufferSize;
201 Profile->ProcessorMask = Affinity;
202 Profile->Started = FALSE;
203 Profile->Process = pProcess;
204
205 /*
206 * Insert the profile into the profile list data structures
207 */
208 KiInsertProfile(Profile);
209
210 Status = ObInsertObject ((PVOID)Profile,
211 NULL,
212 STANDARD_RIGHTS_ALL,
213 0,
214 NULL,
215 &SafeProfileHandle);
216 if (!NT_SUCCESS(Status))
217 {
218 ObDereferenceObject (Profile);
219 return Status;
220 }
221
222 /*
223 * Copy the created handle back to the caller
224 */
225 Status = MmCopyToCaller(ProfileHandle, &SafeProfileHandle, sizeof(HANDLE));
226 if (!NT_SUCCESS(Status))
227 {
228 ObDereferenceObject(Profile);
229 ZwClose(ProfileHandle);
230 return(Status);
231 }
232
233 ObDereferenceObject(Profile);
234
235 return(STATUS_SUCCESS);
236 }
237
238 NTSTATUS STDCALL
239 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource,
240 OUT PULONG Interval)
241 {
242 NTSTATUS Status;
243
244 if (ProfileSource == ProfileTime)
245 {
246 ULONG SafeInterval;
247
248 /* FIXME: What units does this use, for now nanoseconds */
249 SafeInterval = 100;
250 Status = MmCopyToCaller(Interval, &SafeInterval, sizeof(ULONG));
251 if (!NT_SUCCESS(Status))
252 {
253 return(Status);
254 }
255 return(STATUS_SUCCESS);
256 }
257 return(STATUS_INVALID_PARAMETER_2);
258 }
259
260 NTSTATUS STDCALL
261 NtSetIntervalProfile(IN ULONG Interval,
262 IN KPROFILE_SOURCE Source)
263 {
264 return(STATUS_NOT_IMPLEMENTED);
265 }
266
267 NTSTATUS STDCALL
268 NtStartProfile(IN HANDLE ProfileHandle)
269 {
270 NTSTATUS Status;
271 PKPROFILE Profile;
272
273 Status = ObReferenceObjectByHandle(ProfileHandle,
274 STANDARD_RIGHTS_ALL,
275 ExProfileObjectType,
276 UserMode,
277 (PVOID*)&Profile,
278 NULL);
279 if (!NT_SUCCESS(Status))
280 {
281 return(Status);
282 }
283 Profile->Started = TRUE;
284 ObDereferenceObject(Profile);
285 return(STATUS_SUCCESS);
286 }
287
288 NTSTATUS STDCALL
289 NtStopProfile(IN HANDLE ProfileHandle)
290 {
291 NTSTATUS Status;
292 PKPROFILE Profile;
293
294 Status = ObReferenceObjectByHandle(ProfileHandle,
295 STANDARD_RIGHTS_ALL,
296 ExProfileObjectType,
297 UserMode,
298 (PVOID*)&Profile,
299 NULL);
300 if (!NT_SUCCESS(Status))
301 {
302 return(Status);
303 }
304 Profile->Started = FALSE;
305 ObDereferenceObject(Profile);
306 return(STATUS_SUCCESS);
307 }
308
309