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)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 ULONG CmpCallBackCount
= 0;
18 EX_CALLBACK CmpCallBackVector
[100];
20 LIST_ENTRY CmiCallbackHead
;
21 FAST_MUTEX CmiCallbackLock
;
23 typedef struct _REGISTRY_CALLBACK
26 EX_RUNDOWN_REF RundownRef
;
27 PEX_CALLBACK_FUNCTION Function
;
30 BOOLEAN PendingDelete
;
31 } REGISTRY_CALLBACK
, *PREGISTRY_CALLBACK
;
33 /* PRIVATE FUNCTIONS *********************************************************/
45 /* Loop all the callbacks */
46 for (i
= 0; i
< CMP_MAX_CALLBACKS
; i
++)
48 /* Initialize this one */
49 ExInitializeCallBack(&CmpCallBackVector
[i
]);
52 /* ROS: Initialize old-style callbacks for now */
53 InitializeListHead(&CmiCallbackHead
);
54 ExInitializeFastMutex(&CmiCallbackLock
);
58 CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1
,
61 PLIST_ENTRY CurrentEntry
;
62 NTSTATUS Status
= STATUS_SUCCESS
;
63 PREGISTRY_CALLBACK CurrentCallback
;
66 ExAcquireFastMutex(&CmiCallbackLock
);
68 for (CurrentEntry
= CmiCallbackHead
.Flink
;
69 CurrentEntry
!= &CmiCallbackHead
;
70 CurrentEntry
= CurrentEntry
->Flink
)
72 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
73 if (!CurrentCallback
->PendingDelete
&&
74 ExAcquireRundownProtection(&CurrentCallback
->RundownRef
))
76 /* don't hold locks during the callbacks! */
77 ExReleaseFastMutex(&CmiCallbackLock
);
79 Status
= CurrentCallback
->Function(CurrentCallback
->Context
,
83 ExAcquireFastMutex(&CmiCallbackLock
);
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
88 ExReleaseRundownProtection(&CurrentCallback
->RundownRef
);
89 if(!NT_SUCCESS(Status
))
91 /* one callback returned failure, don't call any more callbacks */
97 ExReleaseFastMutex(&CmiCallbackLock
);
102 /* PUBLIC FUNCTIONS **********************************************************/
109 CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function
,
111 IN OUT PLARGE_INTEGER Cookie
)
113 PREGISTRY_CALLBACK Callback
;
115 ASSERT(Function
&& Cookie
);
117 Callback
= ExAllocatePoolWithTag(PagedPool
,
118 sizeof(REGISTRY_CALLBACK
),
120 if (Callback
!= NULL
)
122 /* initialize the callback */
123 ExInitializeRundownProtection(&Callback
->RundownRef
);
124 Callback
->Function
= Function
;
125 Callback
->Context
= Context
;
126 Callback
->PendingDelete
= FALSE
;
128 /* add it to the callback list and receive a cookie for the callback */
129 ExAcquireFastMutex(&CmiCallbackLock
);
131 /* FIXME - to receive a unique cookie we'll just return the pointer to the
133 Callback
->Cookie
.QuadPart
= (ULONG_PTR
)Callback
;
134 InsertTailList(&CmiCallbackHead
, &Callback
->ListEntry
);
136 ExReleaseFastMutex(&CmiCallbackLock
);
138 *Cookie
= Callback
->Cookie
;
139 return STATUS_SUCCESS
;
142 return STATUS_INSUFFICIENT_RESOURCES
;
150 CmUnRegisterCallback(IN LARGE_INTEGER Cookie
)
152 PLIST_ENTRY CurrentEntry
;
153 PREGISTRY_CALLBACK CurrentCallback
;
156 ExAcquireFastMutex(&CmiCallbackLock
);
158 for (CurrentEntry
= CmiCallbackHead
.Flink
;
159 CurrentEntry
!= &CmiCallbackHead
;
160 CurrentEntry
= CurrentEntry
->Flink
)
162 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
163 if (CurrentCallback
->Cookie
.QuadPart
== Cookie
.QuadPart
)
165 if (!CurrentCallback
->PendingDelete
)
167 /* found the callback, don't unlink it from the list yet so we don't screw
169 CurrentCallback
->PendingDelete
= TRUE
;
170 ExReleaseFastMutex(&CmiCallbackLock
);
172 /* if the callback is currently executing, wait until it finished */
173 ExWaitForRundownProtectionRelease(&CurrentCallback
->RundownRef
);
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
);
181 /* free the callback */
182 ExFreePool(CurrentCallback
);
183 return STATUS_SUCCESS
;
187 /* pending delete, pretend like it already is deleted */
188 ExReleaseFastMutex(&CmiCallbackLock
);
189 return STATUS_UNSUCCESSFUL
;
194 ExReleaseFastMutex(&CmiCallbackLock
);
196 return STATUS_UNSUCCESSFUL
;