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
;
45 HANDLE DirectoryHandle
;
48 /* Allocate memory for Object */
49 ExCallbackObjectType
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(OBJECT_TYPE
), CALLBACK_TAG
);
52 RtlRosInitUnicodeStringFromLiteral(&ExCallbackObjectType
->TypeName
,L
"Callback");
54 /* Create the Object Type */
55 ExCallbackObjectType
->Tag
= CALLBACK_TAG
;
56 ExCallbackObjectType
->TotalObjects
= 0;
57 ExCallbackObjectType
->TotalHandles
= 0;
58 ExCallbackObjectType
->PeakObjects
= 0;
59 ExCallbackObjectType
->PeakHandles
= 0;
60 ExCallbackObjectType
->PagedPoolCharge
= 0;
61 ExCallbackObjectType
->Dump
= NULL
;
62 ExCallbackObjectType
->Open
= NULL
;
63 ExCallbackObjectType
->Close
= NULL
;
64 ExCallbackObjectType
->Delete
= NULL
;
65 ExCallbackObjectType
->Parse
= NULL
;
66 ExCallbackObjectType
->Security
= NULL
;
67 ExCallbackObjectType
->QueryName
= NULL
;
68 ExCallbackObjectType
->DuplicationNotify
= NULL
;
69 ExCallbackObjectType
->OkayToClose
= NULL
;
70 ExCallbackObjectType
->Create
= NULL
;
71 ExCallbackObjectType
->Mapping
= &ExpCallbackMapping
;
72 ExCallbackObjectType
->NonpagedPoolCharge
= sizeof(_INT_CALLBACK_OBJECT
);
73 Status
= ObpCreateTypeObject(ExCallbackObjectType
);
75 /* Fail if it wasn't created successfully */
76 if (!NT_SUCCESS(Status
))
81 /* Initialize the Object */
82 RtlRosInitUnicodeStringFromLiteral(&DirName
, L
"\\Callback" );
83 InitializeObjectAttributes(
86 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
91 /* Create the Object Directory */
92 Status
= NtCreateDirectoryObject(
98 /* Fail if couldn't create */
99 if (!NT_SUCCESS(Status
))
104 /* Close Handle... */
105 NtClose(DirectoryHandle
);
107 /* Initialize Event used when unregistering */
108 KeInitializeEvent(&ExpCallbackEvent
, NotificationEvent
, 0);
110 /* Default NT Kernel Callbacks. */
111 for (i
=0; ExpInitializeCallback
[i
].CallbackObject
; i
++)
113 /* Create the name from the structure */
114 RtlInitUnicodeString(&CallbackName
, ExpInitializeCallback
[i
].Name
);
116 /* Initialize the Object Attributes Structure */
117 InitializeObjectAttributes(
120 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
125 /* Create the Callback Object */
126 Status
= ExCreateCallback(
127 (PCALLBACK_OBJECT
*)&(ExpInitializeCallback
[i
].CallbackObject
),
133 /* Make sure Global Callbacks have been created */
134 if (!NT_SUCCESS(Status
))
139 /* Everything successful */
146 * Opens or creates a Callback Object. Creates only if Create is true.
147 * Allows multiple Callback Functions to be registred only if AllowMultipleCallbacks
151 * CallbackObject = Pointer that will receive the Callback Object.
152 * CallbackName = Name of Callback
153 * Create = Determines if the object will be created if it doesn't exit
154 * AllowMultipleCallbacks = Determines if more then one registered callback function
155 * can be attached to this Callback Object.
158 * STATUS_SUCESS if not failed.
165 OUT PCALLBACK_OBJECT
*CallbackObject
,
166 IN POBJECT_ATTRIBUTES ObjectAttributes
,
168 IN BOOLEAN AllowMultipleCallbacks
171 PINT_CALLBACK_OBJECT Callback
;
175 /* Open a handle to the callback if it exists */
176 if (ObjectAttributes
->ObjectName
)
178 Status
= ObOpenObjectByName(ObjectAttributes
,
179 ExCallbackObjectType
,
188 Status
= STATUS_UNSUCCESSFUL
;
191 /* We weren't able to open it...should we create it? */
192 if(!NT_SUCCESS(Status
) && Create
)
194 Status
= ObCreateObject(KernelMode
,
195 ExCallbackObjectType
,
199 sizeof(_INT_CALLBACK_OBJECT
),
202 (PVOID
*)&Callback
);
204 /* We Created it...let's initialize the structure now */
205 if(NT_SUCCESS(Status
))
207 KeInitializeSpinLock (&Callback
->Lock
); /* SpinLock */
208 InitializeListHead(&Callback
->RegisteredCallbacks
); /* Callback Entries */
209 Callback
->AllowMultipleCallbacks
= AllowMultipleCallbacks
; /* Multiple Callbacks */
210 Status
= ObInsertObject ( /* Create the object */
219 if(NT_SUCCESS(Status
))
222 /* Get a pointer to the new object from the handle we just got */
223 Status
= ObReferenceObjectByHandle (
226 ExCallbackObjectType
,
231 /* Close the Handle, since we now have the pointer */
235 /* Everything went fine, so return a pointer to the Object */
236 if (NT_SUCCESS(Status
))
238 *CallbackObject
= (PCALLBACK_OBJECT
)Callback
;
247 * Calls a function pointer (a registered callback)
250 * CallbackObject - Which callback to call
251 * Argument1 - Pointer/data to send to callback function
252 * Argument2 - Pointer/data to send to callback function
262 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
267 PINT_CALLBACK_OBJECT CallbackObject
= (PINT_CALLBACK_OBJECT
)OpaqueCallbackObject
;
268 PLIST_ENTRY RegisteredCallbacks
;
269 PCALLBACK_REGISTRATION CallbackRegistration
;
272 /* Acquire the Lock */
273 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
275 /* Enumerate through all the registered functions */
276 for (RegisteredCallbacks
= CallbackObject
->RegisteredCallbacks
.Flink
;
277 RegisteredCallbacks
!= &CallbackObject
->RegisteredCallbacks
;
278 RegisteredCallbacks
= RegisteredCallbacks
->Flink
)
281 /* Get a pointer to a Callback Registration from the List Entries */
282 CallbackRegistration
= CONTAINING_RECORD ( RegisteredCallbacks
,
283 CALLBACK_REGISTRATION
,
284 RegisteredCallbacks
);
286 /* Don't bother doing Callback Notification if it's pending to be deleted */
287 if (!CallbackRegistration
->PendingDeletion
)
290 /* Mark the Callback in use, so it won't get deleted while we are calling it */
291 CallbackRegistration
->InUse
+= 1;
293 /* Release the Spinlock before making the call */
294 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
296 /* Call the Registered Function */
297 CallbackRegistration
->CallbackFunction (
298 CallbackRegistration
->CallbackContext
,
303 /* Get SpinLock back */
304 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
306 /* We are not in use anymore */
307 CallbackRegistration
->InUse
-= 1;
309 /* If another instance of this function isn't running and deletion is pending, signal the event */
310 if (CallbackRegistration
->PendingDeletion
&& CallbackRegistration
->InUse
== 0)
312 KeSetEvent(&ExpCallbackEvent
, 0, FALSE
);
316 /* Unsynchronize and release the Callback Object */
317 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
324 * Allows a function to associate a callback pointer (Function)
325 * to a created Callback object
328 * CallbackObject = The Object Created with ExCreateCallBack
329 * CallBackFunction = Pointer to the function to be called back
330 * CallBackContext = Block of memory that can contain user-data
331 * which will be passed on to the callback
334 * A handle to a Callback Registration Structure (MSDN Documentation)
341 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
342 IN PCALLBACK_FUNCTION CallbackFunction
,
343 IN PVOID CallbackContext
346 PINT_CALLBACK_OBJECT CallbackObject
= (PINT_CALLBACK_OBJECT
)OpaqueCallbackObject
;
347 PCALLBACK_REGISTRATION CallbackRegistration
= NULL
;
350 /* Create reference to Callback Object */
351 ObReferenceObject (CallbackObject
);
353 /* Allocate memory for the structure */
354 CallbackRegistration
= ExAllocatePoolWithTag(
356 sizeof(CallbackRegistration
),
359 /* Fail if memory allocation failed */
360 if(!CallbackRegistration
)
362 ObDereferenceObject (CallbackObject
);
366 /* Create Callback Registration */
367 CallbackRegistration
->CallbackObject
= CallbackObject
; /* When unregistering, drivers send a handle to the Registration, not the object... */
368 CallbackRegistration
->CallbackFunction
= CallbackFunction
; /* NotifyCallback uses Objects, so this needs to be here in order to call the registered functions */
369 CallbackRegistration
->CallbackContext
= CallbackContext
; /* The documented NotifyCallback returns the Context, so we must save this somewhere */
371 /* Acquire SpinLock */
372 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
374 /* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
375 if(CallbackObject
->AllowMultipleCallbacks
|| IsListEmpty(&CallbackObject
->RegisteredCallbacks
))
377 InsertTailList(&CallbackObject
->RegisteredCallbacks
,&CallbackRegistration
->RegisteredCallbacks
);
381 ExFreePool(CallbackRegistration
);
382 CallbackRegistration
= NULL
;
385 /* Release SpinLock */
386 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
388 /* Return handle to Registration Object */
389 return (PVOID
) CallbackRegistration
;
393 * ExUnregisterCallback
396 * Deregisters a CallBack
399 * CallbackRegistration = Callback Registration Handle
407 ExUnregisterCallback(
408 IN PVOID CallbackRegistrationHandle
411 PCALLBACK_REGISTRATION CallbackRegistration
;
412 PINT_CALLBACK_OBJECT CallbackObject
;
415 /* Convert Handle to valid Structure Pointer */
416 CallbackRegistration
= (PCALLBACK_REGISTRATION
) CallbackRegistrationHandle
;
418 /* Get the Callback Object */
419 CallbackObject
= CallbackRegistration
->CallbackObject
;
421 /* Lock the Object */
422 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
424 /* We can't Delete the Callback if it's in use, because this would create a call towards a null pointer => crash */
425 while (CallbackRegistration
->InUse
)
428 /* Similarly, we also don't want to wait ages for all pending callbacks to be called */
429 CallbackRegistration
->PendingDeletion
= TRUE
;
431 /* We are going to wait for the event, so the Lock isn't necessary */
432 KfReleaseSpinLock (&CallbackObject
->Lock
, OldIrql
);
434 /* Make sure the event is cleared */
435 KeClearEvent (&ExpCallbackEvent
);
437 /* Wait for the Event */
438 KeWaitForSingleObject (
446 /* We need the Lock again */
447 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
450 /* Remove the Callback */
451 RemoveEntryList(&CallbackRegistration
->RegisteredCallbacks
);
453 /* It's now safe to release the lock */
454 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
456 /* Delete this registration */
457 ExFreePool(CallbackRegistration
);
459 /* Remove the reference */
460 ObDereferenceObject(CallbackObject
);