2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ex/callback.c
5 * PURPOSE: Executive callbacks
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
9 /* INCLUDES *****************************************************************/
13 #include <internal/debug.h>
15 #if defined (ALLOC_PRAGMA)
16 #pragma alloc_text(INIT, ExpInitializeCallbacks)
20 /* TYPES ********************************************************************/
22 /* Mapping for Callback Object */
23 GENERIC_MAPPING ExpCallbackMapping
=
31 /* Structure used to hold Callbacks */
32 typedef struct _CALLBACK_REGISTRATION
34 LIST_ENTRY RegisteredCallbacks
;
35 PCALLBACK_OBJECT CallbackObject
;
36 PCALLBACK_FUNCTION CallbackFunction
;
37 PVOID CallbackContext
;
39 BOOLEAN PendingDeletion
;
40 } CALLBACK_REGISTRATION
, *PCALLBACK_REGISTRATION
;
44 PCALLBACK_OBJECT
*CallbackObject
;
48 /* Kernel Default Callbacks */
49 PCALLBACK_OBJECT SetSystemTimeCallback
;
50 PCALLBACK_OBJECT SetSystemStateCallback
;
51 PCALLBACK_OBJECT PowerStateCallback
;
53 SYSTEM_CALLBACKS ExpInitializeCallback
[] =
55 {&SetSystemTimeCallback
, L
"\\Callback\\SetSystemTime"},
56 {&SetSystemStateCallback
, L
"\\Callback\\SetSystemState"},
57 {&PowerStateCallback
, L
"\\Callback\\PowerState"},
61 POBJECT_TYPE ExCallbackObjectType
;
62 KEVENT ExpCallbackEvent
;
64 /* FUNCTIONS *****************************************************************/
67 * ExpInitializeCallbacks
70 * Creates the Callback Object as a valid Object Type in the Kernel.
76 * TRUE if the Callback Object Type was successfully created.
81 ExpInitializeCallbacks(VOID
)
83 OBJECT_ATTRIBUTES ObjectAttributes
;
85 UNICODE_STRING DirName
= RTL_CONSTANT_STRING(L
"\\Callback");
86 UNICODE_STRING CallbackName
;
88 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
89 HANDLE DirectoryHandle
;
92 /* Initialize the Callback Object type */
93 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
94 RtlInitUnicodeString(&Name
, L
"Callback");
95 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
96 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(CALLBACK_OBJECT
);
97 ObjectTypeInitializer
.GenericMapping
= ExpCallbackMapping
;
98 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
100 Status
= ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ExCallbackObjectType
);
102 /* Fail if it wasn't created successfully */
103 if (!NT_SUCCESS(Status
))
108 /* Initialize the Object */
109 InitializeObjectAttributes(
112 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
117 /* Create the Object Directory */
118 Status
= NtCreateDirectoryObject(
120 DIRECTORY_ALL_ACCESS
,
124 /* Fail if couldn't create */
125 if (!NT_SUCCESS(Status
))
130 /* Close Handle... */
131 NtClose(DirectoryHandle
);
133 /* Initialize Event used when unregistering */
134 KeInitializeEvent(&ExpCallbackEvent
, NotificationEvent
, 0);
136 /* Default NT Kernel Callbacks. */
137 for (i
=0; ExpInitializeCallback
[i
].CallbackObject
; i
++)
139 /* Create the name from the structure */
140 RtlInitUnicodeString(&CallbackName
, ExpInitializeCallback
[i
].Name
);
142 /* Initialize the Object Attributes Structure */
143 InitializeObjectAttributes(
146 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
151 /* Create the Callback Object */
152 Status
= ExCreateCallback(
153 (PCALLBACK_OBJECT
*)&(ExpInitializeCallback
[i
].CallbackObject
),
159 /* Make sure Global Callbacks have been created */
160 if (!NT_SUCCESS(Status
))
165 /* Everything successful */
172 * Opens or creates a Callback Object. Creates only if Create is true.
173 * Allows multiple Callback Functions to be registred only if AllowMultipleCallbacks
177 * CallbackObject = Pointer that will receive the Callback Object.
178 * CallbackName = Name of Callback
179 * Create = Determines if the object will be created if it doesn't exit
180 * AllowMultipleCallbacks = Determines if more then one registered callback function
181 * can be attached to this Callback Object.
184 * STATUS_SUCESS if not failed.
191 OUT PCALLBACK_OBJECT
*CallbackObject
,
192 IN POBJECT_ATTRIBUTES ObjectAttributes
,
194 IN BOOLEAN AllowMultipleCallbacks
197 PCALLBACK_OBJECT Callback
;
203 /* Open a handle to the callback if it exists */
204 if (ObjectAttributes
->ObjectName
)
206 Status
= ObOpenObjectByName(ObjectAttributes
,
207 ExCallbackObjectType
,
216 Status
= STATUS_UNSUCCESSFUL
;
219 /* We weren't able to open it...should we create it? */
220 if(!NT_SUCCESS(Status
) && Create
)
222 Status
= ObCreateObject(KernelMode
,
223 ExCallbackObjectType
,
227 sizeof(CALLBACK_OBJECT
),
230 (PVOID
*)&Callback
);
232 /* We Created it...let's initialize the structure now */
233 if(NT_SUCCESS(Status
))
235 KeInitializeSpinLock (&Callback
->Lock
); /* SpinLock */
236 InitializeListHead(&Callback
->RegisteredCallbacks
); /* Callback Entries */
237 Callback
->AllowMultipleCallbacks
= AllowMultipleCallbacks
; /* Multiple Callbacks */
238 Status
= ObInsertObject ( /* Create the object */
247 if(NT_SUCCESS(Status
))
250 /* Get a pointer to the new object from the handle we just got */
251 Status
= ObReferenceObjectByHandle (
254 ExCallbackObjectType
,
259 /* Close the Handle, since we now have the pointer */
263 /* Everything went fine, so return a pointer to the Object */
264 if (NT_SUCCESS(Status
))
266 *CallbackObject
= (PCALLBACK_OBJECT
)Callback
;
275 * Calls a function pointer (a registered callback)
278 * CallbackObject - Which callback to call
279 * Argument1 - Pointer/data to send to callback function
280 * Argument2 - Pointer/data to send to callback function
290 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
295 PCALLBACK_OBJECT CallbackObject
= (PCALLBACK_OBJECT
)OpaqueCallbackObject
;
296 PLIST_ENTRY RegisteredCallbacks
;
297 PCALLBACK_REGISTRATION CallbackRegistration
;
300 /* Acquire the Lock */
301 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
303 /* Enumerate through all the registered functions */
304 for (RegisteredCallbacks
= CallbackObject
->RegisteredCallbacks
.Flink
;
305 RegisteredCallbacks
!= &CallbackObject
->RegisteredCallbacks
;
306 RegisteredCallbacks
= RegisteredCallbacks
->Flink
)
309 /* Get a pointer to a Callback Registration from the List Entries */
310 CallbackRegistration
= CONTAINING_RECORD ( RegisteredCallbacks
,
311 CALLBACK_REGISTRATION
,
312 RegisteredCallbacks
);
314 /* Don't bother doing Callback Notification if it's pending to be deleted */
315 if (!CallbackRegistration
->PendingDeletion
)
318 /* Mark the Callback in use, so it won't get deleted while we are calling it */
319 CallbackRegistration
->InUse
+= 1;
321 /* Release the Spinlock before making the call */
322 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
324 /* Call the Registered Function */
325 CallbackRegistration
->CallbackFunction (
326 CallbackRegistration
->CallbackContext
,
331 /* Get SpinLock back */
332 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
334 /* We are not in use anymore */
335 CallbackRegistration
->InUse
-= 1;
337 /* If another instance of this function isn't running and deletion is pending, signal the event */
338 if (CallbackRegistration
->PendingDeletion
&& CallbackRegistration
->InUse
== 0)
340 KeSetEvent(&ExpCallbackEvent
, 0, FALSE
);
344 /* Unsynchronize and release the Callback Object */
345 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
352 * Allows a function to associate a callback pointer (Function)
353 * to a created Callback object
356 * CallbackObject = The Object Created with ExCreateCallBack
357 * CallBackFunction = Pointer to the function to be called back
358 * CallBackContext = Block of memory that can contain user-data
359 * which will be passed on to the callback
362 * A handle to a Callback Registration Structure (MSDN Documentation)
369 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
370 IN PCALLBACK_FUNCTION CallbackFunction
,
371 IN PVOID CallbackContext
374 PCALLBACK_OBJECT CallbackObject
= (PCALLBACK_OBJECT
)OpaqueCallbackObject
;
375 PCALLBACK_REGISTRATION CallbackRegistration
= NULL
;
380 /* Create reference to Callback Object */
381 ObReferenceObject (CallbackObject
);
383 /* Allocate memory for the structure */
384 CallbackRegistration
= ExAllocatePoolWithTag(
386 sizeof(CallbackRegistration
),
389 /* Fail if memory allocation failed */
390 if(!CallbackRegistration
)
392 ObDereferenceObject (CallbackObject
);
396 /* Create Callback Registration */
397 CallbackRegistration
->CallbackObject
= CallbackObject
; /* When unregistering, drivers send a handle to the Registration, not the object... */
398 CallbackRegistration
->CallbackFunction
= CallbackFunction
; /* NotifyCallback uses Objects, so this needs to be here in order to call the registered functions */
399 CallbackRegistration
->CallbackContext
= CallbackContext
; /* The documented NotifyCallback returns the Context, so we must save this somewhere */
401 /* Acquire SpinLock */
402 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
404 /* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
405 if(CallbackObject
->AllowMultipleCallbacks
|| IsListEmpty(&CallbackObject
->RegisteredCallbacks
))
407 InsertTailList(&CallbackObject
->RegisteredCallbacks
,&CallbackRegistration
->RegisteredCallbacks
);
411 ExFreePool(CallbackRegistration
);
412 CallbackRegistration
= NULL
;
415 /* Release SpinLock */
416 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
418 /* Return handle to Registration Object */
419 return (PVOID
) CallbackRegistration
;
423 * ExUnregisterCallback
426 * Deregisters a CallBack
429 * CallbackRegistration = Callback Registration Handle
437 ExUnregisterCallback(
438 IN PVOID CallbackRegistrationHandle
441 PCALLBACK_REGISTRATION CallbackRegistration
;
442 PCALLBACK_OBJECT CallbackObject
;
447 /* Convert Handle to valid Structure Pointer */
448 CallbackRegistration
= (PCALLBACK_REGISTRATION
) CallbackRegistrationHandle
;
450 /* Get the Callback Object */
451 CallbackObject
= CallbackRegistration
->CallbackObject
;
453 /* Lock the Object */
454 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
456 /* We can't Delete the Callback if it's in use, because this would create a call towards a null pointer => crash */
457 while (CallbackRegistration
->InUse
)
460 /* Similarly, we also don't want to wait ages for all pending callbacks to be called */
461 CallbackRegistration
->PendingDeletion
= TRUE
;
463 /* We are going to wait for the event, so the Lock isn't necessary */
464 KfReleaseSpinLock (&CallbackObject
->Lock
, OldIrql
);
466 /* Make sure the event is cleared */
467 KeClearEvent (&ExpCallbackEvent
);
469 /* Wait for the Event */
470 KeWaitForSingleObject (
478 /* We need the Lock again */
479 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
482 /* Remove the Callback */
483 RemoveEntryList(&CallbackRegistration
->RegisteredCallbacks
);
485 /* It's now safe to release the lock */
486 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
488 /* Delete this registration */
489 ExFreePool(CallbackRegistration
);
491 /* Remove the reference */
492 ObDereferenceObject(CallbackObject
);