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