Author: ion
Date: Tue Jan 16 07:16:31 2007
New Revision: 25482
URL:
http://svn.reactos.org/svn/reactos?rev=25482&view=rev
Log:
- 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.
Modified:
trunk/reactos/include/ndk/extypes.h
trunk/reactos/ntoskrnl/ex/callback.c
trunk/reactos/ntoskrnl/include/internal/ex.h
Modified: trunk/reactos/include/ndk/extypes.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/include/ndk/extypes.h?rev=…
==============================================================================
--- trunk/reactos/include/ndk/extypes.h (original)
+++ trunk/reactos/include/ndk/extypes.h Tue Jan 16 07:16:31 2007
@@ -488,11 +488,25 @@
//
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
Modified: trunk/reactos/ntoskrnl/ex/callback.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/ex/callback.c?rev…
==============================================================================
--- trunk/reactos/ntoskrnl/ex/callback.c (original)
+++ trunk/reactos/ntoskrnl/ex/callback.c Tue Jan 16 07:16:31 2007
@@ -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(a)relsoft.net)
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu(a)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 @@
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 @@
* @remarks None
*
*--*/
-VOID
+BOOLEAN
INIT_FUNCTION
NTAPI
ExpInitializeCallbacks(VOID)
@@ -89,43 +73,33 @@
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,36 +108,31 @@
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
@@ -200,15 +169,15 @@
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 @@
}
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 @@
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 @@
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 @@
*
* 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_e954f5…
*
http://vmsone.com/~decuslib/vmssig/vmslt99b/nt/wdm-callback.txt
*
* @param CallbackObject
@@ -297,17 +267,24 @@
*--*/
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 @@
/* Get a pointer to a Callback Registration from the List Entries */
CallbackRegistration = CONTAINING_RECORD(RegisteredCallbacks,
CALLBACK_REGISTRATION,
- RegisteredCallbacks);
-
- /* Don't bother doing Callback Notification if it's pending to be deleted
*/
- if (!CallbackRegistration->PendingDeletion)
+ Link);
+
+ /* 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;
-
- /* If another instance of this function isn't running and deletion is
pending, signal the event */
- if (CallbackRegistration->PendingDeletion &&
CallbackRegistration->InUse == 0)
+ CallbackRegistration->Busy -= 1;
+
+ /* 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 @@
*--*/
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;
-
- PAGED_CODE();
+ PCALLBACK_REGISTRATION CallbackRegistration = NULL;
+ KIRQL OldIrql;
+
+ /* 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);
-
- /* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
- if(CallbackObject->AllowMultipleCallbacks ||
IsListEmpty(&CallbackObject->RegisteredCallbacks))
- {
-
InsertTailList(&CallbackObject->RegisteredCallbacks,&CallbackRegistration->RegisteredCallbacks);
+ KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql);
+
+ /* Check if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
+ if ((CallbackObject->AllowMultipleCallbacks) ||
+ (IsListEmpty(&CallbackObject->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 @@
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);
-
- /* 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)
- {
- /* Similarly, we also don't want to wait ages for all pending callbacks to be
called */
- CallbackRegistration->PendingDeletion = TRUE;
+ KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql);
+
+ /* We can't Delete the Callback if it's in use */
+ while (CallbackRegistration->Busy)
+ {
+ /* 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);
Modified: trunk/reactos/ntoskrnl/include/internal/ex.h
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/include/internal/…
==============================================================================
--- trunk/reactos/ntoskrnl/include/internal/ex.h (original)
+++ trunk/reactos/ntoskrnl/include/internal/ex.h Tue Jan 16 07:16:31 2007
@@ -34,6 +34,12 @@
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 @@
IN PLIST_ENTRY ListHead
);
-VOID
+BOOLEAN
NTAPI
ExpInitializeCallbacks(VOID);