1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/config/cmhook.c 5 * PURPOSE: Configuration Manager - Registry Notifications/Callbacks 6 * PROGRAMMERS: Thomas Weidenmueller (w3seek@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "ntoskrnl.h" 12 #define NDEBUG 13 #include "debug.h" 14 15 /* GLOBALS *******************************************************************/ 16 17 ULONG CmpCallBackCount = 0; 18 EX_CALLBACK CmpCallBackVector[100]; 19 20 LIST_ENTRY CmiCallbackHead; 21 FAST_MUTEX CmiCallbackLock; 22 23 typedef struct _REGISTRY_CALLBACK 24 { 25 LIST_ENTRY ListEntry; 26 EX_RUNDOWN_REF RundownRef; 27 PEX_CALLBACK_FUNCTION Function; 28 PVOID Context; 29 LARGE_INTEGER Cookie; 30 BOOLEAN PendingDelete; 31 } REGISTRY_CALLBACK, *PREGISTRY_CALLBACK; 32 33 /* PRIVATE FUNCTIONS *********************************************************/ 34 35 INIT_FUNCTION 36 VOID 37 NTAPI 38 CmpInitCallback(VOID) 39 { 40 ULONG i; 41 PAGED_CODE(); 42 43 /* Reset counter */ 44 CmpCallBackCount = 0; 45 46 /* Loop all the callbacks */ 47 for (i = 0; i < CMP_MAX_CALLBACKS; i++) 48 { 49 /* Initialize this one */ 50 ExInitializeCallBack(&CmpCallBackVector[i]); 51 } 52 53 /* ROS: Initialize old-style callbacks for now */ 54 InitializeListHead(&CmiCallbackHead); 55 ExInitializeFastMutex(&CmiCallbackLock); 56 } 57 58 NTSTATUS 59 CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1, 60 IN PVOID Argument2) 61 { 62 PLIST_ENTRY CurrentEntry; 63 NTSTATUS Status = STATUS_SUCCESS; 64 PREGISTRY_CALLBACK CurrentCallback; 65 PAGED_CODE(); 66 67 ExAcquireFastMutex(&CmiCallbackLock); 68 69 for (CurrentEntry = CmiCallbackHead.Flink; 70 CurrentEntry != &CmiCallbackHead; 71 CurrentEntry = CurrentEntry->Flink) 72 { 73 CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); 74 if (!CurrentCallback->PendingDelete && 75 ExAcquireRundownProtection(&CurrentCallback->RundownRef)) 76 { 77 /* don't hold locks during the callbacks! */ 78 ExReleaseFastMutex(&CmiCallbackLock); 79 80 Status = CurrentCallback->Function(CurrentCallback->Context, 81 (PVOID)Argument1, 82 Argument2); 83 84 ExAcquireFastMutex(&CmiCallbackLock); 85 86 /* don't release the rundown protection before holding the callback lock 87 so the pointer to the next callback isn't cleared in case this callback 88 get's deleted */ 89 ExReleaseRundownProtection(&CurrentCallback->RundownRef); 90 if(!NT_SUCCESS(Status)) 91 { 92 /* one callback returned failure, don't call any more callbacks */ 93 break; 94 } 95 } 96 } 97 98 ExReleaseFastMutex(&CmiCallbackLock); 99 100 return Status; 101 } 102 103 /* PUBLIC FUNCTIONS **********************************************************/ 104 105 /* 106 * @implemented 107 */ 108 NTSTATUS 109 NTAPI 110 CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function, 111 IN PVOID Context, 112 IN OUT PLARGE_INTEGER Cookie) 113 { 114 PREGISTRY_CALLBACK Callback; 115 PAGED_CODE(); 116 ASSERT(Function && Cookie); 117 118 Callback = ExAllocatePoolWithTag(PagedPool, 119 sizeof(REGISTRY_CALLBACK), 120 'bcMC'); 121 if (Callback == NULL) 122 { 123 return STATUS_INSUFFICIENT_RESOURCES; 124 } 125 126 /* initialize the callback */ 127 ExInitializeRundownProtection(&Callback->RundownRef); 128 Callback->Function = Function; 129 Callback->Context = Context; 130 Callback->PendingDelete = FALSE; 131 132 /* add it to the callback list and receive a cookie for the callback */ 133 ExAcquireFastMutex(&CmiCallbackLock); 134 135 /* FIXME - to receive a unique cookie we'll just return the pointer to the 136 callback object */ 137 Callback->Cookie.QuadPart = (ULONG_PTR)Callback; 138 InsertTailList(&CmiCallbackHead, &Callback->ListEntry); 139 140 ExReleaseFastMutex(&CmiCallbackLock); 141 142 *Cookie = Callback->Cookie; 143 return STATUS_SUCCESS; 144 } 145 146 /* 147 * @implemented 148 */ 149 NTSTATUS 150 NTAPI 151 CmUnRegisterCallback(IN LARGE_INTEGER Cookie) 152 { 153 PLIST_ENTRY CurrentEntry; 154 PREGISTRY_CALLBACK CurrentCallback; 155 PAGED_CODE(); 156 157 ExAcquireFastMutex(&CmiCallbackLock); 158 159 for (CurrentEntry = CmiCallbackHead.Flink; 160 CurrentEntry != &CmiCallbackHead; 161 CurrentEntry = CurrentEntry->Flink) 162 { 163 CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); 164 if (CurrentCallback->Cookie.QuadPart == Cookie.QuadPart) 165 { 166 if (!CurrentCallback->PendingDelete) 167 { 168 /* found the callback, don't unlink it from the list yet so we don't screw 169 the calling loop */ 170 CurrentCallback->PendingDelete = TRUE; 171 ExReleaseFastMutex(&CmiCallbackLock); 172 173 /* if the callback is currently executing, wait until it finished */ 174 ExWaitForRundownProtectionRelease(&CurrentCallback->RundownRef); 175 176 /* time to unlink it. It's now safe because every attempt to acquire a 177 runtime protection on this callback will fail */ 178 ExAcquireFastMutex(&CmiCallbackLock); 179 RemoveEntryList(&CurrentCallback->ListEntry); 180 ExReleaseFastMutex(&CmiCallbackLock); 181 182 /* free the callback */ 183 ExFreePoolWithTag(CurrentCallback, 'bcMC'); 184 return STATUS_SUCCESS; 185 } 186 else 187 { 188 /* pending delete, pretend like it already is deleted */ 189 ExReleaseFastMutex(&CmiCallbackLock); 190 return STATUS_UNSUCCESSFUL; 191 } 192 } 193 } 194 195 ExReleaseFastMutex(&CmiCallbackLock); 196 197 return STATUS_UNSUCCESSFUL; 198 } 199