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 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 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 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 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 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 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 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 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 212 CmpReleaseKcbLockByKey(ULONG ConvKey) 213 { 214 CmpReleaseKcbLockByIndex(GET_HASH_INDEX(ConvKey)); 215 } 216 217 // 218 // Converts a KCB lock 219 // 220 FORCEINLINE 221 VOID 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