Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencallback.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/ex/callback.c 00005 * PURPOSE: Executive callbacks 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 */ 00008 00009 /* INCLUDES ******************************************************************/ 00010 00011 #include <ntoskrnl.h> 00012 #define NDEBUG 00013 #include <debug.h> 00014 00015 /* TYPES *********************************************************************/ 00016 00017 /* Mapping for Callback Object */ 00018 GENERIC_MAPPING ExpCallbackMapping = 00019 { 00020 CALLBACK_READ, 00021 CALLBACK_WRITE, 00022 CALLBACK_EXECUTE, 00023 CALLBACK_ALL_ACCESS 00024 }; 00025 00026 /* Kernel Default Callbacks */ 00027 PCALLBACK_OBJECT SetSystemTimeCallback; 00028 PCALLBACK_OBJECT SetSystemStateCallback; 00029 PCALLBACK_OBJECT PowerStateCallback; 00030 SYSTEM_CALLBACKS ExpInitializeCallback[] = 00031 { 00032 {&SetSystemTimeCallback, L"\\Callback\\SetSystemTime"}, 00033 {&SetSystemStateCallback, L"\\Callback\\SetSystemState"}, 00034 {&PowerStateCallback, L"\\Callback\\PowerState"}, 00035 {NULL, NULL} 00036 }; 00037 00038 POBJECT_TYPE ExCallbackObjectType; 00039 KEVENT ExpCallbackEvent; 00040 EX_PUSH_LOCK ExpCallBackFlush; 00041 00042 /* PRIVATE FUNCTIONS *********************************************************/ 00043 00044 VOID 00045 NTAPI 00046 ExInitializeCallBack(IN OUT PEX_CALLBACK Callback) 00047 { 00048 /* Initialize the fast reference */ 00049 ExInitializeFastReference(&Callback->RoutineBlock, NULL); 00050 } 00051 00052 PEX_CALLBACK_ROUTINE_BLOCK 00053 NTAPI 00054 ExAllocateCallBack(IN PEX_CALLBACK_FUNCTION Function, 00055 IN PVOID Context) 00056 { 00057 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock; 00058 00059 /* Allocate a callback */ 00060 CallbackBlock = ExAllocatePoolWithTag(PagedPool, 00061 sizeof(EX_CALLBACK_ROUTINE_BLOCK), 00062 'CbRb'); 00063 if (CallbackBlock) 00064 { 00065 /* Initialize it */ 00066 CallbackBlock->Function = Function; 00067 CallbackBlock->Context = Context; 00068 ExInitializeRundownProtection(&CallbackBlock->RundownProtect); 00069 } 00070 00071 /* Return it */ 00072 return CallbackBlock; 00073 } 00074 00075 VOID 00076 NTAPI 00077 ExFreeCallBack(IN PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock) 00078 { 00079 /* Just free it from memory */ 00080 ExFreePoolWithTag(CallbackBlock, CALLBACK_TAG); 00081 } 00082 00083 VOID 00084 NTAPI 00085 ExWaitForCallBacks(IN PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock) 00086 { 00087 /* Wait on the rundown */ 00088 ExWaitForRundownProtectionRelease(&CallbackBlock->RundownProtect); 00089 } 00090 00091 PEX_CALLBACK_FUNCTION 00092 NTAPI 00093 ExGetCallBackBlockRoutine(IN PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock) 00094 { 00095 /* Return the function */ 00096 return CallbackBlock->Function; 00097 } 00098 00099 PVOID 00100 NTAPI 00101 ExGetCallBackBlockContext(IN PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock) 00102 { 00103 /* Return the context */ 00104 return CallbackBlock->Context; 00105 } 00106 00107 VOID 00108 NTAPI 00109 ExDereferenceCallBackBlock(IN OUT PEX_CALLBACK CallBack, 00110 IN PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock) 00111 { 00112 /* Release a fast reference */ 00113 if (!ExReleaseFastReference(&CallBack->RoutineBlock, CallbackBlock)) 00114 { 00115 /* Take slow path */ 00116 ExReleaseRundownProtection(&CallbackBlock->RundownProtect); 00117 } 00118 } 00119 00120 PEX_CALLBACK_ROUTINE_BLOCK 00121 NTAPI 00122 ExReferenceCallBackBlock(IN OUT PEX_CALLBACK CallBack) 00123 { 00124 EX_FAST_REF OldValue; 00125 ULONG_PTR Count; 00126 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock; 00127 00128 /* Acquire a reference */ 00129 OldValue = ExAcquireFastReference(&CallBack->RoutineBlock); 00130 Count = ExGetCountFastReference(OldValue); 00131 00132 /* Fail if there isn't any object */ 00133 if (!ExGetObjectFastReference(OldValue)) return NULL; 00134 00135 /* Check if we don't have a reference */ 00136 if (!Count) 00137 { 00138 /* FIXME: Race */ 00139 DPRINT1("Unhandled callback race condition\n"); 00140 ASSERT(FALSE); 00141 return NULL; 00142 } 00143 00144 /* Get the callback block */ 00145 CallbackBlock = ExGetObjectFastReference(OldValue); 00146 00147 /* Check if this is the last reference */ 00148 if (Count == 1) 00149 { 00150 /* Acquire rundown protection */ 00151 if (ExfAcquireRundownProtectionEx(&CallbackBlock->RundownProtect, 00152 MAX_FAST_REFS)) 00153 { 00154 /* Insert references */ 00155 if (!ExInsertFastReference(&CallBack->RoutineBlock, CallbackBlock)) 00156 { 00157 /* Backdown the rundown acquire */ 00158 ExfReleaseRundownProtectionEx(&CallbackBlock->RundownProtect, 00159 MAX_FAST_REFS); 00160 } 00161 } 00162 } 00163 00164 /* Return the callback block */ 00165 return CallbackBlock; 00166 } 00167 00168 BOOLEAN 00169 NTAPI 00170 ExCompareExchangeCallBack(IN OUT PEX_CALLBACK CallBack, 00171 IN PEX_CALLBACK_ROUTINE_BLOCK NewBlock, 00172 IN PEX_CALLBACK_ROUTINE_BLOCK OldBlock) 00173 { 00174 EX_FAST_REF OldValue; 00175 PEX_CALLBACK_ROUTINE_BLOCK CallbackBlock; 00176 ULONG Count; 00177 00178 /* Check that we have a new block */ 00179 if (NewBlock) 00180 { 00181 /* Acquire rundown */ 00182 if (!ExfAcquireRundownProtectionEx(&NewBlock->RundownProtect, 00183 MAX_FAST_REFS + 1)) 00184 { 00185 /* This should never happen */ 00186 ASSERTMSG("Callback block is already undergoing rundown", FALSE); 00187 return FALSE; 00188 } 00189 } 00190 00191 /* Do the swap */ 00192 OldValue = ExCompareSwapFastReference(&CallBack->RoutineBlock, 00193 NewBlock, 00194 OldBlock); 00195 00196 /* Get the routine block */ 00197 CallbackBlock = ExGetObjectFastReference(OldValue); 00198 Count = ExGetCountFastReference(OldValue); 00199 00200 /* Make sure the swap worked */ 00201 if (CallbackBlock == OldBlock) 00202 { 00203 /* Make sure we replaced a valid pointer */ 00204 if (CallbackBlock) 00205 { 00206 /* Acquire the flush lock and immediately release it */ 00207 KeEnterCriticalRegion(); 00208 ExWaitOnPushLock(&ExpCallBackFlush); 00209 00210 /* Release rundown protection */ 00211 KeLeaveCriticalRegion(); 00212 ExfReleaseRundownProtectionEx(&CallbackBlock->RundownProtect, 00213 Count + 1); 00214 } 00215 00216 /* Compare worked */ 00217 return TRUE; 00218 } 00219 else 00220 { 00221 /* It failed, check if we had a block */ 00222 if (NewBlock) 00223 { 00224 /* We did, remove the refernces that we had added */ 00225 ExfReleaseRundownProtectionEx(&NewBlock->RundownProtect, 00226 MAX_FAST_REFS + 1); 00227 } 00228 00229 /* Return failure */ 00230 return FALSE; 00231 } 00232 } 00233 00234 VOID 00235 NTAPI 00236 ExpDeleteCallback(IN PVOID Object) 00237 { 00238 /* Sanity check */ 00239 ASSERT(IsListEmpty(&((PCALLBACK_OBJECT)Object)->RegisteredCallbacks)); 00240 } 00241 00242 /*++ 00243 * @name ExpInitializeCallbacks 00244 * 00245 * Creates the Callback Object as a valid Object Type in the Kernel. 00246 * Internal function, subject to further review 00247 * 00248 * @return TRUE if the Callback Object Type was successfully created. 00249 * 00250 * @remarks None 00251 * 00252 *--*/ 00253 BOOLEAN 00254 INIT_FUNCTION 00255 NTAPI 00256 ExpInitializeCallbacks(VOID) 00257 { 00258 OBJECT_ATTRIBUTES ObjectAttributes; 00259 NTSTATUS Status; 00260 UNICODE_STRING DirName = RTL_CONSTANT_STRING(L"\\Callback"); 00261 UNICODE_STRING CallbackName; 00262 UNICODE_STRING Name; 00263 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 00264 HANDLE DirectoryHandle; 00265 ULONG i; 00266 00267 /* Setup lightweight callback lock */ 00268 ExpCallBackFlush.Value = 0; 00269 00270 /* Initialize the Callback Object type */ 00271 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 00272 RtlInitUnicodeString(&Name, L"Callback"); 00273 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 00274 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 00275 ObjectTypeInitializer.GenericMapping = ExpCallbackMapping; 00276 ObjectTypeInitializer.PoolType = NonPagedPool; 00277 ObjectTypeInitializer.DeleteProcedure = ExpDeleteCallback; 00278 ObjectTypeInitializer.ValidAccessMask = CALLBACK_ALL_ACCESS; 00279 Status = ObCreateObjectType(&Name, 00280 &ObjectTypeInitializer, 00281 NULL, 00282 &ExCallbackObjectType); 00283 if (!NT_SUCCESS(Status)) return FALSE; 00284 00285 /* Initialize the Object */ 00286 InitializeObjectAttributes(&ObjectAttributes, 00287 &DirName, 00288 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, 00289 NULL, 00290 SePublicDefaultSd); 00291 00292 /* Create the Object Directory */ 00293 Status = NtCreateDirectoryObject(&DirectoryHandle, 00294 DIRECTORY_ALL_ACCESS, 00295 &ObjectAttributes); 00296 if (!NT_SUCCESS(Status)) return FALSE; 00297 00298 /* Close Handle... */ 00299 NtClose(DirectoryHandle); 00300 00301 /* Initialize Event used when unregistering */ 00302 KeInitializeEvent(&ExpCallbackEvent, NotificationEvent, 0); 00303 00304 /* Default NT Kernel Callbacks. */ 00305 for (i = 0; ExpInitializeCallback[i].CallbackObject; i++) 00306 { 00307 /* Create the name from the structure */ 00308 RtlInitUnicodeString(&CallbackName, ExpInitializeCallback[i].Name); 00309 00310 /* Initialize the Object Attributes Structure */ 00311 InitializeObjectAttributes(&ObjectAttributes, 00312 &CallbackName, 00313 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, 00314 NULL, 00315 NULL); 00316 00317 /* Create the Callback Object */ 00318 Status = ExCreateCallback(ExpInitializeCallback[i].CallbackObject, 00319 &ObjectAttributes, 00320 TRUE, 00321 TRUE); 00322 if (!NT_SUCCESS(Status)) return FALSE; 00323 } 00324 00325 /* Everything successful */ 00326 return TRUE; 00327 } 00328 00329 /* PUBLIC FUNCTIONS **********************************************************/ 00330 00331 /*++ 00332 * @name ExCreateCallback 00333 * @implemented 00334 * 00335 * Opens or creates a Callback Object. Creates only if Create is true. 00336 * Allows multiple Callback Functions to be registred only if 00337 * AllowMultipleCallbacks is true. 00338 * See: http://www.osronline.com/ddkx/kmarch/k102_967m.htm 00339 * http://www.osronline.com/article.cfm?id=24 00340 * 00341 * @param CallbackObject 00342 * Pointer that will receive the Callback Object. 00343 * 00344 * @param CallbackName 00345 * Name of Callback 00346 * 00347 * @param Create 00348 * Determines if the object will be created if it doesn't exit 00349 * 00350 * @param AllowMultipleCallbacks 00351 * Determines if more then one registered callback function 00352 * can be attached to this Callback Object. 00353 * 00354 * @return STATUS_SUCESS if not failed. 00355 * 00356 * @remarks Must be called at IRQL = PASSIVE_LEVEL 00357 * 00358 *--*/ 00359 NTSTATUS 00360 NTAPI 00361 ExCreateCallback(OUT PCALLBACK_OBJECT *CallbackObject, 00362 IN POBJECT_ATTRIBUTES ObjectAttributes, 00363 IN BOOLEAN Create, 00364 IN BOOLEAN AllowMultipleCallbacks) 00365 { 00366 PCALLBACK_OBJECT Callback = NULL; 00367 NTSTATUS Status; 00368 HANDLE Handle = NULL; 00369 PAGED_CODE(); 00370 00371 /* Open a handle to the callback if it exists */ 00372 if (ObjectAttributes->ObjectName) 00373 { 00374 /* Open the handle */ 00375 Status = ObOpenObjectByName(ObjectAttributes, 00376 ExCallbackObjectType, 00377 KernelMode, 00378 NULL, 00379 0, 00380 NULL, 00381 &Handle); 00382 } 00383 else 00384 { 00385 /* Otherwise, fail */ 00386 Status = STATUS_UNSUCCESSFUL; 00387 } 00388 00389 /* We weren't able to open it...should we create it? */ 00390 if (!(NT_SUCCESS(Status)) && (Create)) 00391 { 00392 /* Create the object */ 00393 Status = ObCreateObject(KernelMode, 00394 ExCallbackObjectType, 00395 ObjectAttributes, 00396 KernelMode, 00397 NULL, 00398 sizeof(CALLBACK_OBJECT), 00399 0, 00400 0, 00401 (PVOID *)&Callback); 00402 if (NT_SUCCESS(Status)) 00403 { 00404 /* Set it up */ 00405 Callback->Signature = 'llaC'; 00406 KeInitializeSpinLock(&Callback->Lock); 00407 InitializeListHead(&Callback->RegisteredCallbacks); 00408 Callback->AllowMultipleCallbacks = AllowMultipleCallbacks; 00409 00410 /* Insert the object into the object namespace */ 00411 Status = ObInsertObject(Callback, 00412 NULL, 00413 FILE_READ_DATA, 00414 0, 00415 NULL, 00416 &Handle); 00417 } 00418 } 00419 00420 /* Check if we have success until here */ 00421 if (NT_SUCCESS(Status)) 00422 { 00423 /* Get a pointer to the new object from the handle we just got */ 00424 Status = ObReferenceObjectByHandle(Handle, 00425 0, 00426 ExCallbackObjectType, 00427 KernelMode, 00428 (PVOID)&Callback, 00429 NULL); 00430 00431 /* Close the Handle, since we now have the pointer */ 00432 ZwClose(Handle); 00433 } 00434 00435 /* Everything went fine, so return a pointer to the Object */ 00436 if (NT_SUCCESS(Status)) *CallbackObject = Callback; 00437 return Status; 00438 } 00439 00440 /*++ 00441 * @name ExNotifyCallback 00442 * @implemented 00443 * 00444 * Calls a function pointer (a registered callback) 00445 * See: http://www.osronline.com/ddkx/kmarch/k102_2f5e.htm 00446 * http://vmsone.com/~decuslib/vmssig/vmslt99b/nt/wdm-callback.txt 00447 * 00448 * @param CallbackObject 00449 * Which callback to call 00450 * 00451 * @param Argument1 00452 * Pointer/data to send to callback function 00453 * 00454 * @param Argument2 00455 * Pointer/data to send to callback function 00456 * 00457 * @return None 00458 * 00459 * @remarks None 00460 * 00461 *--*/ 00462 VOID 00463 NTAPI 00464 ExNotifyCallback(IN PCALLBACK_OBJECT CallbackObject, 00465 IN PVOID Argument1, 00466 IN PVOID Argument2) 00467 { 00468 PLIST_ENTRY RegisteredCallbacks; 00469 PCALLBACK_REGISTRATION CallbackRegistration; 00470 KIRQL OldIrql; 00471 00472 /* Check if we don't have an object or registrations */ 00473 if (!(CallbackObject) || 00474 (IsListEmpty(&CallbackObject->RegisteredCallbacks))) 00475 { 00476 /* Don't notify */ 00477 return; 00478 } 00479 00480 /* Acquire the Lock */ 00481 KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql); 00482 00483 /* Enumerate through all the registered functions */ 00484 for (RegisteredCallbacks = CallbackObject->RegisteredCallbacks.Flink; 00485 RegisteredCallbacks != &CallbackObject->RegisteredCallbacks; 00486 RegisteredCallbacks = RegisteredCallbacks->Flink) 00487 { 00488 /* Get a pointer to a Callback Registration from the List Entries */ 00489 CallbackRegistration = CONTAINING_RECORD(RegisteredCallbacks, 00490 CALLBACK_REGISTRATION, 00491 Link); 00492 00493 /* Don't bother doing notification if it's pending to be deleted */ 00494 if (!CallbackRegistration->UnregisterWaiting) 00495 { 00496 /* Mark the Callback in use, so it won't get deleted */ 00497 CallbackRegistration->Busy += 1; 00498 00499 /* Release the Spinlock before making the call */ 00500 KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); 00501 00502 /* Call the Registered Function */ 00503 CallbackRegistration->CallbackFunction(CallbackRegistration-> 00504 CallbackContext, 00505 Argument1, 00506 Argument2); 00507 00508 /* Get SpinLock back */ 00509 KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql); 00510 00511 /* We are not in use anymore */ 00512 CallbackRegistration->Busy -= 1; 00513 00514 /* Check if removal is pending and we're not active */ 00515 if ((CallbackRegistration->UnregisterWaiting) && 00516 !(CallbackRegistration->Busy)) 00517 { 00518 /* Signal the callback event */ 00519 KeSetEvent(&ExpCallbackEvent, 0, FALSE); 00520 } 00521 } 00522 } 00523 00524 /* Release the Callback Object */ 00525 KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); 00526 } 00527 00528 /*++ 00529 * @name ExRegisterCallback 00530 * @implemented 00531 * 00532 * Allows a function to associate a callback pointer (Function) to 00533 * a created Callback object 00534 * See: DDK, OSR, links in ExNotifyCallback 00535 * 00536 * @param CallbackObject 00537 * The Object Created with ExCreateCallBack 00538 * 00539 * @param CallBackFunction 00540 * Pointer to the function to be called back 00541 * 00542 * @param CallBackContext 00543 * Block of memory that can contain user-data which will be 00544 * passed on to the callback 00545 * 00546 * @return A handle to a Callback Registration Structure (MSDN Documentation) 00547 * 00548 * @remarks None 00549 * 00550 *--*/ 00551 PVOID 00552 NTAPI 00553 ExRegisterCallback(IN PCALLBACK_OBJECT CallbackObject, 00554 IN PCALLBACK_FUNCTION CallbackFunction, 00555 IN PVOID CallbackContext) 00556 { 00557 PCALLBACK_REGISTRATION CallbackRegistration = NULL; 00558 KIRQL OldIrql; 00559 00560 /* Sanity checks */ 00561 ASSERT(CallbackFunction); 00562 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00563 00564 /* Create reference to Callback Object */ 00565 ObReferenceObject(CallbackObject); 00566 00567 /* Allocate memory for the structure */ 00568 CallbackRegistration = ExAllocatePoolWithTag(NonPagedPool, 00569 sizeof(CALLBACK_REGISTRATION), 00570 CALLBACK_TAG); 00571 if (!CallbackRegistration) 00572 { 00573 /* Dereference and fail */ 00574 ObDereferenceObject (CallbackObject); 00575 return NULL; 00576 } 00577 00578 /* Create Callback Registration */ 00579 CallbackRegistration->CallbackObject = CallbackObject; 00580 CallbackRegistration->CallbackFunction = CallbackFunction; 00581 CallbackRegistration->CallbackContext = CallbackContext; 00582 CallbackRegistration->Busy = 0; 00583 CallbackRegistration->UnregisterWaiting = FALSE; 00584 00585 /* Acquire SpinLock */ 00586 KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql); 00587 00588 /* Check if 1) No Callbacks registered or 2) Multiple Callbacks allowed */ 00589 if ((CallbackObject->AllowMultipleCallbacks) || 00590 (IsListEmpty(&CallbackObject->RegisteredCallbacks))) 00591 { 00592 /* Register the callback */ 00593 InsertTailList(&CallbackObject->RegisteredCallbacks, 00594 &CallbackRegistration->Link); 00595 00596 /* Release SpinLock */ 00597 KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); 00598 } 00599 else 00600 { 00601 /* Release SpinLock */ 00602 KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); 00603 00604 /* Free the registration */ 00605 ExFreePoolWithTag(CallbackRegistration, CALLBACK_TAG); 00606 CallbackRegistration = NULL; 00607 00608 /* Dereference the object */ 00609 ObDereferenceObject(CallbackObject); 00610 } 00611 00612 /* Return handle to Registration Object */ 00613 return (PVOID)CallbackRegistration; 00614 } 00615 00616 /*++ 00617 * @name ExUnregisterCallback 00618 * @implemented 00619 * 00620 * Deregisters a CallBack 00621 * See: DDK, OSR, links in ExNotifyCallback 00622 * 00623 * @param CallbackRegistration 00624 * Callback Registration Handle 00625 * 00626 * @return None 00627 * 00628 * @remarks None 00629 * 00630 *--*/ 00631 VOID 00632 NTAPI 00633 ExUnregisterCallback(IN PVOID CallbackRegistrationHandle) 00634 { 00635 PCALLBACK_REGISTRATION CallbackRegistration; 00636 PCALLBACK_OBJECT CallbackObject; 00637 KIRQL OldIrql; 00638 ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); 00639 00640 /* Convert Handle to valid Structure Pointer */ 00641 CallbackRegistration = (PCALLBACK_REGISTRATION)CallbackRegistrationHandle; 00642 00643 /* Get the Callback Object */ 00644 CallbackObject = CallbackRegistration->CallbackObject; 00645 00646 /* Lock the Object */ 00647 KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); 00648 00649 /* We can't Delete the Callback if it's in use */ 00650 while (CallbackRegistration->Busy) 00651 { 00652 /* Let everyone else know we're unregistering */ 00653 CallbackRegistration->UnregisterWaiting = TRUE; 00654 00655 /* We are going to wait for the event, so the Lock isn't necessary */ 00656 KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); 00657 00658 /* Make sure the event is cleared */ 00659 KeClearEvent(&ExpCallbackEvent); 00660 00661 /* Wait for the Event */ 00662 KeWaitForSingleObject(&ExpCallbackEvent, 00663 Executive, 00664 KernelMode, 00665 FALSE, 00666 NULL); 00667 00668 /* We need the Lock again */ 00669 KeAcquireSpinLock(&CallbackObject->Lock, &OldIrql); 00670 } 00671 00672 /* Remove the Callback */ 00673 RemoveEntryList(&CallbackRegistration->Link); 00674 00675 /* It's now safe to release the lock */ 00676 KeReleaseSpinLock(&CallbackObject->Lock, OldIrql); 00677 00678 /* Delete this registration */ 00679 ExFreePoolWithTag(CallbackRegistration, CALLBACK_TAG); 00680 00681 /* Remove the reference */ 00682 ObDereferenceObject(CallbackObject); 00683 } 00684 00685 /* EOF */ Generated on Fri May 25 2012 04:15:53 for ReactOS by
1.7.6.1
|