3 * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 /* $Id: callback.c,v 1.11 2004/06/19 08:48:00 navaraf Exp $
21 * PROJECT: ReactOS kernel
22 * FILE: ntoskrnl/ex/callback.c
23 * PURPOSE: Executive callbacks
24 * PROGRAMMER: David Welch (welch@mcmail.com)
25 * Alex Ionescu (alex@relsoft.net)
26 * PORTABILITY: Checked.
28 * Added all functions 30/05/04
31 * These funtions are not implemented in NT4, but
32 * they are implemented in Win2k.
35 /* INCLUDES *****************************************************************/
37 #include <ddk/ntddk.h>
38 #include <rosrtl/string.h>
39 #include <internal/debug.h>
40 #include <internal/ob.h>
41 #include <internal/callbacks.h>
43 /* FUNCTIONS *****************************************************************/
46 * ExpInitializeCallbacks
49 * Creates the Callback Object as a valid Object Type in the Kernel.
55 * TRUE if the Callback Object Type was successfully created.
58 ExpInitializeCallbacks(VOID
)
60 OBJECT_ATTRIBUTES ObjectAttributes
;
62 UNICODE_STRING DirName
;
63 UNICODE_STRING CallbackName
;
64 HANDLE DirectoryHandle
;
67 /* Allocate memory for Object */
68 ExCallbackObjectType
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(OBJECT_TYPE
), CALLBACK_TAG
);
71 RtlRosInitUnicodeStringFromLiteral(&ExCallbackObjectType
->TypeName
,L
"Callback");
73 /* Create the Object Type */
74 ExCallbackObjectType
->Tag
= CALLBACK_TAG
;
75 ExCallbackObjectType
->TotalObjects
= 0;
76 ExCallbackObjectType
->TotalHandles
= 0;
77 ExCallbackObjectType
->MaxObjects
= 0xFFFFFFFF;
78 ExCallbackObjectType
->MaxHandles
= 0xFFFFFFFF;
79 ExCallbackObjectType
->PagedPoolCharge
= 0;
80 ExCallbackObjectType
->Dump
= NULL
;
81 ExCallbackObjectType
->Open
= NULL
;
82 ExCallbackObjectType
->Close
= NULL
;
83 ExCallbackObjectType
->Delete
= NULL
;
84 ExCallbackObjectType
->Parse
= NULL
;
85 ExCallbackObjectType
->Security
= NULL
;
86 ExCallbackObjectType
->QueryName
= NULL
;
87 ExCallbackObjectType
->DuplicationNotify
= NULL
;
88 ExCallbackObjectType
->OkayToClose
= NULL
;
89 ExCallbackObjectType
->Create
= NULL
;
90 ExCallbackObjectType
->Mapping
= &ExpCallbackMapping
;
91 ExCallbackObjectType
->NonpagedPoolCharge
= sizeof(_INT_CALLBACK_OBJECT
);
92 Status
= ObpCreateTypeObject(ExCallbackObjectType
);
94 /* Fail if it wasn't created successfully */
95 if (!NT_SUCCESS(Status
))
100 /* Initialize the Object */
101 RtlRosInitUnicodeStringFromLiteral(&DirName
, L
"\\Callback" );
102 InitializeObjectAttributes(
105 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
110 /* Create the Object Directory */
111 Status
= NtCreateDirectoryObject(
113 DIRECTORY_ALL_ACCESS
,
117 /* Fail if couldn't create */
118 if (!NT_SUCCESS(Status
))
123 /* Close Handle... */
124 NtClose(DirectoryHandle
);
126 /* Initialize Event used when unregistering */
127 KeInitializeEvent(&ExpCallbackEvent
, NotificationEvent
, 0);
129 /* Default NT Kernel Callbacks. */
130 for (i
=0; ExpInitializeCallback
[i
].CallbackObject
; i
++)
132 /* Create the name from the structure */
133 RtlInitUnicodeString(&CallbackName
, ExpInitializeCallback
[i
].Name
);
135 /* Initialize the Object Attributes Structure */
136 InitializeObjectAttributes(
139 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
144 /* Create the Callback Object */
145 Status
= ExCreateCallback(
146 (PCALLBACK_OBJECT
*)&(ExpInitializeCallback
[i
].CallbackObject
),
152 /* Make sure Global Callbacks have been created */
153 if (!NT_SUCCESS(Status
))
158 /* Everything successful */
166 * Opens or creates a Callback Object. Creates only if Create is true.
167 * Allows multiple Callback Functions to be registred only if AllowMultipleCallbacks
171 * CallbackObject = Pointer that will receive the Callback Object.
172 * CallbackName = Name of Callback
173 * Create = Determines if the object will be created if it doesn't exit
174 * AllowMultipleCallbacks = Determines if more then one registered callback function
175 * can be attached to this Callback Object.
178 * STATUS_SUCESS if not failed.
185 OUT PCALLBACK_OBJECT
*CallbackObject
,
186 IN POBJECT_ATTRIBUTES ObjectAttributes
,
188 IN BOOLEAN AllowMultipleCallbacks
191 PINT_CALLBACK_OBJECT Callback
;
195 /* Open a handle to the callback if it exists */
196 if (ObjectAttributes
->ObjectName
)
198 Status
= ObOpenObjectByName(ObjectAttributes
,
199 ExCallbackObjectType
,
208 Status
= STATUS_UNSUCCESSFUL
;
211 /* We weren't able to open it...should we create it? */
212 if(!NT_SUCCESS(Status
) && Create
)
214 Status
= ObCreateObject(KernelMode
,
215 ExCallbackObjectType
,
219 sizeof(_INT_CALLBACK_OBJECT
),
222 (PVOID
*)&Callback
);
224 /* We Created it...let's initialize the structure now */
225 if(NT_SUCCESS(Status
))
227 KeInitializeSpinLock (&Callback
->Lock
); /* SpinLock */
228 InitializeListHead(&Callback
->RegisteredCallbacks
); /* Callback Entries */
229 Callback
->AllowMultipleCallbacks
= AllowMultipleCallbacks
; /* Multiple Callbacks */
230 Status
= ObInsertObject ( /* Create the object */
239 if(NT_SUCCESS(Status
))
242 /* Get a pointer to the new object from the handle we just got */
243 Status
= ObReferenceObjectByHandle (
246 ExCallbackObjectType
,
251 /* Close the Handle, since we now have the pointer */
255 /* Everything went fine, so return a pointer to the Object */
256 if (NT_SUCCESS(Status
))
258 *CallbackObject
= (PCALLBACK_OBJECT
)Callback
;
267 * Calls a function pointer (a registered callback)
270 * CallbackObject - Which callback to call
271 * Argument1 - Pointer/data to send to callback function
272 * Argument2 - Pointer/data to send to callback function
282 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
287 PINT_CALLBACK_OBJECT CallbackObject
= (PINT_CALLBACK_OBJECT
)OpaqueCallbackObject
;
288 PLIST_ENTRY RegisteredCallbacks
;
289 PCALLBACK_REGISTRATION CallbackRegistration
;
292 /* Acquire the Lock */
293 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
295 /* Enumerate through all the registered functions */
296 for (RegisteredCallbacks
= CallbackObject
->RegisteredCallbacks
.Flink
;
297 RegisteredCallbacks
!= &CallbackObject
->RegisteredCallbacks
;
298 RegisteredCallbacks
= RegisteredCallbacks
->Flink
)
301 /* Get a pointer to a Callback Registration from the List Entries */
302 CallbackRegistration
= CONTAINING_RECORD ( RegisteredCallbacks
,
303 CALLBACK_REGISTRATION
,
304 RegisteredCallbacks
);
306 /* Don't bother doing Callback Notification if it's pending to be deleted */
307 if (!CallbackRegistration
->PendingDeletion
)
310 /* Mark the Callback in use, so it won't get deleted while we are calling it */
311 CallbackRegistration
->InUse
+= 1;
313 /* Release the Spinlock before making the call */
314 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
316 /* Call the Registered Function */
317 CallbackRegistration
->CallbackFunction (
318 CallbackRegistration
->CallbackContext
,
323 /* Get SpinLock back */
324 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
326 /* We are not in use anymore */
327 CallbackRegistration
->InUse
-= 1;
329 /* If another instance of this function isn't running and deletion is pending, signal the event */
330 if (CallbackRegistration
->PendingDeletion
&& CallbackRegistration
->InUse
== 0)
332 KeSetEvent(&ExpCallbackEvent
, 0, FALSE
);
336 /* Unsynchronize and release the Callback Object */
337 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
344 * Allows a function to associate a callback pointer (Function)
345 * to a created Callback object
348 * CallbackObject = The Object Created with ExCreateCallBack
349 * CallBackFunction = Pointer to the function to be called back
350 * CallBackContext = Block of memory that can contain user-data
351 * which will be passed on to the callback
354 * A handle to a Callback Registration Structure (MSDN Documentation)
361 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
362 IN PCALLBACK_FUNCTION CallbackFunction
,
363 IN PVOID CallbackContext
366 PINT_CALLBACK_OBJECT CallbackObject
= (PINT_CALLBACK_OBJECT
)OpaqueCallbackObject
;
367 PCALLBACK_REGISTRATION CallbackRegistration
= NULL
;
370 /* Create reference to Callback Object */
371 ObReferenceObject (CallbackObject
);
373 /* Allocate memory for the structure */
374 CallbackRegistration
= ExAllocatePoolWithTag(
376 sizeof(CallbackRegistration
),
379 /* Fail if memory allocation failed */
380 if(!CallbackRegistration
)
382 ObDereferenceObject (CallbackObject
);
386 /* Create Callback Registration */
387 CallbackRegistration
->CallbackObject
= CallbackObject
; /* When unregistering, drivers send a handle to the Registration, not the object... */
388 CallbackRegistration
->CallbackFunction
= CallbackFunction
; /* NotifyCallback uses Objects, so this needs to be here in order to call the registered functions */
389 CallbackRegistration
->CallbackContext
= CallbackContext
; /* The documented NotifyCallback returns the Context, so we must save this somewhere */
391 /* Acquire SpinLock */
392 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
394 /* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
395 if(CallbackObject
->AllowMultipleCallbacks
|| IsListEmpty(&CallbackObject
->RegisteredCallbacks
))
397 InsertTailList(&CallbackObject
->RegisteredCallbacks
,&CallbackRegistration
->RegisteredCallbacks
)
401 ExFreePool(CallbackRegistration
);
402 CallbackRegistration
= NULL
;
405 /* Release SpinLock */
406 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
408 /* Return handle to Registration Object */
409 return (PVOID
) CallbackRegistration
;
413 * ExUnregisterCallback
416 * Deregisters a CallBack
419 * CallbackRegistration = Callback Registration Handle
427 ExUnregisterCallback(
428 IN PVOID CallbackRegistrationHandle
431 PCALLBACK_REGISTRATION CallbackRegistration
;
432 PINT_CALLBACK_OBJECT CallbackObject
;
435 /* Convert Handle to valid Structure Pointer */
436 CallbackRegistration
= (PCALLBACK_REGISTRATION
) CallbackRegistrationHandle
;
438 /* Get the Callback Object */
439 CallbackObject
= CallbackRegistration
->CallbackObject
;
441 /* Lock the Object */
442 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
444 /* We can't Delete the Callback if it's in use, because this would create a call towards a null pointer => crash */
445 while (CallbackRegistration
->InUse
)
448 /* Similarly, we also don't want to wait ages for all pending callbacks to be called */
449 CallbackRegistration
->PendingDeletion
= TRUE
;
451 /* We are going to wait for the event, so the Lock isn't necessary */
452 KfReleaseSpinLock (&CallbackObject
->Lock
, OldIrql
);
454 /* Make sure the event is cleared */
455 KeClearEvent (&ExpCallbackEvent
);
457 /* Wait for the Event */
458 KeWaitForSingleObject (
466 /* We need the Lock again */
467 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
470 /* Remove the Callback */
471 RemoveEntryList(&CallbackRegistration
->RegisteredCallbacks
);
473 /* It's now safe to release the lock */
474 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
476 /* Delete this registration */
477 ExFreePool(CallbackRegistration
);
479 /* Remove the reference */
480 ObDereferenceObject(CallbackObject
);