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 /* TYPES ********************************************************************/
17 /* Mapping for Callback Object */
18 GENERIC_MAPPING ExpCallbackMapping
=
26 /* Structure used to hold Callbacks */
27 typedef struct _CALLBACK_REGISTRATION
29 LIST_ENTRY RegisteredCallbacks
;
30 PCALLBACK_OBJECT CallbackObject
;
31 PCALLBACK_FUNCTION CallbackFunction
;
32 PVOID CallbackContext
;
34 BOOLEAN PendingDeletion
;
35 } CALLBACK_REGISTRATION
, *PCALLBACK_REGISTRATION
;
39 PCALLBACK_OBJECT
*CallbackObject
;
43 /* Kernel Default Callbacks */
44 PCALLBACK_OBJECT SetSystemTimeCallback
;
45 PCALLBACK_OBJECT SetSystemStateCallback
;
46 PCALLBACK_OBJECT PowerStateCallback
;
48 SYSTEM_CALLBACKS ExpInitializeCallback
[] =
50 {&SetSystemTimeCallback
, L
"\\Callback\\SetSystemTime"},
51 {&SetSystemStateCallback
, L
"\\Callback\\SetSystemState"},
52 {&PowerStateCallback
, L
"\\Callback\\PowerState"},
56 POBJECT_TYPE ExCallbackObjectType
;
57 KEVENT ExpCallbackEvent
;
59 /* FUNCTIONS *****************************************************************/
62 * ExpInitializeCallbacks
65 * Creates the Callback Object as a valid Object Type in the Kernel.
71 * TRUE if the Callback Object Type was successfully created.
76 ExpInitializeCallbacks(VOID
)
78 OBJECT_ATTRIBUTES ObjectAttributes
;
80 UNICODE_STRING DirName
= RTL_CONSTANT_STRING(L
"\\Callback");
81 UNICODE_STRING CallbackName
;
83 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
84 HANDLE DirectoryHandle
;
87 /* Initialize the Callback Object type */
88 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
89 RtlInitUnicodeString(&Name
, L
"Callback");
90 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
91 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(CALLBACK_OBJECT
);
92 ObjectTypeInitializer
.GenericMapping
= ExpCallbackMapping
;
93 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
95 Status
= ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ExCallbackObjectType
);
97 /* Fail if it wasn't created successfully */
98 if (!NT_SUCCESS(Status
))
103 /* Initialize the Object */
104 InitializeObjectAttributes(
107 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
112 /* Create the Object Directory */
113 Status
= NtCreateDirectoryObject(
115 DIRECTORY_ALL_ACCESS
,
119 /* Fail if couldn't create */
120 if (!NT_SUCCESS(Status
))
125 /* Close Handle... */
126 NtClose(DirectoryHandle
);
128 /* Initialize Event used when unregistering */
129 KeInitializeEvent(&ExpCallbackEvent
, NotificationEvent
, 0);
131 /* Default NT Kernel Callbacks. */
132 for (i
=0; ExpInitializeCallback
[i
].CallbackObject
; i
++)
134 /* Create the name from the structure */
135 RtlInitUnicodeString(&CallbackName
, ExpInitializeCallback
[i
].Name
);
137 /* Initialize the Object Attributes Structure */
138 InitializeObjectAttributes(
141 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
146 /* Create the Callback Object */
147 Status
= ExCreateCallback(
148 (PCALLBACK_OBJECT
*)&(ExpInitializeCallback
[i
].CallbackObject
),
154 /* Make sure Global Callbacks have been created */
155 if (!NT_SUCCESS(Status
))
160 /* Everything successful */
167 * Opens or creates a Callback Object. Creates only if Create is true.
168 * Allows multiple Callback Functions to be registred only if AllowMultipleCallbacks
172 * CallbackObject = Pointer that will receive the Callback Object.
173 * CallbackName = Name of Callback
174 * Create = Determines if the object will be created if it doesn't exit
175 * AllowMultipleCallbacks = Determines if more then one registered callback function
176 * can be attached to this Callback Object.
179 * STATUS_SUCESS if not failed.
186 OUT PCALLBACK_OBJECT
*CallbackObject
,
187 IN POBJECT_ATTRIBUTES ObjectAttributes
,
189 IN BOOLEAN AllowMultipleCallbacks
192 PCALLBACK_OBJECT Callback
;
198 /* Open a handle to the callback if it exists */
199 if (ObjectAttributes
->ObjectName
)
201 Status
= ObOpenObjectByName(ObjectAttributes
,
202 ExCallbackObjectType
,
211 Status
= STATUS_UNSUCCESSFUL
;
214 /* We weren't able to open it...should we create it? */
215 if(!NT_SUCCESS(Status
) && Create
)
217 Status
= ObCreateObject(KernelMode
,
218 ExCallbackObjectType
,
222 sizeof(CALLBACK_OBJECT
),
225 (PVOID
*)&Callback
);
227 /* We Created it...let's initialize the structure now */
228 if(NT_SUCCESS(Status
))
230 KeInitializeSpinLock (&Callback
->Lock
); /* SpinLock */
231 InitializeListHead(&Callback
->RegisteredCallbacks
); /* Callback Entries */
232 Callback
->AllowMultipleCallbacks
= AllowMultipleCallbacks
; /* Multiple Callbacks */
233 Status
= ObInsertObject ( /* Create the object */
242 if(NT_SUCCESS(Status
))
245 /* Get a pointer to the new object from the handle we just got */
246 Status
= ObReferenceObjectByHandle (
249 ExCallbackObjectType
,
254 /* Close the Handle, since we now have the pointer */
258 /* Everything went fine, so return a pointer to the Object */
259 if (NT_SUCCESS(Status
))
261 *CallbackObject
= (PCALLBACK_OBJECT
)Callback
;
270 * Calls a function pointer (a registered callback)
273 * CallbackObject - Which callback to call
274 * Argument1 - Pointer/data to send to callback function
275 * Argument2 - Pointer/data to send to callback function
285 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
290 PCALLBACK_OBJECT CallbackObject
= (PCALLBACK_OBJECT
)OpaqueCallbackObject
;
291 PLIST_ENTRY RegisteredCallbacks
;
292 PCALLBACK_REGISTRATION CallbackRegistration
;
295 /* Acquire the Lock */
296 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
298 /* Enumerate through all the registered functions */
299 for (RegisteredCallbacks
= CallbackObject
->RegisteredCallbacks
.Flink
;
300 RegisteredCallbacks
!= &CallbackObject
->RegisteredCallbacks
;
301 RegisteredCallbacks
= RegisteredCallbacks
->Flink
)
304 /* Get a pointer to a Callback Registration from the List Entries */
305 CallbackRegistration
= CONTAINING_RECORD ( RegisteredCallbacks
,
306 CALLBACK_REGISTRATION
,
307 RegisteredCallbacks
);
309 /* Don't bother doing Callback Notification if it's pending to be deleted */
310 if (!CallbackRegistration
->PendingDeletion
)
313 /* Mark the Callback in use, so it won't get deleted while we are calling it */
314 CallbackRegistration
->InUse
+= 1;
316 /* Release the Spinlock before making the call */
317 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
319 /* Call the Registered Function */
320 CallbackRegistration
->CallbackFunction (
321 CallbackRegistration
->CallbackContext
,
326 /* Get SpinLock back */
327 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
329 /* We are not in use anymore */
330 CallbackRegistration
->InUse
-= 1;
332 /* If another instance of this function isn't running and deletion is pending, signal the event */
333 if (CallbackRegistration
->PendingDeletion
&& CallbackRegistration
->InUse
== 0)
335 KeSetEvent(&ExpCallbackEvent
, 0, FALSE
);
339 /* Unsynchronize and release the Callback Object */
340 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
347 * Allows a function to associate a callback pointer (Function)
348 * to a created Callback object
351 * CallbackObject = The Object Created with ExCreateCallBack
352 * CallBackFunction = Pointer to the function to be called back
353 * CallBackContext = Block of memory that can contain user-data
354 * which will be passed on to the callback
357 * A handle to a Callback Registration Structure (MSDN Documentation)
364 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
365 IN PCALLBACK_FUNCTION CallbackFunction
,
366 IN PVOID CallbackContext
369 PCALLBACK_OBJECT CallbackObject
= (PCALLBACK_OBJECT
)OpaqueCallbackObject
;
370 PCALLBACK_REGISTRATION CallbackRegistration
= NULL
;
375 /* Create reference to Callback Object */
376 ObReferenceObject (CallbackObject
);
378 /* Allocate memory for the structure */
379 CallbackRegistration
= ExAllocatePoolWithTag(
381 sizeof(CallbackRegistration
),
384 /* Fail if memory allocation failed */
385 if(!CallbackRegistration
)
387 ObDereferenceObject (CallbackObject
);
391 /* Create Callback Registration */
392 CallbackRegistration
->CallbackObject
= CallbackObject
; /* When unregistering, drivers send a handle to the Registration, not the object... */
393 CallbackRegistration
->CallbackFunction
= CallbackFunction
; /* NotifyCallback uses Objects, so this needs to be here in order to call the registered functions */
394 CallbackRegistration
->CallbackContext
= CallbackContext
; /* The documented NotifyCallback returns the Context, so we must save this somewhere */
396 /* Acquire SpinLock */
397 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
399 /* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
400 if(CallbackObject
->AllowMultipleCallbacks
|| IsListEmpty(&CallbackObject
->RegisteredCallbacks
))
402 InsertTailList(&CallbackObject
->RegisteredCallbacks
,&CallbackRegistration
->RegisteredCallbacks
);
406 ExFreePool(CallbackRegistration
);
407 CallbackRegistration
= NULL
;
410 /* Release SpinLock */
411 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
413 /* Return handle to Registration Object */
414 return (PVOID
) CallbackRegistration
;
418 * ExUnregisterCallback
421 * Deregisters a CallBack
424 * CallbackRegistration = Callback Registration Handle
432 ExUnregisterCallback(
433 IN PVOID CallbackRegistrationHandle
436 PCALLBACK_REGISTRATION CallbackRegistration
;
437 PCALLBACK_OBJECT CallbackObject
;
442 /* Convert Handle to valid Structure Pointer */
443 CallbackRegistration
= (PCALLBACK_REGISTRATION
) CallbackRegistrationHandle
;
445 /* Get the Callback Object */
446 CallbackObject
= CallbackRegistration
->CallbackObject
;
448 /* Lock the Object */
449 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
451 /* We can't Delete the Callback if it's in use, because this would create a call towards a null pointer => crash */
452 while (CallbackRegistration
->InUse
)
455 /* Similarly, we also don't want to wait ages for all pending callbacks to be called */
456 CallbackRegistration
->PendingDeletion
= TRUE
;
458 /* We are going to wait for the event, so the Lock isn't necessary */
459 KfReleaseSpinLock (&CallbackObject
->Lock
, OldIrql
);
461 /* Make sure the event is cleared */
462 KeClearEvent (&ExpCallbackEvent
);
464 /* Wait for the Event */
465 KeWaitForSingleObject (
473 /* We need the Lock again */
474 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
477 /* Remove the Callback */
478 RemoveEntryList(&CallbackRegistration
->RegisteredCallbacks
);
480 /* It's now safe to release the lock */
481 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
483 /* Delete this registration */
484 ExFreePool(CallbackRegistration
);
486 /* Remove the reference */
487 ObDereferenceObject(CallbackObject
);