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