1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/include/internal/cm_x.h
5 * PURPOSE: Inlined Functions for the Configuration Manager
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 #if DBG
10 FORCEINLINE
11 VOID
CmpCaptureLockBackTraceByIndex(_In_ ULONG Index)12 CmpCaptureLockBackTraceByIndex(_In_ ULONG Index)
13 {
14 /* Capture the backtrace */
15 RtlCaptureStackBackTrace(1,
16 _countof(CmpCacheTable[Index].LockBackTrace),
17 CmpCacheTable[Index].LockBackTrace,
18 NULL);
19 }
20 #endif
21
22 //
23 // Returns the hashkey corresponding to a convkey
24 //
25 #define GET_HASH_KEY(ConvKey) \
26 ((CMP_HASH_IRRATIONAL * (ConvKey)) % CMP_HASH_PRIME)
27
28 //
29 // Computes the hashkey of a character
30 //
31 #define COMPUTE_HASH_CHAR(ConvKey, Char) \
32 (37 * ConvKey + RtlUpcaseUnicodeChar(Char))
33
34 //
35 // Returns the index into the hash table, or the entry itself
36 //
37 #define GET_HASH_INDEX(ConvKey) \
38 (GET_HASH_KEY(ConvKey) % CmpHashTableSize)
39 #define GET_HASH_ENTRY(Table, ConvKey) \
40 (&Table[GET_HASH_INDEX(ConvKey)])
41 #define ASSERT_VALID_HASH(h) \
42 ASSERT_KCB_VALID(CONTAINING_RECORD((h), CM_KEY_CONTROL_BLOCK, KeyHash))
43
44 //
45 // Returns whether or not the cell is cached
46 //
47 #define CMP_IS_CELL_CACHED(c) \
48 (((c) & HCELL_CACHED) && ((c) != HCELL_NIL))
49
50 //
51 // Return data from a cached cell
52 //
53 #define CMP_GET_CACHED_CELL(c) \
54 (ULONG_PTR)((c) & ~HCELL_CACHED)
55 #define CMP_GET_CACHED_DATA(c) \
56 (&(((PCM_CACHED_VALUE_INDEX)(CMP_GET_CACHED_CELL(c)))->Data.CellData))
57 #define CMP_GET_CACHED_INDEX(c) \
58 (&(((PCM_CACHED_ENTRY)(CMP_GET_CACHED_CELL(c)))->CellIndex))
59 #define CMP_GET_CACHED_VALUE(c) \
60 (&(((PCM_CACHED_VALUE)(CMP_GET_CACHED_CELL(c)))->KeyValue))
61
62 //
63 // Makes sure that the registry is locked
64 //
65 #define CMP_ASSERT_REGISTRY_LOCK() \
66 ASSERT((CmpSpecialBootCondition == TRUE) || \
67 (CmpTestRegistryLock() == TRUE))
68
69 //
70 // Makes sure that the registry is locked or loading
71 //
72 #define CMP_ASSERT_REGISTRY_LOCK_OR_LOADING(h) \
73 ASSERT((CmpSpecialBootCondition == TRUE) || \
74 (((PCMHIVE)h)->HiveIsLoading == TRUE) || \
75 (CmpTestRegistryLock() == TRUE))
76
77 //
78 // Makes sure that the registry is exclusively locked
79 //
80 #define CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK() \
81 ASSERT((CmpSpecialBootCondition == TRUE) || \
82 (CmpTestRegistryLockExclusive() == TRUE))
83
84 //
85 // Makes sure that the registry is exclusively locked or loading
86 //
87 #define CMP_ASSERT_EXCLUSIVE_REGISTRY_LOCK_OR_LOADING(h) \
88 ASSERT((CmpSpecialBootCondition == TRUE) || \
89 (((PCMHIVE)h)->HiveIsLoading == TRUE) || \
90 (CmpTestRegistryLockExclusive() == TRUE))
91
92 //
93 // Makes sure this is a valid KCB
94 //
95 #define ASSERT_KCB_VALID(k) \
96 ASSERT((k)->Signature == CM_KCB_SIGNATURE)
97
98 //
99 // Checks if a KCB is exclusively locked
100 //
101 #define CmpIsKcbLockedExclusive(k) \
102 (GET_HASH_ENTRY(CmpCacheTable, \
103 (k)->ConvKey)->Owner == KeGetCurrentThread())
104
105 //
106 // Shared acquires a KCB by index
107 //
108 #define CmpAcquireKcbLockSharedByIndex(i) \
109 { \
110 ExAcquirePushLockShared(&CmpCacheTable[(i)].Lock); \
111 }
112
113 //
114 // Exclusively acquires a KCB by index
115 //
116 FORCEINLINE
117 VOID
CmpAcquireKcbLockExclusiveByIndex(ULONG Index)118 CmpAcquireKcbLockExclusiveByIndex(ULONG Index)
119 {
120 ASSERT(CmpCacheTable[Index].Owner != KeGetCurrentThread());
121 ExAcquirePushLockExclusive(&CmpCacheTable[Index].Lock);
122 CmpCacheTable[Index].Owner = KeGetCurrentThread();
123 #if DBG
124 CmpCaptureLockBackTraceByIndex(Index);
125 #endif
126 }
127
128 //
129 // Exclusively acquires a KCB
130 //
131 FORCEINLINE
132 VOID
CmpAcquireKcbLockExclusive(PCM_KEY_CONTROL_BLOCK Kcb)133 CmpAcquireKcbLockExclusive(PCM_KEY_CONTROL_BLOCK Kcb)
134 {
135 CmpAcquireKcbLockExclusiveByIndex(GET_HASH_INDEX(Kcb->ConvKey));
136 }
137
138 //
139 // Exclusively acquires a KCB by key
140 //
141 FORCEINLINE
142 VOID
CmpAcquireKcbLockExclusiveByKey(IN ULONG ConvKey)143 CmpAcquireKcbLockExclusiveByKey(IN ULONG ConvKey)
144 {
145 CmpAcquireKcbLockExclusiveByIndex(GET_HASH_INDEX(ConvKey));
146 }
147
148 //
149 // Shared acquires a KCB by key
150 //
151 FORCEINLINE
152 VOID
CmpAcquireKcbLockSharedByKey(_In_ ULONG ConvKey)153 CmpAcquireKcbLockSharedByKey(
154 _In_ ULONG ConvKey)
155 {
156 CmpAcquireKcbLockSharedByIndex(GET_HASH_INDEX(ConvKey));
157 }
158
159 //
160 // Shared acquires a KCB
161 //
162 #define CmpAcquireKcbLockShared(k) \
163 { \
164 ExAcquirePushLockShared(&GET_HASH_ENTRY(CmpCacheTable, \
165 (k)->ConvKey)->Lock); \
166 }
167
168 //
169 // Tries to convert a KCB lock
170 //
171 FORCEINLINE
172 BOOLEAN
CmpTryToConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k)173 CmpTryToConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k)
174 {
175 ASSERT(CmpIsKcbLockedExclusive(k) == FALSE);
176 if (ExConvertPushLockSharedToExclusive(
177 &GET_HASH_ENTRY(CmpCacheTable, k->ConvKey)->Lock))
178 {
179 GET_HASH_ENTRY(CmpCacheTable,
180 k->ConvKey)->Owner = KeGetCurrentThread();
181 return TRUE;
182 }
183 return FALSE;
184 }
185
186 //
187 // Releases an exlusively or shared acquired KCB by index
188 //
189 FORCEINLINE
190 VOID
CmpReleaseKcbLockByIndex(ULONG Index)191 CmpReleaseKcbLockByIndex(ULONG Index)
192 {
193 CmpCacheTable[Index].Owner = NULL;
194 ExReleasePushLock(&CmpCacheTable[Index].Lock);
195 }
196
197 //
198 // Releases an exlusively or shared acquired KCB
199 //
200 FORCEINLINE
201 VOID
CmpReleaseKcbLock(PCM_KEY_CONTROL_BLOCK Kcb)202 CmpReleaseKcbLock(PCM_KEY_CONTROL_BLOCK Kcb)
203 {
204 CmpReleaseKcbLockByIndex(GET_HASH_INDEX(Kcb->ConvKey));
205 }
206
207 //
208 // Releases an exlusively or shared acquired KCB by key
209 //
210 FORCEINLINE
211 VOID
CmpReleaseKcbLockByKey(ULONG ConvKey)212 CmpReleaseKcbLockByKey(ULONG ConvKey)
213 {
214 CmpReleaseKcbLockByIndex(GET_HASH_INDEX(ConvKey));
215 }
216
217 //
218 // Converts a KCB lock
219 //
220 FORCEINLINE
221 VOID
CmpConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k)222 CmpConvertKcbSharedToExclusive(IN PCM_KEY_CONTROL_BLOCK k)
223 {
224 ASSERT(CmpIsKcbLockedExclusive(k) == FALSE);
225 CmpReleaseKcbLock(k);
226 CmpAcquireKcbLockExclusive(k);
227 }
228
229 //
230 // Exclusively acquires an NCB
231 //
232 #define CmpAcquireNcbLockExclusive(n) \
233 { \
234 ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \
235 (n)->ConvKey)->Lock); \
236 }
237
238 //
239 // Exclusively acquires an NCB by key
240 //
241 #define CmpAcquireNcbLockExclusiveByKey(k) \
242 { \
243 ExAcquirePushLockExclusive(&GET_HASH_ENTRY(CmpNameCacheTable, \
244 (k))->Lock); \
245 }
246
247 //
248 // Releases an exlusively or shared acquired NCB
249 //
250 #define CmpReleaseNcbLock(k) \
251 { \
252 ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \
253 (k)->ConvKey)->Lock); \
254 }
255
256 //
257 // Releases an exlusively or shared acquired NCB by key
258 //
259 #define CmpReleaseNcbLockByKey(k) \
260 { \
261 ExReleasePushLock(&GET_HASH_ENTRY(CmpNameCacheTable, \
262 (k))->Lock); \
263 }
264
265 //
266 // Asserts that either the registry or the KCB is locked
267 //
268 #define CMP_ASSERT_HASH_ENTRY_LOCK(k) \
269 { \
270 ASSERT(((GET_HASH_ENTRY(CmpCacheTable, k)->Owner == \
271 KeGetCurrentThread())) || \
272 (CmpTestRegistryLockExclusive() == TRUE)); \
273 }
274
275 //
276 // Asserts that either the registry or the KCB is locked
277 //
278 #define CMP_ASSERT_KCB_LOCK(k) \
279 { \
280 ASSERT((CmpIsKcbLockedExclusive(k) == TRUE) || \
281 (CmpTestRegistryLockExclusive() == TRUE)); \
282 }
283
284 //
285 // Gets the page attached to the KCB
286 //
287 #define CmpGetAllocPageFromKcb(k) \
288 (PCM_ALLOC_PAGE)(((ULONG_PTR)(k)) & ~(PAGE_SIZE - 1))
289
290 //
291 // Gets the page attached to the delayed allocation
292 //
293 #define CmpGetAllocPageFromDelayAlloc(a) \
294 (PCM_ALLOC_PAGE)(((ULONG_PTR)(a)) & ~(PAGE_SIZE - 1))
295
296 //
297 // Makes sure that the registry is locked for flushes
298 //
299 #define CMP_ASSERT_FLUSH_LOCK(h) \
300 ASSERT((CmpSpecialBootCondition == TRUE) || \
301 (((PCMHIVE)h)->HiveIsLoading == TRUE) || \
302 (CmpTestHiveFlusherLockShared((PCMHIVE)h) == TRUE) || \
303 (CmpTestHiveFlusherLockExclusive((PCMHIVE)h) == TRUE) || \
304 (CmpTestRegistryLockExclusive() == TRUE));
305