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
)
122 HANDLE SafeProfileHandle
;
128 * Reference the associated process
132 Status
= ObReferenceObjectByHandle(Process
,
133 PROCESS_QUERY_INFORMATION
,
138 if (!NT_SUCCESS(Status
))
146 /* FIXME: Check privilege. */
150 * Check the parameters
152 if ((pProcess
== NULL
&& ImageBase
< (PVOID
)KERNEL_BASE
) ||
153 (pProcess
!= NULL
&& ImageBase
>= (PVOID
)KERNEL_BASE
))
155 return(STATUS_INVALID_PARAMETER_3
);
157 if (((ImageSize
>> BucketSize
) * 4) >= BufferSize
)
159 return(STATUS_BUFFER_TOO_SMALL
);
161 if (ProfileSource
!= ProfileTime
)
163 return(STATUS_INVALID_PARAMETER_9
);
167 return(STATUS_INVALID_PARAMETER_10
);
173 Status
= ObCreateObject(ExGetPreviousMode(),
182 if (!NT_SUCCESS(Status
))
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
);
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
;
206 * Insert the profile into the profile list data structures
208 KiInsertProfile(Profile
);
210 Status
= ObInsertObject ((PVOID
)Profile
,
216 if (!NT_SUCCESS(Status
))
218 ObDereferenceObject (Profile
);
223 * Copy the created handle back to the caller
225 Status
= MmCopyToCaller(ProfileHandle
, &SafeProfileHandle
, sizeof(HANDLE
));
226 if (!NT_SUCCESS(Status
))
228 ObDereferenceObject(Profile
);
229 ZwClose(ProfileHandle
);
233 ObDereferenceObject(Profile
);
235 return(STATUS_SUCCESS
);
239 NtQueryIntervalProfile(IN KPROFILE_SOURCE ProfileSource
,
244 if (ProfileSource
== ProfileTime
)
248 /* FIXME: What units does this use, for now nanoseconds */
250 Status
= MmCopyToCaller(Interval
, &SafeInterval
, sizeof(ULONG
));
251 if (!NT_SUCCESS(Status
))
255 return(STATUS_SUCCESS
);
257 return(STATUS_INVALID_PARAMETER_2
);
261 NtSetIntervalProfile(IN ULONG Interval
,
262 IN KPROFILE_SOURCE Source
)
264 return(STATUS_NOT_IMPLEMENTED
);
268 NtStartProfile(IN HANDLE ProfileHandle
)
273 Status
= ObReferenceObjectByHandle(ProfileHandle
,
279 if (!NT_SUCCESS(Status
))
283 Profile
->Started
= TRUE
;
284 ObDereferenceObject(Profile
);
285 return(STATUS_SUCCESS
);
289 NtStopProfile(IN HANDLE ProfileHandle
)
294 Status
= ObReferenceObjectByHandle(ProfileHandle
,
300 if (!NT_SUCCESS(Status
))
304 Profile
->Started
= FALSE
;
305 ObDereferenceObject(Profile
);
306 return(STATUS_SUCCESS
);