xref: /reactos/ntoskrnl/include/internal/cm_x.h (revision da64119f)
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