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=2... ============================================================================== --- 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@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 @@ 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_e954f51... * 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/e... ============================================================================== --- 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);