3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ex/callback.c
6 * PURPOSE: Executive callbacks
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 * Alex Ionescu (alex@relsoft.net)
14 * NOTE: These funtions are not implemented in NT4, but
15 * they are implemented in Win2k.
18 /* INCLUDES *****************************************************************/
21 #include <internal/callbacks.h>
22 #include <internal/debug.h>
24 /* FUNCTIONS *****************************************************************/
27 * ExpInitializeCallbacks
30 * Creates the Callback Object as a valid Object Type in the Kernel.
36 * TRUE if the Callback Object Type was successfully created.
39 ExpInitializeCallbacks(VOID
)
41 OBJECT_ATTRIBUTES ObjectAttributes
;
43 UNICODE_STRING DirName
;
44 UNICODE_STRING CallbackName
;
46 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
47 HANDLE DirectoryHandle
;
50 /* Initialize the Callback Object type */
51 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
52 RtlInitUnicodeString(&Name
, L
"Callback");
53 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
54 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(_INT_CALLBACK_OBJECT
);
55 ObjectTypeInitializer
.GenericMapping
= ExpCallbackMapping
;
56 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
57 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
59 Status
= ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &ExCallbackObjectType
);
61 /* Fail if it wasn't created successfully */
62 if (!NT_SUCCESS(Status
))
67 /* Initialize the Object */
68 RtlRosInitUnicodeStringFromLiteral(&DirName
, L
"\\Callback" );
69 InitializeObjectAttributes(
72 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
77 /* Create the Object Directory */
78 Status
= NtCreateDirectoryObject(
84 /* Fail if couldn't create */
85 if (!NT_SUCCESS(Status
))
91 NtClose(DirectoryHandle
);
93 /* Initialize Event used when unregistering */
94 KeInitializeEvent(&ExpCallbackEvent
, NotificationEvent
, 0);
96 /* Default NT Kernel Callbacks. */
97 for (i
=0; ExpInitializeCallback
[i
].CallbackObject
; i
++)
99 /* Create the name from the structure */
100 RtlInitUnicodeString(&CallbackName
, ExpInitializeCallback
[i
].Name
);
102 /* Initialize the Object Attributes Structure */
103 InitializeObjectAttributes(
106 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
111 /* Create the Callback Object */
112 Status
= ExCreateCallback(
113 (PCALLBACK_OBJECT
*)&(ExpInitializeCallback
[i
].CallbackObject
),
119 /* Make sure Global Callbacks have been created */
120 if (!NT_SUCCESS(Status
))
125 /* Everything successful */
132 * Opens or creates a Callback Object. Creates only if Create is true.
133 * Allows multiple Callback Functions to be registred only if AllowMultipleCallbacks
137 * CallbackObject = Pointer that will receive the Callback Object.
138 * CallbackName = Name of Callback
139 * Create = Determines if the object will be created if it doesn't exit
140 * AllowMultipleCallbacks = Determines if more then one registered callback function
141 * can be attached to this Callback Object.
144 * STATUS_SUCESS if not failed.
151 OUT PCALLBACK_OBJECT
*CallbackObject
,
152 IN POBJECT_ATTRIBUTES ObjectAttributes
,
154 IN BOOLEAN AllowMultipleCallbacks
157 PINT_CALLBACK_OBJECT Callback
;
163 /* Open a handle to the callback if it exists */
164 if (ObjectAttributes
->ObjectName
)
166 Status
= ObOpenObjectByName(ObjectAttributes
,
167 ExCallbackObjectType
,
176 Status
= STATUS_UNSUCCESSFUL
;
179 /* We weren't able to open it...should we create it? */
180 if(!NT_SUCCESS(Status
) && Create
)
182 Status
= ObCreateObject(KernelMode
,
183 ExCallbackObjectType
,
187 sizeof(_INT_CALLBACK_OBJECT
),
190 (PVOID
*)&Callback
);
192 /* We Created it...let's initialize the structure now */
193 if(NT_SUCCESS(Status
))
195 KeInitializeSpinLock (&Callback
->Lock
); /* SpinLock */
196 InitializeListHead(&Callback
->RegisteredCallbacks
); /* Callback Entries */
197 Callback
->AllowMultipleCallbacks
= AllowMultipleCallbacks
; /* Multiple Callbacks */
198 Status
= ObInsertObject ( /* Create the object */
207 if(NT_SUCCESS(Status
))
210 /* Get a pointer to the new object from the handle we just got */
211 Status
= ObReferenceObjectByHandle (
214 ExCallbackObjectType
,
219 /* Close the Handle, since we now have the pointer */
223 /* Everything went fine, so return a pointer to the Object */
224 if (NT_SUCCESS(Status
))
226 *CallbackObject
= (PCALLBACK_OBJECT
)Callback
;
235 * Calls a function pointer (a registered callback)
238 * CallbackObject - Which callback to call
239 * Argument1 - Pointer/data to send to callback function
240 * Argument2 - Pointer/data to send to callback function
250 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
255 PINT_CALLBACK_OBJECT CallbackObject
= (PINT_CALLBACK_OBJECT
)OpaqueCallbackObject
;
256 PLIST_ENTRY RegisteredCallbacks
;
257 PCALLBACK_REGISTRATION CallbackRegistration
;
260 /* Acquire the Lock */
261 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
263 /* Enumerate through all the registered functions */
264 for (RegisteredCallbacks
= CallbackObject
->RegisteredCallbacks
.Flink
;
265 RegisteredCallbacks
!= &CallbackObject
->RegisteredCallbacks
;
266 RegisteredCallbacks
= RegisteredCallbacks
->Flink
)
269 /* Get a pointer to a Callback Registration from the List Entries */
270 CallbackRegistration
= CONTAINING_RECORD ( RegisteredCallbacks
,
271 CALLBACK_REGISTRATION
,
272 RegisteredCallbacks
);
274 /* Don't bother doing Callback Notification if it's pending to be deleted */
275 if (!CallbackRegistration
->PendingDeletion
)
278 /* Mark the Callback in use, so it won't get deleted while we are calling it */
279 CallbackRegistration
->InUse
+= 1;
281 /* Release the Spinlock before making the call */
282 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
284 /* Call the Registered Function */
285 CallbackRegistration
->CallbackFunction (
286 CallbackRegistration
->CallbackContext
,
291 /* Get SpinLock back */
292 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
294 /* We are not in use anymore */
295 CallbackRegistration
->InUse
-= 1;
297 /* If another instance of this function isn't running and deletion is pending, signal the event */
298 if (CallbackRegistration
->PendingDeletion
&& CallbackRegistration
->InUse
== 0)
300 KeSetEvent(&ExpCallbackEvent
, 0, FALSE
);
304 /* Unsynchronize and release the Callback Object */
305 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
312 * Allows a function to associate a callback pointer (Function)
313 * to a created Callback object
316 * CallbackObject = The Object Created with ExCreateCallBack
317 * CallBackFunction = Pointer to the function to be called back
318 * CallBackContext = Block of memory that can contain user-data
319 * which will be passed on to the callback
322 * A handle to a Callback Registration Structure (MSDN Documentation)
329 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
330 IN PCALLBACK_FUNCTION CallbackFunction
,
331 IN PVOID CallbackContext
334 PINT_CALLBACK_OBJECT CallbackObject
= (PINT_CALLBACK_OBJECT
)OpaqueCallbackObject
;
335 PCALLBACK_REGISTRATION CallbackRegistration
= NULL
;
340 /* Create reference to Callback Object */
341 ObReferenceObject (CallbackObject
);
343 /* Allocate memory for the structure */
344 CallbackRegistration
= ExAllocatePoolWithTag(
346 sizeof(CallbackRegistration
),
349 /* Fail if memory allocation failed */
350 if(!CallbackRegistration
)
352 ObDereferenceObject (CallbackObject
);
356 /* Create Callback Registration */
357 CallbackRegistration
->CallbackObject
= CallbackObject
; /* When unregistering, drivers send a handle to the Registration, not the object... */
358 CallbackRegistration
->CallbackFunction
= CallbackFunction
; /* NotifyCallback uses Objects, so this needs to be here in order to call the registered functions */
359 CallbackRegistration
->CallbackContext
= CallbackContext
; /* The documented NotifyCallback returns the Context, so we must save this somewhere */
361 /* Acquire SpinLock */
362 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
364 /* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
365 if(CallbackObject
->AllowMultipleCallbacks
|| IsListEmpty(&CallbackObject
->RegisteredCallbacks
))
367 InsertTailList(&CallbackObject
->RegisteredCallbacks
,&CallbackRegistration
->RegisteredCallbacks
);
371 ExFreePool(CallbackRegistration
);
372 CallbackRegistration
= NULL
;
375 /* Release SpinLock */
376 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
378 /* Return handle to Registration Object */
379 return (PVOID
) CallbackRegistration
;
383 * ExUnregisterCallback
386 * Deregisters a CallBack
389 * CallbackRegistration = Callback Registration Handle
397 ExUnregisterCallback(
398 IN PVOID CallbackRegistrationHandle
401 PCALLBACK_REGISTRATION CallbackRegistration
;
402 PINT_CALLBACK_OBJECT CallbackObject
;
407 /* Convert Handle to valid Structure Pointer */
408 CallbackRegistration
= (PCALLBACK_REGISTRATION
) CallbackRegistrationHandle
;
410 /* Get the Callback Object */
411 CallbackObject
= CallbackRegistration
->CallbackObject
;
413 /* Lock the Object */
414 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
416 /* We can't Delete the Callback if it's in use, because this would create a call towards a null pointer => crash */
417 while (CallbackRegistration
->InUse
)
420 /* Similarly, we also don't want to wait ages for all pending callbacks to be called */
421 CallbackRegistration
->PendingDeletion
= TRUE
;
423 /* We are going to wait for the event, so the Lock isn't necessary */
424 KfReleaseSpinLock (&CallbackObject
->Lock
, OldIrql
);
426 /* Make sure the event is cleared */
427 KeClearEvent (&ExpCallbackEvent
);
429 /* Wait for the Event */
430 KeWaitForSingleObject (
438 /* We need the Lock again */
439 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
442 /* Remove the Callback */
443 RemoveEntryList(&CallbackRegistration
->RegisteredCallbacks
);
445 /* It's now safe to release the lock */
446 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
448 /* Delete this registration */
449 ExFreePool(CallbackRegistration
);
451 /* Remove the reference */
452 ObDereferenceObject(CallbackObject
);