reactos/ntoskrnl/config/cmhook.c

199 lines
5.8 KiB
C
Raw Normal View History

/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/config/cmhook.c
* PURPOSE: Configuration Manager - Registry Notifications/Callbacks
* PROGRAMMERS: Thomas Weidenmueller (w3seek@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "ntoskrnl.h"
#define NDEBUG
#include "debug.h"
/* GLOBALS *******************************************************************/
ULONG CmpCallBackCount = 0;
EX_CALLBACK CmpCallBackVector[100];
LIST_ENTRY CmiCallbackHead;
FAST_MUTEX CmiCallbackLock;
typedef struct _REGISTRY_CALLBACK
{
LIST_ENTRY ListEntry;
EX_RUNDOWN_REF RundownRef;
PEX_CALLBACK_FUNCTION Function;
PVOID Context;
LARGE_INTEGER Cookie;
BOOLEAN PendingDelete;
} REGISTRY_CALLBACK, *PREGISTRY_CALLBACK;
/* PRIVATE FUNCTIONS *********************************************************/
CODE_SEG("INIT")
VOID
NTAPI
CmpInitCallback(VOID)
{
ULONG i;
PAGED_CODE();
/* Reset counter */
CmpCallBackCount = 0;
/* Loop all the callbacks */
for (i = 0; i < CMP_MAX_CALLBACKS; i++)
{
/* Initialize this one */
ExInitializeCallBack(&CmpCallBackVector[i]);
}
/* ROS: Initialize old-style callbacks for now */
InitializeListHead(&CmiCallbackHead);
ExInitializeFastMutex(&CmiCallbackLock);
}
NTSTATUS
CmiCallRegisteredCallbacks(IN REG_NOTIFY_CLASS Argument1,
IN PVOID Argument2)
{
PLIST_ENTRY CurrentEntry;
NTSTATUS Status = STATUS_SUCCESS;
PREGISTRY_CALLBACK CurrentCallback;
PAGED_CODE();
ExAcquireFastMutex(&CmiCallbackLock);
for (CurrentEntry = CmiCallbackHead.Flink;
CurrentEntry != &CmiCallbackHead;
CurrentEntry = CurrentEntry->Flink)
{
CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
if (!CurrentCallback->PendingDelete &&
ExAcquireRundownProtection(&CurrentCallback->RundownRef))
{
/* don't hold locks during the callbacks! */
ExReleaseFastMutex(&CmiCallbackLock);
Status = CurrentCallback->Function(CurrentCallback->Context,
(PVOID)Argument1,
Argument2);
ExAcquireFastMutex(&CmiCallbackLock);
/* don't release the rundown protection before holding the callback lock
so the pointer to the next callback isn't cleared in case this callback
get's deleted */
ExReleaseRundownProtection(&CurrentCallback->RundownRef);
if(!NT_SUCCESS(Status))
{
/* one callback returned failure, don't call any more callbacks */
break;
}
}
}
ExReleaseFastMutex(&CmiCallbackLock);
return Status;
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
CmRegisterCallback(IN PEX_CALLBACK_FUNCTION Function,
IN PVOID Context,
IN OUT PLARGE_INTEGER Cookie)
{
PREGISTRY_CALLBACK Callback;
PAGED_CODE();
ASSERT(Function && Cookie);
Callback = ExAllocatePoolWithTag(PagedPool,
sizeof(REGISTRY_CALLBACK),
'bcMC');
if (Callback == NULL)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* initialize the callback */
ExInitializeRundownProtection(&Callback->RundownRef);
Callback->Function = Function;
Callback->Context = Context;
Callback->PendingDelete = FALSE;
/* add it to the callback list and receive a cookie for the callback */
ExAcquireFastMutex(&CmiCallbackLock);
/* FIXME - to receive a unique cookie we'll just return the pointer to the
callback object */
Callback->Cookie.QuadPart = (ULONG_PTR)Callback;
InsertTailList(&CmiCallbackHead, &Callback->ListEntry);
ExReleaseFastMutex(&CmiCallbackLock);
*Cookie = Callback->Cookie;
return STATUS_SUCCESS;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
CmUnRegisterCallback(IN LARGE_INTEGER Cookie)
{
PLIST_ENTRY CurrentEntry;
PREGISTRY_CALLBACK CurrentCallback;
PAGED_CODE();
ExAcquireFastMutex(&CmiCallbackLock);
for (CurrentEntry = CmiCallbackHead.Flink;
CurrentEntry != &CmiCallbackHead;
CurrentEntry = CurrentEntry->Flink)
{
CurrentCallback = CONTAINING_RECORD(CurrentEntry, REGISTRY_CALLBACK, ListEntry);
if (CurrentCallback->Cookie.QuadPart == Cookie.QuadPart)
{
if (!CurrentCallback->PendingDelete)
{
/* found the callback, don't unlink it from the list yet so we don't screw
the calling loop */
CurrentCallback->PendingDelete = TRUE;
ExReleaseFastMutex(&CmiCallbackLock);
/* if the callback is currently executing, wait until it finished */
ExWaitForRundownProtectionRelease(&CurrentCallback->RundownRef);
/* time to unlink it. It's now safe because every attempt to acquire a
runtime protection on this callback will fail */
ExAcquireFastMutex(&CmiCallbackLock);
RemoveEntryList(&CurrentCallback->ListEntry);
ExReleaseFastMutex(&CmiCallbackLock);
/* free the callback */
ExFreePoolWithTag(CurrentCallback, 'bcMC');
return STATUS_SUCCESS;
}
else
{
/* pending delete, pretend like it already is deleted */
ExReleaseFastMutex(&CmiCallbackLock);
return STATUS_UNSUCCESSFUL;
}
}
}
ExReleaseFastMutex(&CmiCallbackLock);
return STATUS_UNSUCCESSFUL;
}