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 VOID 36 NTAPI 37 CmpInitCallback(VOID) 38 { 39 ULONG i; 40 PAGED_CODE(); 41 42 /* Reset counter */ 43 CmpCallBackCount = 0; 44 45 /* Loop all the callbacks */ 46 for (i = 0; i < CMP_MAX_CALLBACKS; i++) 47 { 48 /* Initialize this one */ 49 ExInitializeCallBack(&CmpCallBackVector[i]); 50 } 51 52 /* ROS: Initialize old-style callbacks for now */ 53 InitializeListHead(&CmiCallbackHead); 54 ExInitializeFastMutex(&CmiCallbackLock); 55 } 56 57 NTSTATUS 58 CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1, 59 IN PVOID Argument2) 60 { 61 PLIST_ENTRY CurrentEntry; 62 NTSTATUS Status = STATUS_SUCCESS; 63 PREGISTRY_CALLBACK CurrentCallback; 64 PAGED_CODE(); 65 66 ExAcquireFastMutex(&CmiCallbackLock); 67 68 for (CurrentEntry = CmiCallbackHead.Flink; 69 CurrentEntry != &CmiCallbackHead; 70 CurrentEntry = CurrentEntry->Flink) 71 { 72 CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); 73 if (!CurrentCallback->PendingDelete && 74 ExAcquireRundownProtection(&CurrentCallback->RundownRef)) 75 { 76 /* don't hold locks during the callbacks! */ 77 ExReleaseFastMutex(&CmiCallbackLock); 78 79 Status = CurrentCallback->Function(CurrentCallback->Context, 80 (PVOID)Argument1, 81 Argument2); 82 83 ExAcquireFastMutex(&CmiCallbackLock); 84 85 /* don't release the rundown protection before holding the callback lock 86 so the pointer to the next callback isn't cleared in case this callback 87 get's deleted */ 88 ExReleaseRundownProtection(&CurrentCallback->RundownRef); 89 if(!NT_SUCCESS(Status)) 90 { 91 /* one callback returned failure, don't call any more callbacks */ 92 break; 93 } 94 } 95 } 96 97 ExReleaseFastMutex(&CmiCallbackLock); 98 99 return Status; 100 } 101 102 /* PUBLIC FUNCTIONS **********************************************************/ 103 104 /* 105 * @implemented 106 */ 107 NTSTATUS 108 NTAPI 109 CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function, 110 IN PVOID Context, 111 IN OUT PLARGE_INTEGER Cookie) 112 { 113 PREGISTRY_CALLBACK Callback; 114 PAGED_CODE(); 115 ASSERT(Function && Cookie); 116 117 Callback = ExAllocatePoolWithTag(PagedPool, 118 sizeof(REGISTRY_CALLBACK), 119 'bcMC'); 120 if (Callback != NULL) 121 { 122 /* initialize the callback */ 123 ExInitializeRundownProtection(&Callback->RundownRef); 124 Callback->Function = Function; 125 Callback->Context = Context; 126 Callback->PendingDelete = FALSE; 127 128 /* add it to the callback list and receive a cookie for the callback */ 129 ExAcquireFastMutex(&CmiCallbackLock); 130 131 /* FIXME - to receive a unique cookie we'll just return the pointer to the 132 callback object */ 133 Callback->Cookie.QuadPart = (ULONG_PTR)Callback; 134 InsertTailList(&CmiCallbackHead, &Callback->ListEntry); 135 136 ExReleaseFastMutex(&CmiCallbackLock); 137 138 *Cookie = Callback->Cookie; 139 return STATUS_SUCCESS; 140 } 141 142 return STATUS_INSUFFICIENT_RESOURCES; 143 } 144 145 /* 146 * @implemented 147 */ 148 NTSTATUS 149 NTAPI 150 CmUnRegisterCallback(IN LARGE_INTEGER Cookie) 151 { 152 PLIST_ENTRY CurrentEntry; 153 PREGISTRY_CALLBACK CurrentCallback; 154 PAGED_CODE(); 155 156 ExAcquireFastMutex(&CmiCallbackLock); 157 158 for (CurrentEntry = CmiCallbackHead.Flink; 159 CurrentEntry != &CmiCallbackHead; 160 CurrentEntry = CurrentEntry->Flink) 161 { 162 CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry); 163 if (CurrentCallback->Cookie.QuadPart == Cookie.QuadPart) 164 { 165 if (!CurrentCallback->PendingDelete) 166 { 167 /* found the callback, don't unlink it from the list yet so we don't screw 168 the calling loop */ 169 CurrentCallback->PendingDelete = TRUE; 170 ExReleaseFastMutex(&CmiCallbackLock); 171 172 /* if the callback is currently executing, wait until it finished */ 173 ExWaitForRundownProtectionRelease(&CurrentCallback->RundownRef); 174 175 /* time to unlink it. It's now safe because every attempt to acquire a 176 runtime protection on this callback will fail */ 177 ExAcquireFastMutex(&CmiCallbackLock); 178 RemoveEntryList(&CurrentCallback->ListEntry); 179 ExReleaseFastMutex(&CmiCallbackLock); 180 181 /* free the callback */ 182 ExFreePool(CurrentCallback); 183 return STATUS_SUCCESS; 184 } 185 else 186 { 187 /* pending delete, pretend like it already is deleted */ 188 ExReleaseFastMutex(&CmiCallbackLock); 189 return STATUS_UNSUCCESSFUL; 190 } 191 } 192 } 193 194 ExReleaseFastMutex(&CmiCallbackLock); 195 196 return STATUS_UNSUCCESSFUL; 197 } 198