7f2674454a915f52c81217b5df3a451279e04197
[reactos.git] / reactos / ntoskrnl / include / internal / ob_x.h
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/include/internal/ob_x.h
5 * PURPOSE: Intenral Inlined Functions for the Object Manager
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 #include "ex.h"
10
11 #define OBP_LOCK_STATE_PRE_ACQUISITION_EXCLUSIVE 0xAAAA1234
12 #define OBP_LOCK_STATE_PRE_ACQUISITION_SHARED 0xBBBB1234
13 #define OBP_LOCK_STATE_POST_ACQUISITION_EXCLUSIVE 0xCCCC1234
14 #define OBP_LOCK_STATE_POST_ACQUISITION_SHARED 0xDDDD1234
15 #define OBP_LOCK_STATE_RELEASED 0xEEEE1234
16 #define OBP_LOCK_STATE_INITIALIZED 0xFFFF1234
17
18 #define OBP_NAME_LOOKASIDE_MAX_SIZE 248
19
20 FORCEINLINE
21 ULONG
22 ObpValidateAttributes(IN ULONG Attributes,
23 IN KPROCESSOR_MODE PreviousMode)
24 {
25 if (PreviousMode == KernelMode)
26 {
27 /* For kernel, allow any valid attributes */
28 return Attributes & OBJ_VALID_KERNEL_ATTRIBUTES;
29 }
30 else
31 {
32 /* For user, mask out kernel-only attributes */
33 return (Attributes & OBJ_VALID_ATTRIBUTES) &
34 ~(OBJ_KERNEL_HANDLE);
35 }
36 }
37
38 FORCEINLINE
39 ULONG
40 ObpSelectObjectLockSlot(IN POBJECT_HEADER ObjectHeader)
41 {
42 /* We have 4 locks total, this will return a 0-index slot */
43 return (((ULONG_PTR)ObjectHeader) >> 8) & 3;
44 }
45
46 FORCEINLINE
47 VOID
48 ObpAcquireObjectLock(IN POBJECT_HEADER ObjectHeader)
49 {
50 ULONG Slot;
51 POBJECT_TYPE ObjectType = ObjectHeader->Type;
52
53 /* Sanity check */
54 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
55
56 /* Pick a slot */
57 Slot = ObpSelectObjectLockSlot(ObjectHeader);
58
59 /* Enter a critical region and acquire the resource */
60 KeEnterCriticalRegion();
61 ExAcquireResourceExclusiveLite(&ObjectType->ObjectLocks[Slot], TRUE);
62 }
63
64 FORCEINLINE
65 VOID
66 ObpAcquireObjectLockShared(IN POBJECT_HEADER ObjectHeader)
67 {
68 ULONG Slot;
69 POBJECT_TYPE ObjectType = ObjectHeader->Type;
70
71 /* Sanity check */
72 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
73
74 /* Pick a slot */
75 Slot = ObpSelectObjectLockSlot(ObjectHeader);
76
77 /* Enter a critical region and acquire the resource */
78 KeEnterCriticalRegion();
79 ExAcquireResourceSharedLite(&ObjectType->ObjectLocks[Slot], TRUE);
80 }
81
82 FORCEINLINE
83 VOID
84 ObpReleaseObjectLock(IN POBJECT_HEADER ObjectHeader)
85 {
86 ULONG Slot;
87 POBJECT_TYPE ObjectType = ObjectHeader->Type;
88
89 /* Pick a slot */
90 Slot = ObpSelectObjectLockSlot(ObjectHeader);
91
92 /* Release the resource and leave a critical region */
93 ExReleaseResourceLite(&ObjectType->ObjectLocks[Slot]);
94 KeLeaveCriticalRegion();
95
96 /* Sanity check */
97 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
98 }
99
100 FORCEINLINE
101 POBJECT_HEADER_NAME_INFO
102 ObpReferenceNameInfo(IN POBJECT_HEADER ObjectHeader)
103 {
104 POBJECT_HEADER_NAME_INFO ObjectNameInfo;
105 ULONG NewValue, References;
106
107 /* Make sure we have name information at all */
108 ObjectNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
109 if (!ObjectNameInfo) return NULL;
110
111 /* Get the number of references */
112 References = ObjectNameInfo->QueryReferences;
113 for (;;)
114 {
115 /* Check if the count is 0 and fail if so */
116 if (!References) return NULL;
117
118 /* Increment the number of references */
119 NewValue = InterlockedCompareExchange((PLONG)&ObjectNameInfo->
120 QueryReferences,
121 References + 1,
122 References);
123 if (NewValue == References) break;
124
125 /* We failed, try again */
126 References = NewValue;
127 }
128
129 /* Check for magic flag */
130 if (ObjectNameInfo->QueryReferences & 0x80000000)
131 {
132 /* FIXME: Unhandled*/
133 DbgPrint("OB: Unhandled path\n");
134 ASSERT(FALSE);
135 }
136
137 /* Return the name information */
138 return ObjectNameInfo;
139 }
140
141 FORCEINLINE
142 VOID
143 ObpDereferenceNameInfo(IN POBJECT_HEADER_NAME_INFO HeaderNameInfo)
144 {
145 POBJECT_DIRECTORY Directory;
146
147 /* Bail out if there's no info at all */
148 if (!HeaderNameInfo) return;
149
150 /* Remove a query reference and check if it was the last one */
151 if (!InterlockedDecrement((PLONG)&HeaderNameInfo->QueryReferences))
152 {
153 /* Check if we have a name */
154 if (HeaderNameInfo->Name.Buffer)
155 {
156 /* We can get rid of the object name now */
157 ExFreePoolWithTag(HeaderNameInfo->Name.Buffer, OB_NAME_TAG);
158 RtlInitEmptyUnicodeString(&HeaderNameInfo->Name, NULL, 0);
159 }
160
161 /* Check if the object has a directory associated to it */
162 Directory = HeaderNameInfo->Directory;
163 if (Directory)
164 {
165 /* Delete the directory */
166 HeaderNameInfo->Directory = NULL;
167 ObDereferenceObjectDeferDelete(Directory);
168 }
169 }
170 }
171
172 FORCEINLINE
173 VOID
174 ObpAcquireDirectoryLockShared(IN POBJECT_DIRECTORY Directory,
175 IN POBP_LOOKUP_CONTEXT Context)
176 {
177 /* It's not, set lock flag */
178 Context->LockStateSignature = OBP_LOCK_STATE_PRE_ACQUISITION_SHARED;
179
180 /* Lock it */
181 KeEnterCriticalRegion();
182 ExAcquirePushLockShared(&Directory->Lock);
183
184 /* Update lock flag */
185 Context->LockStateSignature = OBP_LOCK_STATE_POST_ACQUISITION_SHARED;
186 }
187
188 FORCEINLINE
189 VOID
190 ObpAcquireDirectoryLockExclusive(IN POBJECT_DIRECTORY Directory,
191 IN POBP_LOOKUP_CONTEXT Context)
192 {
193 /* Update lock flag */
194 Context->LockStateSignature = OBP_LOCK_STATE_PRE_ACQUISITION_EXCLUSIVE;
195
196 /* Acquire an exclusive directory lock */
197 KeEnterCriticalRegion();
198 ExAcquirePushLockExclusive(&Directory->Lock);
199
200 /* Set the directory */
201 Context->Directory = Directory;
202
203 /* Update lock settings */
204 Context->LockStateSignature = OBP_LOCK_STATE_POST_ACQUISITION_EXCLUSIVE;
205 Context->DirectoryLocked = TRUE;
206 }
207
208 FORCEINLINE
209 VOID
210 ObpReleaseDirectoryLock(IN POBJECT_DIRECTORY Directory,
211 IN POBP_LOOKUP_CONTEXT Context)
212 {
213 /* Release the lock */
214 ExReleasePushLock(&Directory->Lock);
215 Context->LockStateSignature = OBP_LOCK_STATE_RELEASED;
216 KeLeaveCriticalRegion();
217 }
218
219 FORCEINLINE
220 VOID
221 ObpInitializeLookupContext(IN POBP_LOOKUP_CONTEXT Context)
222 {
223 /* Initialize a null context */
224 Context->Object = NULL;
225 Context->Directory = NULL;
226 Context->DirectoryLocked = FALSE;
227 Context->LockStateSignature = OBP_LOCK_STATE_INITIALIZED;
228 }
229
230 FORCEINLINE
231 VOID
232 ObpReleaseLookupContextObject(IN POBP_LOOKUP_CONTEXT Context)
233 {
234 POBJECT_HEADER ObjectHeader;
235 POBJECT_HEADER_NAME_INFO HeaderNameInfo;
236
237 /* Check if we had found an object */
238 if (Context->Object)
239 {
240 /* Get the object name information */
241 ObjectHeader = OBJECT_TO_OBJECT_HEADER(Context->Object);
242 HeaderNameInfo = OBJECT_HEADER_TO_NAME_INFO(ObjectHeader);
243
244 /* release the name information */
245 ObpDereferenceNameInfo(HeaderNameInfo);
246
247 /* Dereference the object */
248 ObDereferenceObject(Context->Object);
249 Context->Object = NULL;
250 }
251 }
252
253 FORCEINLINE
254 VOID
255 ObpReleaseLookupContext(IN POBP_LOOKUP_CONTEXT Context)
256 {
257 /* Check if we came back with the directory locked */
258 if (Context->DirectoryLocked)
259 {
260 /* Release the lock */
261 ObpReleaseDirectoryLock(Context->Directory, Context);
262 Context->Directory = NULL;
263 Context->DirectoryLocked = FALSE;
264 }
265
266 /* Clear the context */
267 ObpReleaseLookupContextObject(Context);
268 }
269
270 FORCEINLINE
271 VOID
272 ObpEnterObjectTypeMutex(IN POBJECT_TYPE ObjectType)
273 {
274 /* Sanity check */
275 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
276
277 /* Enter a critical region and acquire the resource */
278 KeEnterCriticalRegion();
279 ExAcquireResourceExclusiveLite(&ObjectType->Mutex, TRUE);
280 }
281
282 FORCEINLINE
283 VOID
284 ObpLeaveObjectTypeMutex(IN POBJECT_TYPE ObjectType)
285 {
286 /* Enter a critical region and acquire the resource */
287 ExReleaseResourceLite(&ObjectType->Mutex);
288 KeLeaveCriticalRegion();
289
290 /* Sanity check */
291 ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
292 }
293
294 FORCEINLINE
295 VOID
296 ObpReleaseObjectCreateInformation(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
297 {
298 /* Check if we have a security descriptor */
299 if (ObjectCreateInfo->SecurityDescriptor)
300 {
301 /* Release it */
302 SeReleaseSecurityDescriptor(ObjectCreateInfo->SecurityDescriptor,
303 ObjectCreateInfo->ProbeMode,
304 TRUE);
305 ObjectCreateInfo->SecurityDescriptor = NULL;
306 }
307 }
308
309 FORCEINLINE
310 PVOID
311 ObpAllocateObjectCreateInfoBuffer(IN PP_NPAGED_LOOKASIDE_NUMBER Type)
312 {
313 PVOID Buffer;
314 PNPAGED_LOOKASIDE_LIST List;
315 PKPRCB Prcb = KeGetCurrentPrcb();
316
317 /* Get the P list first */
318 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].P;
319
320 /* Attempt allocation */
321 List->L.TotalAllocates++;
322 Buffer = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
323 if (!Buffer)
324 {
325 /* Let the balancer know that the P list failed */
326 List->L.AllocateMisses++;
327
328 /* Try the L List */
329 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].L;
330 List->L.TotalAllocates++;
331 Buffer = (PVOID)InterlockedPopEntrySList(&List->L.ListHead);
332 if (!Buffer)
333 {
334 /* Let the balancer know the L list failed too */
335 List->L.AllocateMisses++;
336
337 /* Allocate it */
338 Buffer = List->L.Allocate(List->L.Type, List->L.Size, List->L.Tag);
339 }
340 }
341
342 /* Return buffer */
343 return Buffer;
344 }
345
346 FORCEINLINE
347 VOID
348 ObpFreeCapturedAttributes(IN PVOID Buffer,
349 IN PP_NPAGED_LOOKASIDE_NUMBER Type)
350 {
351 PNPAGED_LOOKASIDE_LIST List;
352 PKPRCB Prcb = KeGetCurrentPrcb();
353
354 /* Use the P List */
355 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].P;
356 List->L.TotalFrees++;
357
358 /* Check if the Free was within the Depth or not */
359 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
360 {
361 /* Let the balancer know */
362 List->L.FreeMisses++;
363
364 /* Use the L List */
365 List = (PNPAGED_LOOKASIDE_LIST)Prcb->PPLookasideList[Type].L;
366 List->L.TotalFrees++;
367
368 /* Check if the Free was within the Depth or not */
369 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth)
370 {
371 /* All lists failed, use the pool */
372 List->L.FreeMisses++;
373 List->L.Free(Buffer);
374 }
375 else
376 {
377 /* The free was within the Depth */
378 InterlockedPushEntrySList(&List->L.ListHead,
379 (PSLIST_ENTRY)Buffer);
380 }
381 }
382 else
383 {
384 /* The free was within the Depth */
385 InterlockedPushEntrySList(&List->L.ListHead,
386 (PSLIST_ENTRY)Buffer);
387 }
388 }
389
390 FORCEINLINE
391 VOID
392 ObpFreeObjectCreateInformation(IN POBJECT_CREATE_INFORMATION ObjectCreateInfo)
393 {
394 /* First release the attributes, then free them from the lookaside list */
395 ObpReleaseObjectCreateInformation(ObjectCreateInfo);
396 ObpFreeCapturedAttributes(ObjectCreateInfo, LookasideCreateInfoList);
397 }
398
399 #if DBG
400 FORCEINLINE
401 VOID
402 ObpCalloutStart(IN PKIRQL CalloutIrql)
403 {
404 /* Save the callout IRQL */
405 *CalloutIrql = KeGetCurrentIrql();
406 }
407
408 FORCEINLINE
409 VOID
410 ObpCalloutEnd(IN KIRQL CalloutIrql,
411 IN PCHAR Procedure,
412 IN POBJECT_TYPE ObjectType,
413 IN PVOID Object)
414 {
415 /* Detect IRQL change */
416 if (CalloutIrql != KeGetCurrentIrql())
417 {
418 /* Print error */
419 DbgPrint("OB: ObjectType: %wZ Procedure: %s Object: %p\n",
420 &ObjectType->Name, Procedure, Object);
421 DbgPrint(" Returned at %x IRQL, but was called at %x IRQL\n",
422 KeGetCurrentIrql(), CalloutIrql);
423 DbgBreakPoint();
424 }
425 }
426 #else
427 FORCEINLINE
428 VOID
429 ObpCalloutStart(IN PKIRQL CalloutIrql)
430 {
431 /* No-op */
432 UNREFERENCED_PARAMETER(CalloutIrql);
433 }
434
435 FORCEINLINE
436 VOID
437 ObpCalloutEnd(IN KIRQL CalloutIrql,
438 IN PCHAR Procedure,
439 IN POBJECT_TYPE ObjectType,
440 IN PVOID Object)
441 {
442 UNREFERENCED_PARAMETER(CalloutIrql);
443 }
444 #endif