- Large cleanup of exported callback implementation. It was my first code to ReactOS and quite messy.

- Make code use standard NT structures.
- Fix object type initialization.
- Fix calls to ExCreatecallback during system initalization which were randomly overwriting memory.
- Fix ExREgisterCallback which was allocating only a pointer inside of the entire structure, also over-writing system memory.

svn path=/trunk/; revision=25482
This commit is contained in:
Alex Ionescu 2007-01-16 04:16:31 +00:00
parent 532a28a03c
commit b51d473275
3 changed files with 181 additions and 174 deletions

View file

@ -488,11 +488,25 @@ typedef __ALIGNED(16) struct _EX_PUSH_LOCK_WAIT_BLOCK
//
typedef struct _CALLBACK_OBJECT
{
ULONG Name;
ULONG Signature;
KSPIN_LOCK Lock;
LIST_ENTRY RegisteredCallbacks;
ULONG AllowMultipleCallbacks;
} CALLBACK_OBJECT , *PCALLBACK_OBJECT;
BOOLEAN AllowMultipleCallbacks;
UCHAR reserved[3];
} CALLBACK_OBJECT, *PCALLBACK_OBJECT;
//
// Callback Handle
//
typedef struct _CALLBACK_REGISTRATION
{
LIST_ENTRY Link;
PCALLBACK_OBJECT CallbackObject;
PCALLBACK_FUNCTION CallbackFunction;
PVOID CallbackContext;
ULONG Busy;
BOOLEAN UnregisterWaiting;
} CALLBACK_REGISTRATION, *PCALLBACK_REGISTRATION;
//
// Internal Callback Object

View file

@ -3,54 +3,30 @@
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/ex/callback.c
* PURPOSE: Executive callbacks
* PROGRAMMERS: Filip Navara
* Alex Ionescu (alex@relsoft.net)
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
#include <internal/debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, ExpInitializeCallbacks)
#endif
/* TYPES ********************************************************************/
/* TYPES *********************************************************************/
/* Mapping for Callback Object */
GENERIC_MAPPING ExpCallbackMapping =
{
CALLBACK_READ,
CALLBACK_WRITE,
CALLBACK_EXECUTE,
CALLBACK_ALL_ACCESS
CALLBACK_READ,
CALLBACK_WRITE,
CALLBACK_EXECUTE,
CALLBACK_ALL_ACCESS
};
/* Structure used to hold Callbacks */
typedef struct _CALLBACK_REGISTRATION
{
LIST_ENTRY RegisteredCallbacks;
PCALLBACK_OBJECT CallbackObject;
PCALLBACK_FUNCTION CallbackFunction;
PVOID CallbackContext;
ULONG InUse;
BOOLEAN PendingDeletion;
} CALLBACK_REGISTRATION, *PCALLBACK_REGISTRATION;
typedef struct
{
PCALLBACK_OBJECT *CallbackObject;
PWSTR Name;
} SYSTEM_CALLBACKS;
/* Kernel Default Callbacks */
PCALLBACK_OBJECT SetSystemTimeCallback;
PCALLBACK_OBJECT SetSystemStateCallback;
PCALLBACK_OBJECT PowerStateCallback;
SYSTEM_CALLBACKS ExpInitializeCallback[] =
{
{&SetSystemTimeCallback, L"\\Callback\\SetSystemTime"},
@ -62,7 +38,15 @@ SYSTEM_CALLBACKS ExpInitializeCallback[] =
POBJECT_TYPE ExCallbackObjectType;
KEVENT ExpCallbackEvent;
/* FUNCTIONS *****************************************************************/
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
ExpDeleteCallback(IN PVOID Object)
{
/* Sanity check */
ASSERT(IsListEmpty(&((PCALLBACK_OBJECT)Object)->RegisteredCallbacks));
}
/*++
* @name ExpInitializeCallbacks
@ -75,7 +59,7 @@ KEVENT ExpCallbackEvent;
* @remarks None
*
*--*/
VOID
BOOLEAN
INIT_FUNCTION
NTAPI
ExpInitializeCallbacks(VOID)
@ -89,43 +73,33 @@ ExpInitializeCallbacks(VOID)
HANDLE DirectoryHandle;
ULONG i;
/* Initialize the Callback Object type */
/* Initialize the Callback Object type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Callback");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(CALLBACK_OBJECT);
ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK;
ObjectTypeInitializer.GenericMapping = ExpCallbackMapping;
ObjectTypeInitializer.PoolType = NonPagedPool;
Status = ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &ExCallbackObjectType);
/* Fail if it wasn't created successfully */
if (!NT_SUCCESS(Status))
{
return;
}
ObjectTypeInitializer.DeleteProcedure = ExpDeleteCallback;
ObjectTypeInitializer.ValidAccessMask = CALLBACK_ALL_ACCESS;
Status = ObCreateObjectType(&Name,
&ObjectTypeInitializer,
NULL,
&ExCallbackObjectType);
if (!NT_SUCCESS(Status)) return FALSE;
/* Initialize the Object */
InitializeObjectAttributes(
&ObjectAttributes,
&DirName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
NULL
);
InitializeObjectAttributes(&ObjectAttributes,
&DirName,
OBJ_CASE_INSENSITIVE | OBJ_PERMANENT,
NULL,
SePublicDefaultSd);
/* Create the Object Directory */
Status = NtCreateDirectoryObject(
&DirectoryHandle,
DIRECTORY_ALL_ACCESS,
&ObjectAttributes
);
/* Fail if couldn't create */
if (!NT_SUCCESS(Status))
{
return;
}
Status = NtCreateDirectoryObject(&DirectoryHandle,
DIRECTORY_ALL_ACCESS,
&ObjectAttributes);
if (!NT_SUCCESS(Status)) return FALSE;
/* Close Handle... */
NtClose(DirectoryHandle);
@ -134,37 +108,32 @@ ExpInitializeCallbacks(VOID)
KeInitializeEvent(&ExpCallbackEvent, NotificationEvent, 0);
/* Default NT Kernel Callbacks. */
for (i=0; ExpInitializeCallback[i].CallbackObject; i++)
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
);
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;
}
Status = ExCreateCallback(ExpInitializeCallback[i].CallbackObject,
&ObjectAttributes,
TRUE,
TRUE);
if (!NT_SUCCESS(Status)) return FALSE;
}
/* Everything successful */
return TRUE;
}
/* PUBLIC FUNCTIONS **********************************************************/
/*++
* @name ExCreateCallback
* @implemented
@ -200,15 +169,15 @@ ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject,
IN BOOLEAN Create,
IN BOOLEAN AllowMultipleCallbacks)
{
PCALLBACK_OBJECT Callback;
NTSTATUS Status;
HANDLE Handle;
PCALLBACK_OBJECT Callback = NULL;
NTSTATUS Status;
HANDLE Handle = NULL;
PAGED_CODE();
/* Open a handle to the callback if it exists */
if (ObjectAttributes->ObjectName)
{
/* Open the handle */
Status = ObOpenObjectByName(ObjectAttributes,
ExCallbackObjectType,
KernelMode,
@ -219,12 +188,14 @@ ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject,
}
else
{
/* Otherwise, fail */
Status = STATUS_UNSUCCESSFUL;
}
/* We weren't able to open it...should we create it? */
if(!NT_SUCCESS(Status) && Create )
if (!(NT_SUCCESS(Status)) && (Create))
{
/* Create the object */
Status = ObCreateObject(KernelMode,
ExCallbackObjectType,
ObjectAttributes,
@ -233,25 +204,27 @@ ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject,
sizeof(CALLBACK_OBJECT),
0,
0,
(PVOID *)&Callback );
/* We Created it...let's initialize the structure now */
if(NT_SUCCESS(Status))
(PVOID *)&Callback);
if (NT_SUCCESS(Status))
{
KeInitializeSpinLock(&Callback->Lock); /* SpinLock */
InitializeListHead(&Callback->RegisteredCallbacks); /* Callback Entries */
Callback->AllowMultipleCallbacks = AllowMultipleCallbacks; /* Multiple Callbacks */
/* Create the object */
/* Set it up */
Callback->Signature = TAG('C', 'a', 'l', 'l');
KeInitializeSpinLock(&Callback->Lock);
InitializeListHead(&Callback->RegisteredCallbacks);
Callback->AllowMultipleCallbacks = AllowMultipleCallbacks;
/* Insert the object into the object namespace */
Status = ObInsertObject(Callback,
NULL,
FILE_READ_DATA,
0,
NULL,
&Handle );
&Handle);
}
}
if(NT_SUCCESS(Status))
/* Check if we have success until here */
if (NT_SUCCESS(Status))
{
/* Get a pointer to the new object from the handle we just got */
Status = ObReferenceObjectByHandle(Handle,
@ -260,15 +233,13 @@ ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject,
KernelMode,
(PVOID)&Callback,
NULL);
/* Close the Handle, since we now have the pointer */
ZwClose(Handle);
}
/* Everything went fine, so return a pointer to the Object */
if (NT_SUCCESS(Status))
{
*CallbackObject = (PCALLBACK_OBJECT)Callback;
}
if (NT_SUCCESS(Status)) *CallbackObject = Callback;
return Status;
}
@ -278,7 +249,6 @@ ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject,
*
* 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
@ -297,17 +267,24 @@ ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject,
*--*/
VOID
NTAPI
ExNotifyCallback(IN PCALLBACK_OBJECT OpaqueCallbackObject,
ExNotifyCallback(IN PCALLBACK_OBJECT CallbackObject,
IN PVOID Argument1,
IN PVOID Argument2)
{
PCALLBACK_OBJECT CallbackObject = (PCALLBACK_OBJECT)OpaqueCallbackObject;
PLIST_ENTRY RegisteredCallbacks;
PCALLBACK_REGISTRATION CallbackRegistration;
KIRQL OldIrql;
PLIST_ENTRY RegisteredCallbacks;
PCALLBACK_REGISTRATION CallbackRegistration;
KIRQL OldIrql;
/* Check if we don't have an object or registrations */
if (!(CallbackObject) ||
(IsListEmpty(&CallbackObject->RegisteredCallbacks)))
{
/* Don't notify */
return;
}
/* Acquire the Lock */
OldIrql = KfAcquireSpinLock(&CallbackObject->Lock);
KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql);
/* Enumerate through all the registered functions */
for (RegisteredCallbacks = CallbackObject->RegisteredCallbacks.Flink;
@ -317,39 +294,41 @@ ExNotifyCallback(IN PCALLBACK_OBJECT OpaqueCallbackObject,
/* Get a pointer to a Callback Registration from the List Entries */
CallbackRegistration = CONTAINING_RECORD(RegisteredCallbacks,
CALLBACK_REGISTRATION,
RegisteredCallbacks);
Link);
/* Don't bother doing Callback Notification if it's pending to be deleted */
if (!CallbackRegistration->PendingDeletion)
/* Don't bother doing notification if it's pending to be deleted */
if (!CallbackRegistration->UnregisterWaiting)
{
/* Mark the Callback in use, so it won't get deleted while we are calling it */
CallbackRegistration->InUse += 1;
/* Mark the Callback in use, so it won't get deleted */
CallbackRegistration->Busy += 1;
/* Release the Spinlock before making the call */
KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
KeReleaseSpinLock(&CallbackObject->Lock, OldIrql);
/* Call the Registered Function */
CallbackRegistration->CallbackFunction(
CallbackRegistration->CallbackContext,
Argument1,
Argument2
);
CallbackRegistration->CallbackFunction(CallbackRegistration->
CallbackContext,
Argument1,
Argument2);
/* Get SpinLock back */
OldIrql = KfAcquireSpinLock(&CallbackObject->Lock);
KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql);
/* We are not in use anymore */
CallbackRegistration->InUse -= 1;
CallbackRegistration->Busy -= 1;
/* If another instance of this function isn't running and deletion is pending, signal the event */
if (CallbackRegistration->PendingDeletion && CallbackRegistration->InUse == 0)
/* Check if removal is pending and we're not active */
if ((CallbackRegistration->UnregisterWaiting) &&
!(CallbackRegistration->Busy))
{
/* Signal the callback event */
KeSetEvent(&ExpCallbackEvent, 0, FALSE);
}
}
}
/* Unsynchronize and release the Callback Object */
KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
/* Release the Callback Object */
KeReleaseSpinLock(&CallbackObject->Lock, OldIrql);
}
/*++
@ -377,53 +356,64 @@ ExNotifyCallback(IN PCALLBACK_OBJECT OpaqueCallbackObject,
*--*/
PVOID
NTAPI
ExRegisterCallback(IN PCALLBACK_OBJECT OpaqueCallbackObject,
ExRegisterCallback(IN PCALLBACK_OBJECT CallbackObject,
IN PCALLBACK_FUNCTION CallbackFunction,
IN PVOID CallbackContext)
{
PCALLBACK_OBJECT CallbackObject = (PCALLBACK_OBJECT)OpaqueCallbackObject;
PCALLBACK_REGISTRATION CallbackRegistration = NULL;
KIRQL OldIrql;
PCALLBACK_REGISTRATION CallbackRegistration = NULL;
KIRQL OldIrql;
PAGED_CODE();
/* Sanity checks */
ASSERT(CallbackFunction);
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Create reference to Callback Object */
ObReferenceObject (CallbackObject);
ObReferenceObject(CallbackObject);
/* Allocate memory for the structure */
CallbackRegistration = ExAllocatePoolWithTag(
NonPagedPool,
sizeof(CallbackRegistration),
CALLBACK_TAG
);
/* Fail if memory allocation failed */
if(!CallbackRegistration)
CallbackRegistration = ExAllocatePoolWithTag(NonPagedPool,
sizeof(CALLBACK_REGISTRATION),
CALLBACK_TAG);
if (!CallbackRegistration)
{
/* Dereference and fail */
ObDereferenceObject (CallbackObject);
return NULL;
}
/* Create Callback Registration */
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->CallbackContext = CallbackContext; /* The documented NotifyCallback returns the Context, so we must save this somewhere */
CallbackRegistration->CallbackObject = CallbackObject;
CallbackRegistration->CallbackFunction = CallbackFunction;
CallbackRegistration->CallbackContext = CallbackContext;
CallbackRegistration->Busy = 0;
CallbackRegistration->UnregisterWaiting = FALSE;
/* Acquire SpinLock */
OldIrql = KfAcquireSpinLock (&CallbackObject->Lock);
KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql);
/* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
if(CallbackObject->AllowMultipleCallbacks || IsListEmpty(&CallbackObject->RegisteredCallbacks))
/* Check if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
if ((CallbackObject->AllowMultipleCallbacks) ||
(IsListEmpty(&CallbackObject->RegisteredCallbacks)))
{
InsertTailList(&CallbackObject->RegisteredCallbacks,&CallbackRegistration->RegisteredCallbacks);
/* Register the callback */
InsertTailList(&CallbackObject->RegisteredCallbacks,
&CallbackRegistration->Link);
/* Release SpinLock */
KeReleaseSpinLock(&CallbackObject->Lock, OldIrql);
}
else
{
/* Release SpinLock */
KeReleaseSpinLock(&CallbackObject->Lock, OldIrql);
/* Free the registration */
ExFreePool(CallbackRegistration);
CallbackRegistration = NULL;
}
/* Release SpinLock */
KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
/* Dereference the object */
ObDereferenceObject(CallbackObject);
}
/* Return handle to Registration Object */
return (PVOID)CallbackRegistration;
@ -448,51 +438,48 @@ VOID
NTAPI
ExUnregisterCallback(IN PVOID CallbackRegistrationHandle)
{
PCALLBACK_REGISTRATION CallbackRegistration;
PCALLBACK_OBJECT CallbackObject;
KIRQL OldIrql;
PAGED_CODE();
PCALLBACK_REGISTRATION CallbackRegistration;
PCALLBACK_OBJECT CallbackObject;
KIRQL OldIrql;
ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL);
/* Convert Handle to valid Structure Pointer */
CallbackRegistration = (PCALLBACK_REGISTRATION) CallbackRegistrationHandle;
CallbackRegistration = (PCALLBACK_REGISTRATION)CallbackRegistrationHandle;
/* Get the Callback Object */
CallbackObject = CallbackRegistration->CallbackObject;
/* Lock the Object */
OldIrql = KfAcquireSpinLock (&CallbackObject->Lock);
KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql);
/* 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)
/* We can't Delete the Callback if it's in use */
while (CallbackRegistration->Busy)
{
/* Similarly, we also don't want to wait ages for all pending callbacks to be called */
CallbackRegistration->PendingDeletion = TRUE;
/* Let everyone else know we're unregistering */
CallbackRegistration->UnregisterWaiting = TRUE;
/* We are going to wait for the event, so the Lock isn't necessary */
KfReleaseSpinLock (&CallbackObject->Lock, OldIrql);
KeReleaseSpinLock(&CallbackObject->Lock, OldIrql);
/* Make sure the event is cleared */
KeClearEvent (&ExpCallbackEvent);
KeClearEvent(&ExpCallbackEvent);
/* Wait for the Event */
KeWaitForSingleObject (
&ExpCallbackEvent,
Executive,
KernelMode,
FALSE,
NULL
);
KeWaitForSingleObject(&ExpCallbackEvent,
Executive,
KernelMode,
FALSE,
NULL);
/* We need the Lock again */
OldIrql = KfAcquireSpinLock(&CallbackObject->Lock);
KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql);
}
/* Remove the Callback */
RemoveEntryList(&CallbackRegistration->RegisteredCallbacks);
RemoveEntryList(&CallbackRegistration->Link);
/* It's now safe to release the lock */
KfReleaseSpinLock(&CallbackObject->Lock, OldIrql);
KeReleaseSpinLock(&CallbackObject->Lock, OldIrql);
/* Delete this registration */
ExFreePool(CallbackRegistration);

View file

@ -34,6 +34,12 @@ typedef struct _ETIMER
LIST_ENTRY WakeTimerListEntry;
} ETIMER, *PETIMER;
typedef struct
{
PCALLBACK_OBJECT *CallbackObject;
PWSTR Name;
} SYSTEM_CALLBACKS;
#define MAX_FAST_REFS 7
#define EX_OBJ_TO_HDR(eob) ((POBJECT_HEADER)((ULONG_PTR)(eob) & \
@ -107,7 +113,7 @@ ExInitializeSystemLookasideList(
IN PLIST_ENTRY ListHead
);
VOID
BOOLEAN
NTAPI
ExpInitializeCallbacks(VOID);