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.
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 *****************************************************************/
38 #include <internal/callbacks.h>
39 #include <internal/debug.h>
41 /* FUNCTIONS *****************************************************************/
44 * ExpInitializeCallbacks
47 * Creates the Callback Object as a valid Object Type in the Kernel.
53 * TRUE if the Callback Object Type was successfully created.
56 ExpInitializeCallbacks(VOID
)
58 OBJECT_ATTRIBUTES ObjectAttributes
;
60 UNICODE_STRING DirName
;
61 UNICODE_STRING CallbackName
;
62 HANDLE DirectoryHandle
;
65 /* Allocate memory for Object */
66 ExCallbackObjectType
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(OBJECT_TYPE
), CALLBACK_TAG
);
69 RtlRosInitUnicodeStringFromLiteral(&ExCallbackObjectType
->TypeName
,L
"Callback");
71 /* Create the Object Type */
72 ExCallbackObjectType
->Tag
= CALLBACK_TAG
;
73 ExCallbackObjectType
->TotalObjects
= 0;
74 ExCallbackObjectType
->TotalHandles
= 0;
75 ExCallbackObjectType
->PeakObjects
= 0;
76 ExCallbackObjectType
->PeakHandles
= 0;
77 ExCallbackObjectType
->PagedPoolCharge
= 0;
78 ExCallbackObjectType
->Dump
= NULL
;
79 ExCallbackObjectType
->Open
= NULL
;
80 ExCallbackObjectType
->Close
= NULL
;
81 ExCallbackObjectType
->Delete
= NULL
;
82 ExCallbackObjectType
->Parse
= NULL
;
83 ExCallbackObjectType
->Security
= NULL
;
84 ExCallbackObjectType
->QueryName
= NULL
;
85 ExCallbackObjectType
->DuplicationNotify
= NULL
;
86 ExCallbackObjectType
->OkayToClose
= NULL
;
87 ExCallbackObjectType
->Create
= NULL
;
88 ExCallbackObjectType
->Mapping
= &ExpCallbackMapping
;
89 ExCallbackObjectType
->NonpagedPoolCharge
= sizeof(_INT_CALLBACK_OBJECT
);
90 Status
= ObpCreateTypeObject(ExCallbackObjectType
);
92 /* Fail if it wasn't created successfully */
93 if (!NT_SUCCESS(Status
))
98 /* Initialize the Object */
99 RtlRosInitUnicodeStringFromLiteral(&DirName
, L
"\\Callback" );
100 InitializeObjectAttributes(
103 OBJ_CASE_INSENSITIVE
| OBJ_PERMANENT
,
108 /* Create the Object Directory */
109 Status
= NtCreateDirectoryObject(
111 DIRECTORY_ALL_ACCESS
,
115 /* Fail if couldn't create */
116 if (!NT_SUCCESS(Status
))
121 /* Close Handle... */
122 NtClose(DirectoryHandle
);
124 /* Initialize Event used when unregistering */
125 KeInitializeEvent(&ExpCallbackEvent
, NotificationEvent
, 0);
127 /* Default NT Kernel Callbacks. */
128 for (i
=0; ExpInitializeCallback
[i
].CallbackObject
; i
++)
130 /* Create the name from the structure */
131 RtlInitUnicodeString(&CallbackName
, ExpInitializeCallback
[i
].Name
);
133 /* Initialize the Object Attributes Structure */
134 InitializeObjectAttributes(
137 OBJ_PERMANENT
| OBJ_CASE_INSENSITIVE
,
142 /* Create the Callback Object */
143 Status
= ExCreateCallback(
144 (PCALLBACK_OBJECT
*)&(ExpInitializeCallback
[i
].CallbackObject
),
150 /* Make sure Global Callbacks have been created */
151 if (!NT_SUCCESS(Status
))
156 /* Everything successful */
163 * Opens or creates a Callback Object. Creates only if Create is true.
164 * Allows multiple Callback Functions to be registred only if AllowMultipleCallbacks
168 * CallbackObject = Pointer that will receive the Callback Object.
169 * CallbackName = Name of Callback
170 * Create = Determines if the object will be created if it doesn't exit
171 * AllowMultipleCallbacks = Determines if more then one registered callback function
172 * can be attached to this Callback Object.
175 * STATUS_SUCESS if not failed.
182 OUT PCALLBACK_OBJECT
*CallbackObject
,
183 IN POBJECT_ATTRIBUTES ObjectAttributes
,
185 IN BOOLEAN AllowMultipleCallbacks
188 PINT_CALLBACK_OBJECT Callback
;
192 /* Open a handle to the callback if it exists */
193 if (ObjectAttributes
->ObjectName
)
195 Status
= ObOpenObjectByName(ObjectAttributes
,
196 ExCallbackObjectType
,
205 Status
= STATUS_UNSUCCESSFUL
;
208 /* We weren't able to open it...should we create it? */
209 if(!NT_SUCCESS(Status
) && Create
)
211 Status
= ObCreateObject(KernelMode
,
212 ExCallbackObjectType
,
216 sizeof(_INT_CALLBACK_OBJECT
),
219 (PVOID
*)&Callback
);
221 /* We Created it...let's initialize the structure now */
222 if(NT_SUCCESS(Status
))
224 KeInitializeSpinLock (&Callback
->Lock
); /* SpinLock */
225 InitializeListHead(&Callback
->RegisteredCallbacks
); /* Callback Entries */
226 Callback
->AllowMultipleCallbacks
= AllowMultipleCallbacks
; /* Multiple Callbacks */
227 Status
= ObInsertObject ( /* Create the object */
236 if(NT_SUCCESS(Status
))
239 /* Get a pointer to the new object from the handle we just got */
240 Status
= ObReferenceObjectByHandle (
243 ExCallbackObjectType
,
248 /* Close the Handle, since we now have the pointer */
252 /* Everything went fine, so return a pointer to the Object */
253 if (NT_SUCCESS(Status
))
255 *CallbackObject
= (PCALLBACK_OBJECT
)Callback
;
264 * Calls a function pointer (a registered callback)
267 * CallbackObject - Which callback to call
268 * Argument1 - Pointer/data to send to callback function
269 * Argument2 - Pointer/data to send to callback function
279 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
284 PINT_CALLBACK_OBJECT CallbackObject
= (PINT_CALLBACK_OBJECT
)OpaqueCallbackObject
;
285 PLIST_ENTRY RegisteredCallbacks
;
286 PCALLBACK_REGISTRATION CallbackRegistration
;
289 /* Acquire the Lock */
290 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
292 /* Enumerate through all the registered functions */
293 for (RegisteredCallbacks
= CallbackObject
->RegisteredCallbacks
.Flink
;
294 RegisteredCallbacks
!= &CallbackObject
->RegisteredCallbacks
;
295 RegisteredCallbacks
= RegisteredCallbacks
->Flink
)
298 /* Get a pointer to a Callback Registration from the List Entries */
299 CallbackRegistration
= CONTAINING_RECORD ( RegisteredCallbacks
,
300 CALLBACK_REGISTRATION
,
301 RegisteredCallbacks
);
303 /* Don't bother doing Callback Notification if it's pending to be deleted */
304 if (!CallbackRegistration
->PendingDeletion
)
307 /* Mark the Callback in use, so it won't get deleted while we are calling it */
308 CallbackRegistration
->InUse
+= 1;
310 /* Release the Spinlock before making the call */
311 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
313 /* Call the Registered Function */
314 CallbackRegistration
->CallbackFunction (
315 CallbackRegistration
->CallbackContext
,
320 /* Get SpinLock back */
321 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
323 /* We are not in use anymore */
324 CallbackRegistration
->InUse
-= 1;
326 /* If another instance of this function isn't running and deletion is pending, signal the event */
327 if (CallbackRegistration
->PendingDeletion
&& CallbackRegistration
->InUse
== 0)
329 KeSetEvent(&ExpCallbackEvent
, 0, FALSE
);
333 /* Unsynchronize and release the Callback Object */
334 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
341 * Allows a function to associate a callback pointer (Function)
342 * to a created Callback object
345 * CallbackObject = The Object Created with ExCreateCallBack
346 * CallBackFunction = Pointer to the function to be called back
347 * CallBackContext = Block of memory that can contain user-data
348 * which will be passed on to the callback
351 * A handle to a Callback Registration Structure (MSDN Documentation)
358 IN PCALLBACK_OBJECT OpaqueCallbackObject
,
359 IN PCALLBACK_FUNCTION CallbackFunction
,
360 IN PVOID CallbackContext
363 PINT_CALLBACK_OBJECT CallbackObject
= (PINT_CALLBACK_OBJECT
)OpaqueCallbackObject
;
364 PCALLBACK_REGISTRATION CallbackRegistration
= NULL
;
367 /* Create reference to Callback Object */
368 ObReferenceObject (CallbackObject
);
370 /* Allocate memory for the structure */
371 CallbackRegistration
= ExAllocatePoolWithTag(
373 sizeof(CallbackRegistration
),
376 /* Fail if memory allocation failed */
377 if(!CallbackRegistration
)
379 ObDereferenceObject (CallbackObject
);
383 /* Create Callback Registration */
384 CallbackRegistration
->CallbackObject
= CallbackObject
; /* When unregistering, drivers send a handle to the Registration, not the object... */
385 CallbackRegistration
->CallbackFunction
= CallbackFunction
; /* NotifyCallback uses Objects, so this needs to be here in order to call the registered functions */
386 CallbackRegistration
->CallbackContext
= CallbackContext
; /* The documented NotifyCallback returns the Context, so we must save this somewhere */
388 /* Acquire SpinLock */
389 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
391 /* Add Callback if 1) No Callbacks registered or 2) Multiple Callbacks allowed */
392 if(CallbackObject
->AllowMultipleCallbacks
|| IsListEmpty(&CallbackObject
->RegisteredCallbacks
))
394 InsertTailList(&CallbackObject
->RegisteredCallbacks
,&CallbackRegistration
->RegisteredCallbacks
);
398 ExFreePool(CallbackRegistration
);
399 CallbackRegistration
= NULL
;
402 /* Release SpinLock */
403 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
405 /* Return handle to Registration Object */
406 return (PVOID
) CallbackRegistration
;
410 * ExUnregisterCallback
413 * Deregisters a CallBack
416 * CallbackRegistration = Callback Registration Handle
424 ExUnregisterCallback(
425 IN PVOID CallbackRegistrationHandle
428 PCALLBACK_REGISTRATION CallbackRegistration
;
429 PINT_CALLBACK_OBJECT CallbackObject
;
432 /* Convert Handle to valid Structure Pointer */
433 CallbackRegistration
= (PCALLBACK_REGISTRATION
) CallbackRegistrationHandle
;
435 /* Get the Callback Object */
436 CallbackObject
= CallbackRegistration
->CallbackObject
;
438 /* Lock the Object */
439 OldIrql
= KfAcquireSpinLock (&CallbackObject
->Lock
);
441 /* We can't Delete the Callback if it's in use, because this would create a call towards a null pointer => crash */
442 while (CallbackRegistration
->InUse
)
445 /* Similarly, we also don't want to wait ages for all pending callbacks to be called */
446 CallbackRegistration
->PendingDeletion
= TRUE
;
448 /* We are going to wait for the event, so the Lock isn't necessary */
449 KfReleaseSpinLock (&CallbackObject
->Lock
, OldIrql
);
451 /* Make sure the event is cleared */
452 KeClearEvent (&ExpCallbackEvent
);
454 /* Wait for the Event */
455 KeWaitForSingleObject (
463 /* We need the Lock again */
464 OldIrql
= KfAcquireSpinLock(&CallbackObject
->Lock
);
467 /* Remove the Callback */
468 RemoveEntryList(&CallbackRegistration
->RegisteredCallbacks
);
470 /* It's now safe to release the lock */
471 KfReleaseSpinLock(&CallbackObject
->Lock
, OldIrql
);
473 /* Delete this registration */
474 ExFreePool(CallbackRegistration
);
476 /* Remove the reference */
477 ObDereferenceObject(CallbackObject
);