Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

callback.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989-1995 Microsoft Corporation 00004 00005 Module Name: 00006 00007 callback.c 00008 00009 Abstract: 00010 00011 This module implements the executive callbaqck object. Functions are 00012 provided to open, register, unregister , and notify callback objects. 00013 00014 Author: 00015 00016 Ken Reneris (kenr) 7-March-1995 00017 00018 Environment: 00019 00020 Kernel mode only. 00021 00022 Revision History: 00023 00024 --*/ 00025 00026 00027 #include "exp.h" 00028 00029 // 00030 // Callback Specific Access Rights. 00031 // 00032 00033 #define CALLBACK_MODIFY_STATE 0x0001 00034 00035 #define CALLBACK_ALL_ACCESS (STANDARD_RIGHTS_REQUIRED|SYNCHRONIZE|\ 00036 CALLBACK_MODIFY_STATE ) 00037 00038 00039 // 00040 // Address of callback object type descriptor. 00041 // 00042 00043 POBJECT_TYPE ExCallbackObjectType; 00044 00045 // 00046 // Event to wait for registration to become idle 00047 // 00048 00049 KEVENT ExpCallbackEvent; 00050 00051 // 00052 // Structure that describes the mapping of generic access rights to object 00053 // specific access rights for callback objects. 00054 // 00055 00056 GENERIC_MAPPING ExpCallbackMapping = { 00057 STANDARD_RIGHTS_READ , 00058 STANDARD_RIGHTS_WRITE | CALLBACK_MODIFY_STATE, 00059 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, 00060 CALLBACK_ALL_ACCESS 00061 }; 00062 00063 // 00064 // Executive callback object structure definition. 00065 // 00066 00067 typedef struct _CALLBACK_OBJECT { 00068 ULONG Signature; 00069 KSPIN_LOCK Lock; 00070 LIST_ENTRY RegisteredCallbacks; 00071 BOOLEAN AllowMultipleCallbacks; 00072 UCHAR reserved[3]; 00073 } CALLBACK_OBJECT , *PCALLBACK_OBJECT; 00074 00075 // 00076 // Executive callback registration structure definition. 00077 // 00078 00079 typedef struct _CALLBACK_REGISTRATION { 00080 LIST_ENTRY Link; 00081 PCALLBACK_OBJECT CallbackObject; 00082 PCALLBACK_FUNCTION CallbackFunction; 00083 PVOID CallbackContext; 00084 ULONG Busy; 00085 BOOLEAN UnregisterWaiting; 00086 } CALLBACK_REGISTRATION , *PCALLBACK_REGISTRATION; 00087 00088 00089 VOID 00090 ExpDeleteCallback ( 00091 IN PCALLBACK_OBJECT CallbackObject 00092 ); 00093 00094 #ifdef ALLOC_PRAGMA 00095 #pragma alloc_text(INIT, ExpInitializeCallbacks) 00096 #pragma alloc_text(PAGE, ExCreateCallback) 00097 #pragma alloc_text(PAGE, ExpDeleteCallback) 00098 #endif 00099 00100 BOOLEAN 00101 ExpInitializeCallbacks ( 00102 ) 00103 00104 /*++ 00105 00106 Routine Description: 00107 00108 This function creates the callback object type descriptor at system 00109 initialization and stores the address of the object type descriptor 00110 in local static storage. 00111 00112 Arguments: 00113 00114 None. 00115 00116 Return Value: 00117 00118 A value of TRUE is returned if the timer object type descriptor is 00119 successfully initialized. Otherwise a value of FALSE is returned. 00120 00121 --*/ 00122 00123 { 00124 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 00125 OBJECT_ATTRIBUTES ObjectAttributes; 00126 NTSTATUS Status; 00127 UNICODE_STRING unicodeString; 00128 ULONG i; 00129 HANDLE handle; 00130 00131 // 00132 // Initialize string descriptor. 00133 // 00134 00135 RtlInitUnicodeString(&unicodeString, L"Callback"); 00136 00137 // 00138 // Create timer object type descriptor. 00139 // 00140 00141 RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer)); 00142 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 00143 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 00144 ObjectTypeInitializer.GenericMapping = ExpCallbackMapping; 00145 ObjectTypeInitializer.DeleteProcedure = ExpDeleteCallback; 00146 ObjectTypeInitializer.PoolType = NonPagedPool; 00147 ObjectTypeInitializer.ValidAccessMask = CALLBACK_ALL_ACCESS; 00148 Status = ObCreateObjectType(&unicodeString, 00149 &ObjectTypeInitializer, 00150 (PSECURITY_DESCRIPTOR)NULL, 00151 &ExCallbackObjectType); 00152 00153 if (!NT_SUCCESS(Status)) { 00154 return FALSE; 00155 } 00156 00157 RtlInitUnicodeString( &unicodeString, ExpWstrCallback ); 00158 InitializeObjectAttributes( 00159 &ObjectAttributes, 00160 &unicodeString, 00161 OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, 00162 NULL, 00163 SePublicDefaultSd 00164 ); 00165 00166 Status = NtCreateDirectoryObject( 00167 &handle, 00168 DIRECTORY_ALL_ACCESS, 00169 &ObjectAttributes 00170 ); 00171 00172 if (!NT_SUCCESS(Status)) { 00173 return FALSE; 00174 } 00175 00176 NtClose (handle); 00177 00178 // 00179 // Initialize event to wait on for Unregisters which occur while 00180 // notifications are in progress 00181 // 00182 00183 KeInitializeEvent (&ExpCallbackEvent, NotificationEvent, 0); 00184 00185 // 00186 // Initialize NT global callbacks 00187 // 00188 00189 for (i=0; ExpInitializeCallback[i].CallBackObject; i++) { 00190 00191 // 00192 // Create named calledback 00193 // 00194 00195 RtlInitUnicodeString(&unicodeString, ExpInitializeCallback[i].CallbackName); 00196 00197 00198 InitializeObjectAttributes( 00199 &ObjectAttributes, 00200 &unicodeString, 00201 OBJ_PERMANENT | OBJ_CASE_INSENSITIVE, 00202 NULL, 00203 NULL 00204 ); 00205 00206 Status = ExCreateCallback ( 00207 ExpInitializeCallback[i].CallBackObject, 00208 &ObjectAttributes, 00209 TRUE, 00210 TRUE 00211 ); 00212 00213 if (!NT_SUCCESS(Status)) { 00214 return FALSE; 00215 } 00216 } 00217 00218 return TRUE; 00219 } 00220 00221 NTSTATUS 00222 ExCreateCallback ( 00223 OUT PCALLBACK_OBJECT * CallbackObject, 00224 IN POBJECT_ATTRIBUTES ObjectAttributes, 00225 IN BOOLEAN Create, 00226 IN BOOLEAN AllowMultipleCallbacks 00227 ) 00228 00229 /*++ 00230 00231 Routine Description: 00232 00233 This function opens a callback object with the specified callback 00234 object. If the callback object does not exist or it is a NULL then 00235 a callback object will be created if create is TRUE. If a callbackobject 00236 is created it will only support mulitiple registered callbacks if 00237 AllowMulitipleCallbacks is TRUE. 00238 00239 Arguments: 00240 00241 CallbackObject - Supplies a pointer to a variable that will receive the 00242 Callback object. 00243 00244 CallbackName - Supplies a pointer to a object name that will receive the 00245 00246 Create - Supplies a flag which indicates whether a callback object will 00247 be created or not . 00248 00249 AllowMultipleCallbacks - Supplies a flag which indicates only support 00250 mulitiple registered callbacks. 00251 00252 Return Value: 00253 00254 Returns STATUS_SUCESS unless fali... 00255 00256 --*/ 00257 00258 { 00259 PCALLBACK_OBJECT cbObject; 00260 NTSTATUS Status; 00261 HANDLE Handle; 00262 00263 PAGED_CODE(); 00264 00265 // 00266 // If named callback, open handle to it 00267 // 00268 00269 if (ObjectAttributes->ObjectName) { 00270 Status = ObOpenObjectByName(ObjectAttributes, 00271 ExCallbackObjectType, 00272 KernelMode, 00273 NULL, 00274 0, // DesiredAccess, 00275 NULL, 00276 &Handle); 00277 } else { 00278 Status = STATUS_UNSUCCESSFUL; 00279 } 00280 00281 // 00282 // If not opened, check if callback should be created 00283 // 00284 00285 if(!NT_SUCCESS(Status) && Create ) { 00286 Status = ObCreateObject(KernelMode, 00287 ExCallbackObjectType, 00288 ObjectAttributes, 00289 KernelMode, 00290 NULL, 00291 sizeof(CALLBACK_OBJECT), 00292 0, 00293 0, 00294 (PVOID *)&cbObject ); 00295 00296 if(NT_SUCCESS(Status)){ 00297 00298 // 00299 // Fill in structure signature 00300 // 00301 00302 cbObject->Signature = 'llaC'; 00303 00304 // 00305 // It will support multiple registered callbacks if 00306 // AllowMultipleCallbacks is TRUE. 00307 // 00308 00309 cbObject->AllowMultipleCallbacks = AllowMultipleCallbacks; 00310 00311 // 00312 // Initialize CallbackObject queue. 00313 // 00314 00315 InitializeListHead( &cbObject->RegisteredCallbacks ); 00316 00317 // 00318 // Initialize spinlock 00319 // 00320 00321 KeInitializeSpinLock (&cbObject->Lock); 00322 00323 00324 // 00325 // Put the object in the root directory 00326 // 00327 00328 Status = ObInsertObject ( 00329 cbObject, 00330 NULL, 00331 FILE_READ_DATA, 00332 0, 00333 NULL, 00334 &Handle ); 00335 00336 } 00337 00338 } 00339 00340 if(NT_SUCCESS(Status)){ 00341 00342 // 00343 // Add one to callback object reference count 00344 // 00345 00346 Status = ObReferenceObjectByHandle ( 00347 Handle, 00348 0, // DesiredAccess 00349 ExCallbackObjectType, 00350 KernelMode, 00351 &cbObject, 00352 NULL 00353 ); 00354 00355 ZwClose (Handle); 00356 } 00357 00358 // 00359 // If SUCEESS , returns a referenced pointer to the CallbackObject. 00360 // 00361 00362 if (NT_SUCCESS(Status)) { 00363 *CallbackObject = cbObject; 00364 } 00365 00366 return Status; 00367 } 00368 00369 VOID 00370 ExpDeleteCallback ( 00371 IN PCALLBACK_OBJECT CallbackObject 00372 ) 00373 { 00374 ASSERT (IsListEmpty(&CallbackObject->RegisteredCallbacks)); 00375 } 00376 00377 PVOID 00378 ExRegisterCallback ( 00379 IN PCALLBACK_OBJECT CallbackObject, 00380 IN PCALLBACK_FUNCTION CallbackFunction, 00381 IN PVOID CallbackContext 00382 ) 00383 00384 /*++ 00385 00386 Routine Description: 00387 00388 This routine allows a caller to register that it would like to have its 00389 callback Function invoked when the callback notification call occurs. 00390 00391 Arguments: 00392 00393 CallbackObject - Supplies a pointer to a CallbackObject. 00394 00395 CallbackFunction - Supplies a pointer to a function which is to 00396 be executed when the Callback notification occures. 00397 00398 CallbackContext - Supplies a pointer to an arbitrary data structure 00399 that will be passed to the function specified by the CallbackFunction 00400 parameter. 00401 00402 Return Value: 00403 00404 Returns handle to callback registration. 00405 00406 --*/ 00407 { 00408 PCALLBACK_REGISTRATION CallbackRegistration; 00409 BOOLEAN Inserted; 00410 KIRQL OldIrql; 00411 NTSTATUS Status; 00412 00413 ASSERT (CallbackFunction); 00414 ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL); 00415 00416 // 00417 // Add reference to object 00418 // 00419 00420 ObReferenceObject (CallbackObject); 00421 00422 // 00423 // Begin by attempting to allocate storage for the CallbackRegistration. 00424 // one cannot be allocated, return the error status. 00425 // 00426 00427 CallbackRegistration = ExAllocatePoolWithTag( 00428 NonPagedPool, 00429 sizeof( CALLBACK_REGISTRATION ), 00430 'eRBC' 00431 ); 00432 00433 00434 if( !CallbackRegistration ) { 00435 ObDereferenceObject (CallbackObject); 00436 return NULL; 00437 } 00438 00439 00440 // 00441 // Initialize the callback packet 00442 // 00443 00444 CallbackRegistration->CallbackObject = CallbackObject; 00445 CallbackRegistration->CallbackFunction = CallbackFunction; 00446 CallbackRegistration->CallbackContext = CallbackContext; 00447 CallbackRegistration->Busy = 0; 00448 CallbackRegistration->UnregisterWaiting = FALSE; 00449 00450 00451 Inserted = FALSE; 00452 KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); 00453 00454 if( CallbackObject->AllowMultipleCallbacks || 00455 IsListEmpty( &CallbackObject->RegisteredCallbacks ) ) { 00456 00457 // 00458 // add CallbackRegistration to tail 00459 // 00460 00461 00462 Inserted = TRUE; 00463 InsertTailList( &CallbackObject->RegisteredCallbacks, 00464 &CallbackRegistration->Link ) 00465 } 00466 00467 KeReleaseSpinLock (&CallbackObject->Lock, OldIrql); 00468 00469 if (!Inserted) { 00470 ExFreePool (CallbackRegistration); 00471 CallbackRegistration = NULL; 00472 } 00473 00474 return (PVOID) CallbackRegistration; 00475 } 00476 00477 00478 VOID 00479 ExUnregisterCallback ( 00480 IN PVOID CbRegistration 00481 ) 00482 00483 /*++ 00484 00485 Routine Description: 00486 00487 This function removes the callback registration for the callbacks 00488 from the list of callback object . 00489 00490 Arguments: 00491 00492 CallbackRegistration - Pointer to device object for the file system. 00493 00494 Return Value: 00495 00496 None. 00497 00498 --*/ 00499 00500 { 00501 PCALLBACK_REGISTRATION CallbackRegistration; 00502 PCALLBACK_OBJECT CallbackObject; 00503 KIRQL OldIrql; 00504 00505 ASSERT (KeGetCurrentIrql() < DISPATCH_LEVEL); 00506 00507 CallbackRegistration = (PCALLBACK_REGISTRATION) CbRegistration; 00508 CallbackObject = CallbackRegistration->CallbackObject; 00509 00510 KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); 00511 00512 // 00513 // Wait for registration 00514 // 00515 00516 while (CallbackRegistration->Busy) { 00517 00518 // 00519 // Set waiting flag, then wait. (not performance critical - use 00520 // single global event to wait for any and all unregister waits) 00521 // 00522 00523 CallbackRegistration->UnregisterWaiting = TRUE; 00524 KeClearEvent (&ExpCallbackEvent); 00525 KeReleaseSpinLock (&CallbackObject->Lock, OldIrql); 00526 00527 KeWaitForSingleObject ( 00528 &ExpCallbackEvent, 00529 Executive, 00530 KernelMode, 00531 FALSE, 00532 NULL 00533 ); 00534 00535 // 00536 // Synchronize with callback object and recheck registration busy 00537 // 00538 00539 KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); 00540 } 00541 00542 // 00543 // Registration not busy, remove it from the callback object 00544 // 00545 00546 RemoveEntryList (&CallbackRegistration->Link); 00547 KeReleaseSpinLock (&CallbackObject->Lock, OldIrql); 00548 00549 // 00550 // Free memory used for CallbackRegistration 00551 // 00552 00553 ExFreePool (CallbackRegistration); 00554 00555 // 00556 // Remove reference count on CallbackObject 00557 // 00558 00559 ObDereferenceObject (CallbackObject); 00560 } 00561 00562 VOID 00563 ExNotifyCallback ( 00564 IN PCALLBACK_OBJECT CallbackObject, 00565 IN PVOID Argument1, 00566 IN PVOID Argument2 00567 ) 00568 00569 /*++ 00570 00571 Routine Description: 00572 00573 This function notifies all registered callbacks . 00574 00575 Arguments: 00576 00577 CallbackObject - supplies a pointer to the callback object should be 00578 notified. 00579 00580 SystemArgument1 - supplies a pointer will be passed to callback function. 00581 00582 SystemArgument2 - supplies a pointer will be passed to callback function. 00583 00584 Return Value: 00585 00586 None. 00587 00588 --*/ 00589 00590 { 00591 PLIST_ENTRY Link; 00592 PCALLBACK_REGISTRATION CallbackRegistration; 00593 KIRQL OldIrql; 00594 00595 if (CallbackObject == NULL) { 00596 return ; 00597 } 00598 00599 // 00600 // Synchronize with callback object 00601 // 00602 00603 KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); 00604 00605 // 00606 // call registered callbacks at callers IRQL level 00607 // ( done if FIFO order of registration ) 00608 // 00609 00610 if (OldIrql == DISPATCH_LEVEL) { 00611 00612 // 00613 // OldIrql is DISPATCH_LEVEL, just invoke all callbacks without 00614 // releasing the lock 00615 // 00616 00617 for (Link = CallbackObject->RegisteredCallbacks.Flink; 00618 Link != &CallbackObject->RegisteredCallbacks; 00619 Link = Link->Flink) { 00620 00621 // 00622 // Get current registration to notify 00623 // 00624 00625 CallbackRegistration = CONTAINING_RECORD (Link, 00626 CALLBACK_REGISTRATION, 00627 Link); 00628 00629 // 00630 // Notify reigstration 00631 // 00632 00633 CallbackRegistration->CallbackFunction( 00634 CallbackRegistration->CallbackContext, 00635 Argument1, 00636 Argument2 00637 ); 00638 00639 } // next registration 00640 00641 } else { 00642 00643 // 00644 // OldIrql is < DISPATCH_LEVEL, the code being called may be pagable 00645 // and the callback object spinlock needs to be released around 00646 // each registration callback. 00647 // 00648 00649 for (Link = CallbackObject->RegisteredCallbacks.Flink; 00650 Link != &CallbackObject->RegisteredCallbacks; 00651 Link = Link->Flink ) { 00652 00653 // 00654 // Get current registration to notify 00655 // 00656 00657 CallbackRegistration = CONTAINING_RECORD (Link, 00658 CALLBACK_REGISTRATION, 00659 Link); 00660 00661 // 00662 // If registration is being removed, don't bothing calling it 00663 // 00664 00665 if (!CallbackRegistration->UnregisterWaiting) { 00666 00667 // 00668 // Set registration busy 00669 // 00670 00671 CallbackRegistration->Busy += 1; 00672 00673 // 00674 // Release SpinLock and notify this callback 00675 // 00676 00677 KeReleaseSpinLock (&CallbackObject->Lock, OldIrql); 00678 00679 CallbackRegistration->CallbackFunction( 00680 CallbackRegistration->CallbackContext, 00681 Argument1, 00682 Argument2 00683 ); 00684 00685 // 00686 // Synchronize with CallbackObject 00687 // 00688 00689 KeAcquireSpinLock (&CallbackObject->Lock, &OldIrql); 00690 00691 // 00692 // Remove our busy count 00693 // 00694 00695 CallbackRegistration->Busy -= 1; 00696 00697 // 00698 // If the registriation removal is pending, kick global 00699 // event let unregister conitnue 00700 // 00701 00702 if (CallbackRegistration->UnregisterWaiting && 00703 CallbackRegistration->Busy == 0) { 00704 KeSetEvent (&ExpCallbackEvent, 0, FALSE); 00705 } 00706 } 00707 } 00708 } 00709 00710 00711 // 00712 // Release callback 00713 // 00714 00715 KeReleaseSpinLock (&CallbackObject->Lock, OldIrql); 00716 }

Generated on Sat May 15 19:39:20 2004 for test by doxygen 1.3.7