- Add proper function headers, including links to publically-available documentation
- One internal function is subject to further review/audit

svn path=/trunk/; revision=22672
This commit is contained in:
Aleksey Bragin 2006-06-28 13:53:30 +00:00
parent 6ef4e4d9d4
commit 981fde0f9f

View file

@ -1,9 +1,10 @@
/* /*
* COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Kernel
* PROJECT: ReactOS kernel * LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ex/callback.c * FILE: ntoskrnl/ex/callback.c
* PURPOSE: Executive callbacks * PURPOSE: Executive callbacks
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net) * PROGRAMMERS: Filip Navara
* Alex Ionescu (alex@relsoft.net)
*/ */
/* INCLUDES *****************************************************************/ /* INCLUDES *****************************************************************/
@ -63,433 +64,441 @@ KEVENT ExpCallbackEvent;
/* FUNCTIONS *****************************************************************/ /* FUNCTIONS *****************************************************************/
/* /*++
* ExpInitializeCallbacks * @name ExpInitializeCallbacks
* *
* FUNCTION:
* Creates the Callback Object as a valid Object Type in the Kernel. * Creates the Callback Object as a valid Object Type in the Kernel.
* Internal function, subject to further review
* *
* ARGUMENTS: * @return TRUE if the Callback Object Type was successfully created.
* None
* *
* RETURNS: * @remarks None
* TRUE if the Callback Object Type was successfully created. *
*/ *--*/
VOID VOID
INIT_FUNCTION INIT_FUNCTION
STDCALL NTAPI
ExpInitializeCallbacks(VOID) ExpInitializeCallbacks(VOID)
{ {
OBJECT_ATTRIBUTES ObjectAttributes; OBJECT_ATTRIBUTES ObjectAttributes;
NTSTATUS Status; NTSTATUS Status;
UNICODE_STRING DirName = RTL_CONSTANT_STRING(L"\\Callback"); UNICODE_STRING DirName = RTL_CONSTANT_STRING(L"\\Callback");
UNICODE_STRING CallbackName; UNICODE_STRING CallbackName;
UNICODE_STRING Name; UNICODE_STRING Name;
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
HANDLE DirectoryHandle; HANDLE DirectoryHandle;
ULONG i; ULONG i;
/* Initialize the Callback Object type */ /* Initialize the Callback Object type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Callback"); RtlInitUnicodeString(&Name, L"Callback");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CALLBACK_OBJECT); ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CALLBACK_OBJECT);
ObjectTypeInitializer.GenericMapping = ExpCallbackMapping; ObjectTypeInitializer.GenericMapping = ExpCallbackMapping;
ObjectTypeInitializer.PoolType = NonPagedPool; ObjectTypeInitializer.PoolType = NonPagedPool;
Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExCallbackObjectType); Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExCallbackObjectType);
/* Fail if it wasn't created successfully */ /* Fail if it wasn't created successfully */
if (!NT_SUCCESS(Status)) if (!NT_SUCCESS(Status))
{ {
return; return;
} }
/* Initialize the Object */ /* Initialize the Object */
InitializeObjectAttributes( InitializeObjectAttributes(
&ObjectAttributes, &ObjectAttributes,
&DirName, &DirName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL, NULL,
NULL NULL
); );
/* Create the Object Directory */ /* Create the Object Directory */
Status = NtCreateDirectoryObject( Status = NtCreateDirectoryObject(
&DirectoryHandle, &DirectoryHandle,
DIRECTORY_ALL_ACCESS, DIRECTORY_ALL_ACCESS,
&ObjectAttributes &ObjectAttributes
);
/* Fail if couldn't create */
if (!NT_SUCCESS(Status))
{
return;
}
/* Close Handle... */
NtClose(DirectoryHandle);
/* Initialize Event used when unregistering */
KeInitializeEvent(&ExpCallbackEvent, NotificationEvent, 0);
/* Default NT Kernel Callbacks. */
for (i=0; ExpInitializeCallback[i].CallbackObject; i++)
{
/* Create the name from the structure */
RtlInitUnicodeString(&CallbackName, ExpInitializeCallback[i].Name);
/* Initialize the Object Attributes Structure */
InitializeObjectAttributes(
&ObjectAttributes,
&CallbackName,
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
NULL,
NULL
); );
/* Fail if couldn't create */ /* Create the Callback Object */
if (!NT_SUCCESS(Status)) Status = ExCreateCallback(
{ (PCALLBACK_OBJECT*)&(ExpInitializeCallback[i].CallbackObject),
return; &ObjectAttributes,
} TRUE,
TRUE
);
/* Close Handle... */ /* Make sure Global Callbacks have been created */
NtClose(DirectoryHandle); if (!NT_SUCCESS(Status))
{
/* Initialize Event used when unregistering */ return;
KeInitializeEvent(&ExpCallbackEvent, NotificationEvent, 0); }
}
/* Default NT Kernel Callbacks. */ /* Everything successful */
for (i=0; ExpInitializeCallback[i].CallbackObject; i++)
{
/* Create the name from the structure */
RtlInitUnicodeString(&CallbackName, ExpInitializeCallback[i].Name);
/* Initialize the Object Attributes Structure */
InitializeObjectAttributes(
&ObjectAttributes,
&CallbackName,
OBJ_PERMANENT | OBJ_CASE_INSENSITIVE,
NULL,
NULL
);
/* Create the Callback Object */
Status = ExCreateCallback(
(PCALLBACK_OBJECT*)&(ExpInitializeCallback[i].CallbackObject),
&ObjectAttributes,
TRUE,
TRUE
);
/* Make sure Global Callbacks have been created */
if (!NT_SUCCESS(Status))
{
return;
}
}
/* Everything successful */
} }
/* /*++
* ExCreateCallback * @name ExCreateCallback
* @implemented
* *
* FUNCTION:
* Opens or creates a Callback Object. Creates only if Create is true. * Opens or creates a Callback Object. Creates only if Create is true.
* Allows multiple Callback Functions to be registred only if AllowMultipleCallbacks * Allows multiple Callback Functions to be registred only if
* is true. * AllowMultipleCallbacks is true.
* See: http://www.osronline.com/ddkx/kmarch/k102_967m.htm
* http://www.osronline.com/article.cfm?id=24
* *
* ARGUMENTS: * @param CallbackObject
* CallbackObject = Pointer that will receive the Callback Object. * Pointer that will receive the Callback Object.
* CallbackName = Name of Callback
* Create = Determines if the object will be created if it doesn't exit
* AllowMultipleCallbacks = Determines if more then one registered callback function
* can be attached to this Callback Object.
* *
* RETURNS: * @param CallbackName
* STATUS_SUCESS if not failed. * Name of Callback
* *
* @implemented * @param Create
*/ * Determines if the object will be created if it doesn't exit
*
* @param AllowMultipleCallbacks
* Determines if more then one registered callback function
* can be attached to this Callback Object.
*
* @return STATUS_SUCESS if not failed.
*
* @remarks Must be called at IRQL = PASSIVE_LEVEL
*
*--*/
NTSTATUS NTSTATUS
STDCALL NTAPI
ExCreateCallback( ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject,
OUT PCALLBACK_OBJECT *CallbackObject, IN POBJECT_ATTRIBUTES ObjectAttributes,
IN POBJECT_ATTRIBUTES ObjectAttributes, IN BOOLEAN Create,
IN BOOLEAN Create, IN BOOLEAN AllowMultipleCallbacks)
IN BOOLEAN AllowMultipleCallbacks
)
{ {
PCALLBACK_OBJECT Callback; PCALLBACK_OBJECT Callback;
NTSTATUS Status; NTSTATUS Status;
HANDLE Handle; HANDLE Handle;
PAGED_CODE(); PAGED_CODE();
/* Open a handle to the callback if it exists */ /* Open a handle to the callback if it exists */
if (ObjectAttributes->ObjectName) if (ObjectAttributes->ObjectName)
{ {
Status = ObOpenObjectByName(ObjectAttributes, Status = ObOpenObjectByName(ObjectAttributes,
ExCallbackObjectType, ExCallbackObjectType,
KernelMode, KernelMode,
NULL, NULL,
0, 0,
NULL, NULL,
&Handle); &Handle);
} }
else else
{ {
Status = STATUS_UNSUCCESSFUL; Status = STATUS_UNSUCCESSFUL;
} }
/* We weren't able to open it...should we create it? */ /* We weren't able to open it...should we create it? */
if(!NT_SUCCESS(Status) && Create ) if(!NT_SUCCESS(Status) && Create )
{ {
Status = ObCreateObject(KernelMode, Status = ObCreateObject(KernelMode,
ExCallbackObjectType, ExCallbackObjectType,
ObjectAttributes, ObjectAttributes,
KernelMode, KernelMode,
NULL, NULL,
sizeof(CALLBACK_OBJECT), sizeof(CALLBACK_OBJECT),
0, 0,
0, 0,
(PVOID *)&Callback ); (PVOID *)&Callback );
/* We Created it...let's initialize the structure now */ /* We Created it...let's initialize the structure now */
if(NT_SUCCESS(Status)) if(NT_SUCCESS(Status))
{ {
KeInitializeSpinLock (&Callback->Lock); /* SpinLock */ KeInitializeSpinLock(&Callback->Lock); /* SpinLock */
InitializeListHead(&Callback->RegisteredCallbacks); /* Callback Entries */ InitializeListHead(&Callback->RegisteredCallbacks); /* Callback Entries */
Callback->AllowMultipleCallbacks = AllowMultipleCallbacks; /* Multiple Callbacks */ Callback->AllowMultipleCallbacks = AllowMultipleCallbacks; /* Multiple Callbacks */
Status = ObInsertObject ( /* Create the object */ /* Create the object */
Callback, Status = ObInsertObject(Callback,
NULL, NULL,
FILE_READ_DATA, FILE_READ_DATA,
0, 0,
NULL, NULL,
&Handle ); &Handle );
} }
} }
if(NT_SUCCESS(Status))
{
/* Get a pointer to the new object from the handle we just got */ if(NT_SUCCESS(Status))
Status = ObReferenceObjectByHandle ( {
Handle, /* Get a pointer to the new object from the handle we just got */
0, Status = ObReferenceObjectByHandle(Handle,
ExCallbackObjectType, 0,
KernelMode, ExCallbackObjectType,
(PVOID)&Callback, KernelMode,
NULL (PVOID)&Callback,
); NULL);
/* Close the Handle, since we now have the pointer */ /* Close the Handle, since we now have the pointer */
ZwClose(Handle); ZwClose(Handle);
} }
/* Everything went fine, so return a pointer to the Object */ /* Everything went fine, so return a pointer to the Object */
if (NT_SUCCESS(Status)) if (NT_SUCCESS(Status))
{ {
*CallbackObject = (PCALLBACK_OBJECT)Callback; *CallbackObject = (PCALLBACK_OBJECT)Callback;
} }
return Status; return Status;
} }
/* /*++
* ExNotifyCallback * @name ExNotifyCallback
*
* FUNCTION:
* Calls a function pointer (a registered callback)
*
* ARGUMENTS:
* CallbackObject - Which callback to call
* Argument1 - Pointer/data to send to callback function
* Argument2 - Pointer/data to send to callback function
*
* RETURNS:
* Nothing
*
* @implemented * @implemented
*/ *
* Calls a function pointer (a registered callback)
* See: http://www.osronline.com/ddkx/kmarch/k102_2f5e.htm
* http://msdn.microsoft.com/library/en-us/Kernel_d/hh/Kernel_d/Synchro_e954f515-e536-4e12-8419-e7e54c4a963b.xml.asp?frame=true
* http://vmsone.com/~decuslib/vmssig/vmslt99b/nt/wdm-callback.txt
*
* @param CallbackObject
* Which callback to call
*
* @param Argument1
* Pointer/data to send to callback function
*
* @param Argument2
* Pointer/data to send to callback function
*
* @return None
*
* @remarks None
*
*--*/
VOID VOID
STDCALL NTAPI
ExNotifyCallback( ExNotifyCallback(IN PCALLBACK_OBJECT OpaqueCallbackObject,
IN PCALLBACK_OBJECT OpaqueCallbackObject, IN PVOID Argument1,
IN PVOID Argument1, IN PVOID Argument2)
IN PVOID Argument2
)
{ {
PCALLBACK_OBJECT CallbackObject = (PCALLBACK_OBJECT)OpaqueCallbackObject; PCALLBACK_OBJECT CallbackObject = (PCALLBACK_OBJECT)OpaqueCallbackObject;
PLIST_ENTRY RegisteredCallbacks; PLIST_ENTRY RegisteredCallbacks;
PCALLBACK_REGISTRATION CallbackRegistration; PCALLBACK_REGISTRATION CallbackRegistration;
KIRQL OldIrql; KIRQL OldIrql;
/* Acquire the Lock */ /* Acquire the Lock */
OldIrql = KfAcquireSpinLock(&CallbackObject->Lock); OldIrql = KfAcquireSpinLock(&CallbackObject->Lock);
/* Enumerate through all the registered functions */ /* Enumerate through all the registered functions */
for (RegisteredCallbacks = CallbackObject->RegisteredCallbacks.Flink; for (RegisteredCallbacks = CallbackObject->RegisteredCallbacks.Flink;
RegisteredCallbacks != &CallbackObject->RegisteredCallbacks; RegisteredCallbacks != &CallbackObject->RegisteredCallbacks;
RegisteredCallbacks = RegisteredCallbacks->Flink) RegisteredCallbacks = RegisteredCallbacks->Flink)
{ {
/* Get a pointer to a Callback Registration from the List Entries */
CallbackRegistration = CONTAINING_RECORD(RegisteredCallbacks,
CALLBACK_REGISTRATION,
RegisteredCallbacks);
/* Get a pointer to a Callback Registration from the List Entries */ /* Don't bother doing Callback Notification if it's pending to be deleted */
CallbackRegistration = CONTAINING_RECORD ( RegisteredCallbacks, if (!CallbackRegistration->PendingDeletion)
CALLBACK_REGISTRATION, {
RegisteredCallbacks); /* Mark the Callback in use, so it won't get deleted while we are calling it */
CallbackRegistration->InUse += 1;
/* Don't bother doing Callback Notification if it's pending to be deleted */ /* Release the Spinlock before making the call */
if (!CallbackRegistration->PendingDeletion) KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
{
/* Mark the Callback in use, so it won't get deleted while we are calling it */ /* Call the Registered Function */
CallbackRegistration->InUse += 1; CallbackRegistration->CallbackFunction(
CallbackRegistration->CallbackContext,
Argument1,
Argument2
);
/* Release the Spinlock before making the call */ /* Get SpinLock back */
KfReleaseSpinLock(&CallbackObject->Lock, OldIrql); OldIrql = KfAcquireSpinLock(&CallbackObject->Lock);
/* Call the Registered Function */ /* We are not in use anymore */
CallbackRegistration->CallbackFunction ( CallbackRegistration->InUse -= 1;
CallbackRegistration->CallbackContext,
Argument1,
Argument2
);
/* Get SpinLock back */ /* If another instance of this function isn't running and deletion is pending, signal the event */
OldIrql = KfAcquireSpinLock(&CallbackObject->Lock); if (CallbackRegistration->PendingDeletion && CallbackRegistration->InUse == 0)
{
/* We are not in use anymore */ KeSetEvent(&ExpCallbackEvent, 0, FALSE);
CallbackRegistration->InUse -= 1; }
}
/* If another instance of this function isn't running and deletion is pending, signal the event */ }
if (CallbackRegistration->PendingDeletion && CallbackRegistration->InUse == 0) /* Unsynchronize and release the Callback Object */
{ KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
KeSetEvent(&ExpCallbackEvent, 0, FALSE);
}
}
}
/* Unsynchronize and release the Callback Object */
KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
} }
/* /*++
* ExRegisterCallback * @name ExRegisterCallback
*
* FUNCTION:
* Allows a function to associate a callback pointer (Function)
* to a created Callback object
*
* ARGUMENTS:
* CallbackObject = The Object Created with ExCreateCallBack
* CallBackFunction = Pointer to the function to be called back
* CallBackContext = Block of memory that can contain user-data
* which will be passed on to the callback
*
* RETURNS:
* A handle to a Callback Registration Structure (MSDN Documentation)
*
* @implemented * @implemented
*/ *
* Allows a function to associate a callback pointer (Function) to
* a created Callback object
* See: DDK, OSR, links in ExNotifyCallback
*
* @param CallbackObject
* The Object Created with ExCreateCallBack
*
* @param CallBackFunction
* Pointer to the function to be called back
*
* @param CallBackContext
* Block of memory that can contain user-data which will be
* passed on to the callback
*
* @return A handle to a Callback Registration Structure (MSDN Documentation)
*
* @remarks None
*
*--*/
PVOID PVOID
STDCALL NTAPI
ExRegisterCallback( ExRegisterCallback(IN PCALLBACK_OBJECT OpaqueCallbackObject,
IN PCALLBACK_OBJECT OpaqueCallbackObject, IN PCALLBACK_FUNCTION CallbackFunction,
IN PCALLBACK_FUNCTION CallbackFunction, IN PVOID CallbackContext)
IN PVOID CallbackContext
)
{ {
PCALLBACK_OBJECT CallbackObject = (PCALLBACK_OBJECT)OpaqueCallbackObject; PCALLBACK_OBJECT CallbackObject = (PCALLBACK_OBJECT)OpaqueCallbackObject;
PCALLBACK_REGISTRATION CallbackRegistration = NULL; PCALLBACK_REGISTRATION CallbackRegistration = NULL;
KIRQL OldIrql; KIRQL OldIrql;
PAGED_CODE(); PAGED_CODE();
/* Create reference to Callback Object */ /* Create reference to Callback Object */
ObReferenceObject (CallbackObject); ObReferenceObject (CallbackObject);
/* Allocate memory for the structure */ /* Allocate memory for the structure */
CallbackRegistration = ExAllocatePoolWithTag( CallbackRegistration = ExAllocatePoolWithTag(
NonPagedPool, NonPagedPool,
sizeof(CallbackRegistration), sizeof(CallbackRegistration),
CALLBACK_TAG CALLBACK_TAG
); );
/* Fail if memory allocation failed */ /* Fail if memory allocation failed */
if(!CallbackRegistration) if(!CallbackRegistration)
{ {
ObDereferenceObject (CallbackObject); ObDereferenceObject (CallbackObject);
return NULL; return NULL;
} }
/* Create Callback Registration */ /* Create Callback Registration */
CallbackRegistration->CallbackObject = CallbackObject; /* When unregistering, drivers send a handle to the Registration, not the object... */ CallbackRegistration->CallbackObject = CallbackObject; /* When unregistering, drivers send a handle to the Registration, not the object... */
CallbackRegistration->CallbackFunction = CallbackFunction; /* NotifyCallback uses Objects, so this needs to be here in order to call the registered functions */ CallbackRegistration->CallbackFunction = CallbackFunction; /* NotifyCallback uses Objects, so this needs to be here in order to call the registered functions */
CallbackRegistration->CallbackContext = CallbackContext; /* The documented NotifyCallback returns the Context, so we must save this somewhere */ CallbackRegistration->CallbackContext = CallbackContext; /* The documented NotifyCallback returns the Context, so we must save this somewhere */
/* Acquire SpinLock */ /* Acquire SpinLock */
OldIrql = KfAcquireSpinLock (&CallbackObject->Lock); OldIrql = KfAcquireSpinLock (&CallbackObject->Lock);
/* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */ /* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
if(CallbackObject->AllowMultipleCallbacks || IsListEmpty(&CallbackObject->RegisteredCallbacks)) if(CallbackObject->AllowMultipleCallbacks || IsListEmpty(&CallbackObject->RegisteredCallbacks))
{ {
InsertTailList(&CallbackObject->RegisteredCallbacks,&CallbackRegistration->RegisteredCallbacks); InsertTailList(&CallbackObject->RegisteredCallbacks,&CallbackRegistration->RegisteredCallbacks);
} }
else else
{ {
ExFreePool(CallbackRegistration); ExFreePool(CallbackRegistration);
CallbackRegistration = NULL; CallbackRegistration = NULL;
} }
/* Release SpinLock */ /* Release SpinLock */
KfReleaseSpinLock(&CallbackObject->Lock, OldIrql); KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
/* Return handle to Registration Object */ /* Return handle to Registration Object */
return (PVOID) CallbackRegistration; return (PVOID)CallbackRegistration;
} }
/* /*++
* ExUnregisterCallback * @name ExUnregisterCallback
*
* FUNCTION:
* Deregisters a CallBack
*
* ARGUMENTS:
* CallbackRegistration = Callback Registration Handle
*
* RETURNS:
* Nothing
*
* @implemented * @implemented
*/ *
VOID STDCALL * Deregisters a CallBack
ExUnregisterCallback( * See: DDK, OSR, links in ExNotifyCallback
IN PVOID CallbackRegistrationHandle *
) * @param CallbackRegistration
* Callback Registration Handle
*
* @return None
*
* @remarks None
*
*--*/
VOID
NTAPI
ExUnregisterCallback(IN PVOID CallbackRegistrationHandle)
{ {
PCALLBACK_REGISTRATION CallbackRegistration; PCALLBACK_REGISTRATION CallbackRegistration;
PCALLBACK_OBJECT CallbackObject; PCALLBACK_OBJECT CallbackObject;
KIRQL OldIrql; KIRQL OldIrql;
PAGED_CODE(); PAGED_CODE();
/* Convert Handle to valid Structure Pointer */ /* Convert Handle to valid Structure Pointer */
CallbackRegistration = (PCALLBACK_REGISTRATION) CallbackRegistrationHandle; CallbackRegistration = (PCALLBACK_REGISTRATION) CallbackRegistrationHandle;
/* Get the Callback Object */ /* Get the Callback Object */
CallbackObject = CallbackRegistration->CallbackObject; CallbackObject = CallbackRegistration->CallbackObject;
/* Lock the Object */ /* Lock the Object */
OldIrql = KfAcquireSpinLock (&CallbackObject->Lock); OldIrql = KfAcquireSpinLock (&CallbackObject->Lock);
/* We can't Delete the Callback if it's in use, because this would create a call towards a null pointer => crash */ /* We can't Delete the Callback if it's in use, because this would create a call towards a null pointer => crash */
while (CallbackRegistration->InUse) while (CallbackRegistration->InUse)
{ {
/* Similarly, we also don't want to wait ages for all pending callbacks to be called */
CallbackRegistration->PendingDeletion = TRUE;
/* Similarly, we also don't want to wait ages for all pending callbacks to be called */ /* We are going to wait for the event, so the Lock isn't necessary */
CallbackRegistration->PendingDeletion = TRUE; KfReleaseSpinLock (&CallbackObject->Lock, OldIrql);
/* We are going to wait for the event, so the Lock isn't necessary */ /* Make sure the event is cleared */
KfReleaseSpinLock (&CallbackObject->Lock, OldIrql); KeClearEvent (&ExpCallbackEvent);
/* Make sure the event is cleared */ /* Wait for the Event */
KeClearEvent (&ExpCallbackEvent); KeWaitForSingleObject (
&ExpCallbackEvent,
Executive,
KernelMode,
FALSE,
NULL
);
/* Wait for the Event */ /* We need the Lock again */
KeWaitForSingleObject ( OldIrql = KfAcquireSpinLock(&CallbackObject->Lock);
&ExpCallbackEvent, }
Executive,
KernelMode,
FALSE,
NULL
);
/* We need the Lock again */ /* Remove the Callback */
OldIrql = KfAcquireSpinLock(&CallbackObject->Lock); RemoveEntryList(&CallbackRegistration->RegisteredCallbacks);
}
/* Remove the Callback */ /* It's now safe to release the lock */
RemoveEntryList(&CallbackRegistration->RegisteredCallbacks); KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
/* It's now safe to release the lock */ /* Delete this registration */
KfReleaseSpinLock(&CallbackObject->Lock, OldIrql); ExFreePool(CallbackRegistration);
/* Delete this registration */ /* Remove the reference */
ExFreePool(CallbackRegistration); ObDereferenceObject(CallbackObject);
/* Remove the reference */
ObDereferenceObject(CallbackObject);
} }
/* EOF */ /* EOF */