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 *********************************************************/
46 /* Loop all the callbacks */
47 for (i
= 0; i
< CMP_MAX_CALLBACKS
; i
++)
49 /* Initialize this one */
50 ExInitializeCallBack(&CmpCallBackVector
[i
]);
53 /* ROS: Initialize old-style callbacks for now */
54 InitializeListHead(&CmiCallbackHead
);
55 ExInitializeFastMutex(&CmiCallbackLock
);
59 CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1
,
62 PLIST_ENTRY CurrentEntry
;
63 NTSTATUS Status
= STATUS_SUCCESS
;
64 PREGISTRY_CALLBACK CurrentCallback
;
67 ExAcquireFastMutex(&CmiCallbackLock
);
69 for (CurrentEntry
= CmiCallbackHead
.Flink
;
70 CurrentEntry
!= &CmiCallbackHead
;
71 CurrentEntry
= CurrentEntry
->Flink
)
73 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
74 if (!CurrentCallback
->PendingDelete
&&
75 ExAcquireRundownProtection(&CurrentCallback
->RundownRef
))
77 /* don't hold locks during the callbacks! */
78 ExReleaseFastMutex(&CmiCallbackLock
);
80 Status
= CurrentCallback
->Function(CurrentCallback
->Context
,
84 ExAcquireFastMutex(&CmiCallbackLock
);
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
89 ExReleaseRundownProtection(&CurrentCallback
->RundownRef
);
90 if(!NT_SUCCESS(Status
))
92 /* one callback returned failure, don't call any more callbacks */
98 ExReleaseFastMutex(&CmiCallbackLock
);
103 /* PUBLIC FUNCTIONS **********************************************************/
110 CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function
,
112 IN OUT PLARGE_INTEGER Cookie
)
114 PREGISTRY_CALLBACK Callback
;
116 ASSERT(Function
&& Cookie
);
118 Callback
= ExAllocatePoolWithTag(PagedPool
,
119 sizeof(REGISTRY_CALLBACK
),
121 if (Callback
== NULL
)
123 return STATUS_INSUFFICIENT_RESOURCES
;
126 /* initialize the callback */
127 ExInitializeRundownProtection(&Callback
->RundownRef
);
128 Callback
->Function
= Function
;
129 Callback
->Context
= Context
;
130 Callback
->PendingDelete
= FALSE
;
132 /* add it to the callback list and receive a cookie for the callback */
133 ExAcquireFastMutex(&CmiCallbackLock
);
135 /* FIXME - to receive a unique cookie we'll just return the pointer to the
137 Callback
->Cookie
.QuadPart
= (ULONG_PTR
)Callback
;
138 InsertTailList(&CmiCallbackHead
, &Callback
->ListEntry
);
140 ExReleaseFastMutex(&CmiCallbackLock
);
142 *Cookie
= Callback
->Cookie
;
143 return STATUS_SUCCESS
;
151 CmUnRegisterCallback(IN LARGE_INTEGER Cookie
)
153 PLIST_ENTRY CurrentEntry
;
154 PREGISTRY_CALLBACK CurrentCallback
;
157 ExAcquireFastMutex(&CmiCallbackLock
);
159 for (CurrentEntry
= CmiCallbackHead
.Flink
;
160 CurrentEntry
!= &CmiCallbackHead
;
161 CurrentEntry
= CurrentEntry
->Flink
)
163 CurrentCallback
= CONTAINING_RECORD(CurrentEntry
, REGISTRY_CALLBACK
, ListEntry
);
164 if (CurrentCallback
->Cookie
.QuadPart
== Cookie
.QuadPart
)
166 if (!CurrentCallback
->PendingDelete
)
168 /* found the callback, don't unlink it from the list yet so we don't screw
170 CurrentCallback
->PendingDelete
= TRUE
;
171 ExReleaseFastMutex(&CmiCallbackLock
);
173 /* if the callback is currently executing, wait until it finished */
174 ExWaitForRundownProtectionRelease(&CurrentCallback
->RundownRef
);
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
);
182 /* free the callback */
183 ExFreePool(CurrentCallback
);
184 return STATUS_SUCCESS
;
188 /* pending delete, pretend like it already is deleted */
189 ExReleaseFastMutex(&CmiCallbackLock
);
190 return STATUS_UNSUCCESSFUL
;
195 ExReleaseFastMutex(&CmiCallbackLock
);
197 return STATUS_UNSUCCESSFUL
;