1 /*++ 2 3 Copyright (c) Microsoft Corporation 4 5 Module Name: 6 7 FxVerifierLock.cpp 8 9 Abstract: 10 11 This module contains the implementation of the verifier lock 12 13 Author: 14 15 16 17 18 Environment: 19 20 Both kernel and user mode 21 22 Revision History: 23 24 25 26 27 --*/ 28 29 #include "fxobjectpch.hpp" 30 31 extern "C" { 32 #if defined(EVENT_TRACING) 33 #include "FxVerifierLock.tmh" 34 #endif 35 } 36 37 // 38 // Mapping table structure between Fx object types and lock orders 39 // 40 FxVerifierOrderMapping FxVerifierOrderTable[] = { 41 42 // Table is defined in fx\inc\FxVerifierLock.hpp 43 FX_VERIFIER_LOCK_ENTRIES() 44 }; 45 46 FxVerifierOrderMapping FxVerifierCallbackOrderTable[] = { 47 48 // Table is defined in fx\inc\FxVerifierLock.hpp 49 FX_VERIFIER_CALLBACKLOCK_ENTRIES() 50 }; 51 52 // 53 // Organization of verifier lock structures 54 // 55 // As locks are acquired, they are added to the head of a list of locks held 56 // by the current thread if equal, or higher than the lock 57 // at the current list head. 58 // 59 // The hierachy of locks acquired by a thread is seperate for dispatch level 60 // (spinlock) and passive level (mutex) locks. These locks can not be mixed 61 // since holding a mutex lock does not prevent a DPC from interrupting the 62 // thread and properly acquiring a spinlock, which could appear to be 63 // of an improper level, giving a false report. 64 // 65 // In order to prevent memory allocations (which can fail) when locks are 66 // acquired, each FxVerifierLock structure contains members required to chain 67 // locks that are held on a per thread basis. (m_OwnedLink) 68 // 69 // Since we have no way of knowing the number of unique PETHREADS that may 70 // be holding locks at any time, a fixed size hash table is allocated 71 // and PETHREAD values are hashed into it, with chaining allowed on 72 // each entry due to overflows and collisions. The storage required for 73 // the hash table entry and chain is also allocated as member fields 74 // of the FxVerifierLock class. (m_ThreadTableEntry) 75 // 76 // The hash table and its chained entries (m_ThreadTableEntry) is protected 77 // by a global spinlock, FxDriverGlobals->ThreadTableLock. 78 // 79 // When a lock is acquired, the current threads address is used to look up 80 // a FxVerifierThreadTableEntry for it in the hash table. 81 // 82 // If one does not exist, this is the start of a new chain of locks for this 83 // ETHREAD, and the m_ThreadTableEntry of the current lock being acquired 84 // is inserted into the hash table, and the new lock chain is started using 85 // either the 86 // FxVerifierThreadTableEntry::PerThreadPassiveLockList, or 87 // FxVerifierThreadTableEntry::PerThreadDispatchLockList. 88 // 89 // If an entry does exist, the current lock is added to the head of 90 // the list in the existing entry. 91 // 92 // On lock release, the lock is identified in the list of held locks, 93 // which may not be the head if release was out of order (this is allowed), 94 // and removed from the list. 95 // 96 // If the list of locks held by the current thread is NULL for both 97 // the passive and dispatch lists, the threads entry is removed from 98 // the hash table since the thread no longer holds any locks. 99 // 100 // If either of these lists is not NULL, then the entries in the 101 // current locks FxVerifierThreadTableEntry is copied into one 102 // of the other locks on the new list head and the hash table 103 // is updated to point to the new entry. 104 // 105 // This is because the released FxVerifierLock entry may be freed 106 // as a result of its containing data structure being run down. 107 // 108 109 // 110 // Method Definitions 111 // 112 113 // 114 // Called at Driver Frameworks init time 115 // 116 extern "C" 117 void 118 FxVerifierLockInitialize( 119 __in PFX_DRIVER_GLOBALS FxDriverGlobals 120 ) 121 { 122 if( FxDriverGlobals->FxVerifierLock ) { 123 124 FxDriverGlobals->ThreadTableLock.Initialize(); 125 126 FxVerifierLock::AllocateThreadTable(FxDriverGlobals); 127 } 128 129 return; 130 } 131 132 // 133 // Called at Driver Frameworks is unloading 134 // 135 extern "C" 136 void 137 FxVerifierLockDestroy( 138 __in PFX_DRIVER_GLOBALS FxDriverGlobals 139 ) 140 { 141 if( FxDriverGlobals->FxVerifierLock ) { 142 FxVerifierLock::FreeThreadTable(FxDriverGlobals); 143 144 FxDriverGlobals->ThreadTableLock.Uninitialize(); 145 } 146 147 return; 148 } 149 150 VOID 151 FxVerifierLock::Lock( 152 __out PKIRQL PreviousIrql, 153 __in BOOLEAN AtDpc 154 ) 155 { 156 MxThread curThread; 157 FxVerifierLock* head; 158 pFxVerifierThreadTableEntry perThreadList; 159 KIRQL oldIrql = PASSIVE_LEVEL; 160 161 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 162 163 curThread = Mx::MxGetCurrentThread(); 164 165 // 166 // First check to see if the lock is already 167 // owned. 168 // 169 // This check is race free since this can only be set 170 // to our thread from under the spinlock, and is cleared 171 // before release. 172 // 173 174 if( m_OwningThread == curThread ) { 175 176 DoTraceLevelMessage( 177 FxDriverGlobals, TRACE_LEVEL_FATAL, TRACINGDEVICE, 178 "Thread 0x%p already owns lock 0x%p for object 0x%p, WDFOBJECT 0x%p", 179 curThread, this, m_ParentObject, m_ParentObject->GetObjectHandle()); 180 181 FxVerifierBugCheck( FxDriverGlobals, 182 WDF_RECURSIVE_LOCK, 183 (ULONG_PTR) m_ParentObject->GetObjectHandle(), 184 (ULONG_PTR) this); 185 } 186 187 if( m_UseMutex ) { 188 // Get the Mutex 189 Mx::MxEnterCriticalRegion(); 190 m_Mutex.AcquireUnsafe(); 191 192 *PreviousIrql = Mx::MxGetCurrentIrql(); 193 } 194 else if (AtDpc) { 195 // Get the spinlock 196 m_Lock.AcquireAtDpcLevel(); 197 m_OldIrql = DISPATCH_LEVEL; 198 199 *PreviousIrql = m_OldIrql; 200 } 201 else { 202 // Try to force a thread switch to catch synchronization errors 203 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 204 LARGE_INTEGER sleepTime; 205 206 sleepTime.QuadPart = 0; 207 Mx::MxDelayExecutionThread(KernelMode, TRUE, &sleepTime); 208 } 209 210 // Get the spinlock using a local since KeAcquireSpinLock might use this 211 // var as temp space while spinning and we would then corrupt it if 212 // the owning thread used it in the middle of the spin. 213 // 214 m_Lock.Acquire(PreviousIrql); 215 m_OldIrql = *PreviousIrql; 216 } 217 218 // Lock the verifier lists 219 if (m_UseMutex) { 220 FxDriverGlobals->ThreadTableLock.Acquire(&oldIrql); 221 } 222 else { 223 FxDriverGlobals->ThreadTableLock.AcquireAtDpcLevel(); 224 } 225 226 m_OwningThread = curThread; 227 228 // Get our per thread list from the thread table 229 perThreadList = FxVerifierLock::GetThreadTableEntry(curThread, this, FALSE); 230 if( perThreadList == NULL ) { 231 232 if (m_UseMutex) { 233 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 234 } 235 else { 236 FxDriverGlobals->ThreadTableLock.ReleaseFromDpcLevel(); 237 } 238 239 // Can't get an entry, so return 240 return; 241 } 242 243 // 244 // There are seperately sorted lists for passive and dispatch 245 // level locks since dispatch level locks of a lower level can interrupt a 246 // higher passive level lock, giving a false report. 247 // 248 if( m_UseMutex ) { 249 head = perThreadList->PerThreadPassiveLockList; 250 } 251 else { 252 head = perThreadList->PerThreadDispatchLockList; 253 } 254 255 if( head != NULL ) { 256 257 // Validate current is > head 258 if( m_Order > head->m_Order ) { 259 m_OwnedLink = head; 260 //perThreadList->PerThreadLockList = this; 261 } 262 else if( m_Order == head->m_Order ) { 263 264 // Place at head if the same lock level as current head 265 m_OwnedLink = head; 266 //perThreadList->PerThreadLockList = this; 267 } 268 else { 269 270 // Lock violation, m_Order < head->m_Order 271 FxVerifierLock::DumpDetails(this, curThread, head); 272 273 // 274 // Caller is feeling lucky and resumed so place it at the head 275 // to keep our lists intact 276 // 277 m_OwnedLink = head; 278 //perThreadList->PerThreadLockList = this; 279 } 280 } 281 else { 282 this->m_OwnedLink = NULL; 283 //perThreadList->PerThreadLockList = this; 284 } 285 286 // 287 // Update to the next list head 288 // 289 if (m_UseMutex) { 290 perThreadList->PerThreadPassiveLockList = this; 291 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 292 } 293 else { 294 perThreadList->PerThreadDispatchLockList = this; 295 FxDriverGlobals->ThreadTableLock.ReleaseFromDpcLevel(); 296 } 297 298 return; 299 } 300 301 void 302 FxVerifierLock::Unlock( 303 __in KIRQL PreviousIrql, 304 __in BOOLEAN AtDpc 305 ) 306 { 307 MxThread curThread; 308 pFxVerifierThreadTableEntry perThreadList; 309 KIRQL oldIrql; 310 311 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 312 313 // Only from DISPATCH_LEVEL or below 314 curThread = Mx::MxGetCurrentThread(); 315 316 if( curThread != m_OwningThread ) { 317 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 318 "Thread 0x%p Is Attempting to release a Lock 0x%p " 319 "for Object 0x%p it does not own!", 320 curThread,this,m_ParentObject); 321 FxVerifierDbgBreakPoint(FxDriverGlobals); 322 return; 323 } 324 325 // Lock the verifier lists 326 FxDriverGlobals->ThreadTableLock.Acquire(&oldIrql); 327 328 // Get our per thread list from the thread table 329 perThreadList = FxVerifierLock::GetThreadTableEntry(m_OwningThread, this, TRUE); 330 if( perThreadList == NULL ) { 331 332 // Can't get our entry, so release the spinlock and return 333 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 334 "Unlock: Can't get per thread entry for thread %p", 335 curThread); 336 337 m_OwningThread = NULL; 338 339 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 340 341 if (m_UseMutex) { 342 m_Mutex.ReleaseUnsafe(); 343 Mx::MxLeaveCriticalRegion(); 344 } 345 else if (AtDpc) { 346 m_Lock.ReleaseFromDpcLevel(); 347 } 348 else { 349 m_Lock.Release(PreviousIrql); 350 351 // Try to force a thread switch to catch synchronization errors 352 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 353 LARGE_INTEGER sleepTime; 354 355 sleepTime.QuadPart = 0; 356 Mx::MxDelayExecutionThread(KernelMode, TRUE, &sleepTime); 357 } 358 } 359 return; 360 } 361 362 if( m_UseMutex ) { 363 if( perThreadList->PerThreadPassiveLockList == NULL ) { 364 // Problem with verifier 365 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 366 "Thread has entry, but no locks recorded as " 367 "held for passive!"); 368 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 369 "this 0x%p, perThreadList 0x%p", 370 this, perThreadList); 371 FxVerifierDbgBreakPoint(FxDriverGlobals); 372 373 m_OwningThread = NULL; 374 375 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 376 377 m_Mutex.ReleaseUnsafe(); 378 Mx::MxLeaveCriticalRegion(); 379 380 return; 381 } 382 } 383 else { 384 if( perThreadList->PerThreadDispatchLockList == NULL ) { 385 // Problem with verifier 386 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 387 "Thread has entry, but no locks recorded as held " 388 "for dispatch!"); 389 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 390 "this 0x%p, perThreadList 0x%p", 391 this, perThreadList); 392 FxVerifierDbgBreakPoint(FxDriverGlobals); 393 394 m_OwningThread = NULL; 395 396 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 397 398 if (AtDpc) { 399 m_Lock.ReleaseFromDpcLevel(); 400 } 401 else { 402 m_Lock.Release(PreviousIrql); 403 404 // Try to force a thread switch to catch synchronization errors 405 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 406 LARGE_INTEGER sleepTime; 407 408 sleepTime.QuadPart = 0; 409 Mx::MxDelayExecutionThread(KernelMode, TRUE, &sleepTime); 410 } 411 } 412 413 return; 414 } 415 } 416 417 if( m_UseMutex ) { 418 419 // Common case is a nested release 420 if( perThreadList->PerThreadPassiveLockList == this ) { 421 422 perThreadList->PerThreadPassiveLockList = this->m_OwnedLink; 423 m_OwnedLink = NULL; 424 425 ReleaseOrReplaceThreadTableEntry(curThread, this); 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 } 449 else { 450 // 451 // Releasing out of order does not deadlock as 452 // long as all acquires are in order, but its 453 // not commmon 454 // 455 FxVerifierLock* next; 456 FxVerifierLock* prev = NULL; 457 458 // Skip the first entry checked by the above if 459 prev = perThreadList->PerThreadPassiveLockList; 460 next = perThreadList->PerThreadPassiveLockList->m_OwnedLink; 461 462 while( next != NULL ) { 463 464 if( next == this ) { 465 prev->m_OwnedLink = m_OwnedLink; 466 m_OwnedLink = NULL; 467 468 // 469 // The perThreadList entry may, or may not be the 470 // data structure in this lock. Sinse we are releasing 471 // the lock, this entry can no longer be referenced if 472 // so. 473 // 474 ReleaseOrReplaceThreadTableEntry(curThread, this); 475 476 // FxVerifierLock::ReplaceThreadTableEntry(curThread, this, perThreadList->PerThreadPassiveLockList); 477 478 break; 479 } 480 481 prev = next; 482 next = next->m_OwnedLink; 483 } 484 485 if( next == NULL ) { 486 // Somehow the entry is gone 487 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 488 "Record entry for VerifierLock 0x%p is missing " 489 "on list 0x%p for Thread 0x%p", 490 this,perThreadList,m_OwningThread); 491 FxVerifierDbgBreakPoint(FxDriverGlobals); 492 } 493 } 494 } 495 else { 496 497 // Common case is a nested release 498 if( perThreadList->PerThreadDispatchLockList == this ) { 499 500 perThreadList->PerThreadDispatchLockList = this->m_OwnedLink; 501 m_OwnedLink = NULL; 502 503 ReleaseOrReplaceThreadTableEntry(curThread, this); 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 } 527 else { 528 // 529 // Releasing out of order does not deadlock as 530 // long as all acquires are in order, but its 531 // not commmon 532 // 533 FxVerifierLock* next; 534 FxVerifierLock* prev = NULL; 535 536 // Skip the first entry checked by the above if 537 prev = perThreadList->PerThreadDispatchLockList; 538 next = perThreadList->PerThreadDispatchLockList->m_OwnedLink; 539 540 while( next != NULL ) { 541 542 if( next == this ) { 543 prev->m_OwnedLink = m_OwnedLink; 544 m_OwnedLink = NULL; 545 546 // 547 // The perThreadList entry may, or may not be the 548 // data structure in this lock. Sinse we are releasing 549 // the lock, this entry can no longer be referenced if 550 // so. 551 // 552 ReleaseOrReplaceThreadTableEntry(curThread, this); 553 554 // FxVerifierLock::ReplaceThreadTableEntry(curThread, this, perThreadList->PerThreadDispatchLockList); 555 556 break; 557 } 558 559 prev = next; 560 next = next->m_OwnedLink; 561 } 562 563 if( next == NULL ) { 564 // Somehow the entry is gone 565 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 566 "Record entry for VerifierLock 0x%p is missing " 567 "on list 0x%p for Thread 0x%p", 568 this,perThreadList,m_OwningThread); 569 FxVerifierDbgBreakPoint(FxDriverGlobals); 570 } 571 } 572 573 } 574 575 m_OwningThread = NULL; 576 577 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 578 579 if (m_UseMutex) { 580 m_Mutex.ReleaseUnsafe(); 581 Mx::MxLeaveCriticalRegion(); 582 } 583 else if (AtDpc) { 584 m_Lock.ReleaseFromDpcLevel(); 585 } 586 else { 587 m_Lock.Release(PreviousIrql); 588 589 // Try to force a thread switch to catch synchronization errors 590 if (Mx::MxGetCurrentIrql() == PASSIVE_LEVEL) { 591 LARGE_INTEGER sleepTime; 592 593 sleepTime.QuadPart = 0; 594 Mx::MxDelayExecutionThread(KernelMode, TRUE, &sleepTime); 595 } 596 } 597 598 return; 599 } 600 601 KIRQL 602 FxVerifierLock::GetLockPreviousIrql() 603 { 604 return m_OldIrql; 605 } 606 607 void 608 FxVerifierLock::InitializeLockOrder() 609 { 610 USHORT ObjectType; 611 pFxVerifierOrderMapping p; 612 613 PFX_DRIVER_GLOBALS FxDriverGlobals = GetDriverGlobals(); 614 615 ObjectType = m_ParentObject->GetType(); 616 617 if( m_CallbackLock ) { 618 p = FxVerifierCallbackOrderTable; 619 } 620 else { 621 p = FxVerifierOrderTable; 622 } 623 624 while( p->ObjectType != 0 ) { 625 626 if( p->ObjectType == ObjectType ) { 627 m_Order = p->ObjectLockOrder; 628 return; 629 } 630 631 p++; 632 } 633 634 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 635 "Object Type 0x%x does not have a lock order " 636 "defined in fx\\inc\\FxVerifierLock.hpp", 637 ObjectType); 638 639 m_Order = FX_LOCK_ORDER_UNKNOWN; 640 641 return; 642 } 643 644 // 645 // This looks up the supplied thread in the table, and if 646 // found returns it. 647 // 648 // If no entry for the thread is found, create one using the 649 // m_ThreadTableEntry for the lock. 650 // 651 pFxVerifierThreadTableEntry 652 FxVerifierLock::GetThreadTableEntry( 653 __in MxThread curThread, 654 __in FxVerifierLock* pLock, 655 __in BOOLEAN LookupOnly 656 ) 657 { 658 ULONG Hash, Index; 659 PLIST_ENTRY head, next; 660 FxVerifierLock* entry; 661 662 PFX_DRIVER_GLOBALS FxDriverGlobals = pLock->GetDriverGlobals(); 663 664 // Verifier is off, or an early memory allocation failure 665 if( FxDriverGlobals->ThreadTable == NULL ) { 666 return NULL; 667 } 668 669 // 670 // Hash the KeCurrentThread() information into an table 671 // index. 672 // 673 // Hash takes into account that NT pool items don't use 674 // the lower 4 bits (16 byte boundries) 675 // 676 677 Hash = (ULONG)((ULONG_PTR)curThread >> 4); 678 Hash = ((Hash >> 16) & 0x0000FFFF) ^ (Hash & 0x0000FFFF); 679 680 // 681 // Hash table is maintained as a power of two 682 // 683 Index = Hash & (VERIFIER_THREAD_HASHTABLE_SIZE-1); 684 685 head = &FxDriverGlobals->ThreadTable[Index]; 686 687 // 688 // Walk the list to see if our thread has an entry 689 // 690 next = head->Flink; 691 while( next != head ) { 692 entry = CONTAINING_RECORD(next, FxVerifierLock, m_ThreadTableEntry.HashChain); 693 694 if( entry->m_ThreadTableEntry.Thread == curThread ) { 695 696 //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 697 // "Returning existing Entry 0x%p for Thread 0x%p, " 698 // "Lock 0x%p", 699 // &entry->m_ThreadTableEntry, curThread, pLock); 700 701 return &entry->m_ThreadTableEntry; 702 } 703 704 next = next->Flink; 705 } 706 707 if( LookupOnly ) { 708 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 709 "Thread 0x%p does not have an entry",curThread); 710 FxVerifierDbgBreakPoint(FxDriverGlobals); 711 return NULL; 712 } 713 714 // 715 // The current ETHREAD has no locks it currently holds, so it has 716 // no entry in the hash table. 717 // 718 // Use the supplied locks m_ThreadTableEntry to create an entry 719 // for this ETHREAD and the start of a new list of held locks. 720 // 721 pLock->m_ThreadTableEntry.Thread = curThread; 722 pLock->m_ThreadTableEntry.PerThreadPassiveLockList = NULL; 723 pLock->m_ThreadTableEntry.PerThreadDispatchLockList = NULL; 724 725 InsertTailList(head, &pLock->m_ThreadTableEntry.HashChain); 726 727 // DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 728 // "Returning new Entry 0x%p for Thread 0x%p, Lock 0x%p", 729 // &pLock->m_ThreadTableEntry, curThread, pLock); 730 731 return &pLock->m_ThreadTableEntry; 732 } 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 void 823 FxVerifierLock::ReleaseOrReplaceThreadTableEntry( 824 __in MxThread curThread, 825 __in FxVerifierLock* pLock 826 ) 827 828 /*++ 829 830 Routine Description: 831 832 Removes the use of the supplied locks m_ThreadTableEntry by 833 either releasing it if the ETHREAD is holding no more locks, 834 or by copying it to the m_ThreadTableEntry of another lock 835 held by the thread. 836 837 Arguments: 838 839 curThread - Thread who is holding lock 840 841 pLock - Lock whose m_ThreadTableEntry is to be released 842 843 Returns: 844 845 846 Comments: 847 848 This is called with the verifier hash table lock held 849 FxDriverGlobals->ThreadTableLock. 850 851 The pLock has already been removed from the held locks chain, 852 so the lock at the head of the list can be used for the new hash 853 table entry. 854 855 --*/ 856 857 { 858 ULONG Hash, Index; 859 PLIST_ENTRY head; 860 FxVerifierLock* pNewLock = NULL; 861 862 PFX_DRIVER_GLOBALS FxDriverGlobals = pLock->GetDriverGlobals(); 863 864 if( pLock->m_ThreadTableEntry.Thread == NULL ) { 865 866 // This locks entry is not used for hash chaining 867 //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 868 // "Entry 0x%p Not currently part of the hash chain", 869 // pLock); 870 871 return; 872 } 873 874 // It should be the current thread 875 if( pLock->m_ThreadTableEntry.Thread != curThread ) { 876 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 877 "OldEntry Thread 0x%p not Current! 0x%p", 878 pLock,curThread); 879 FxVerifierDbgBreakPoint(FxDriverGlobals); 880 } 881 882 Hash = (ULONG)((ULONG_PTR)curThread >> 4); 883 Hash = ((Hash >> 16) & 0x0000FFFF) ^ (Hash & 0x0000FFFF); 884 885 Index = Hash & (VERIFIER_THREAD_HASHTABLE_SIZE-1); 886 887 head = &FxDriverGlobals->ThreadTable[Index]; 888 889 // Remove old entry 890 RemoveEntryList(&pLock->m_ThreadTableEntry.HashChain); 891 892 // 893 // If both lock lists are NULL, we can just release the entry 894 // 895 if( (pLock->m_ThreadTableEntry.PerThreadPassiveLockList == NULL) && 896 (pLock->m_ThreadTableEntry.PerThreadDispatchLockList == NULL) ) { 897 898 //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 899 // "Releasing entry for lock 0x%p for Thread 0x%p", 900 // pLock, curThread); 901 902 // This is now an unused entry 903 pLock->m_ThreadTableEntry.Thread = NULL; 904 pLock->m_ThreadTableEntry.PerThreadPassiveLockList = NULL; 905 pLock->m_ThreadTableEntry.PerThreadDispatchLockList = NULL; 906 907 return; 908 } 909 910 //DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 911 // "Replacing Lock 0x%p, for Thread 0x%p", 912 // pLock, curThread); 913 if( pLock->m_ThreadTableEntry.PerThreadPassiveLockList != NULL ) { 914 pNewLock = pLock->m_ThreadTableEntry.PerThreadPassiveLockList; 915 } 916 else { 917 pNewLock = pLock->m_ThreadTableEntry.PerThreadDispatchLockList; 918 } 919 920 ASSERT(pNewLock != NULL); 921 ASSERT(pNewLock->m_ThreadTableEntry.Thread == NULL); 922 ASSERT(pNewLock->m_ThreadTableEntry.PerThreadPassiveLockList == NULL); 923 ASSERT(pNewLock->m_ThreadTableEntry.PerThreadDispatchLockList == NULL); 924 925 // Copy the old lock structures table to the next one 926 pNewLock->m_ThreadTableEntry.Thread = pLock->m_ThreadTableEntry.Thread; 927 pNewLock->m_ThreadTableEntry.PerThreadPassiveLockList = pLock->m_ThreadTableEntry.PerThreadPassiveLockList; 928 pNewLock->m_ThreadTableEntry.PerThreadDispatchLockList = pLock->m_ThreadTableEntry.PerThreadDispatchLockList; 929 930 // Insert new entry at the end of thelist 931 InsertTailList(head, &pNewLock->m_ThreadTableEntry.HashChain); 932 933 return; 934 } 935 936 void 937 FxVerifierLock::AllocateThreadTable( 938 __in PFX_DRIVER_GLOBALS FxDriverGlobals 939 ) 940 { 941 KIRQL oldIrql; 942 ULONG newEntries; 943 PLIST_ENTRY newTable; 944 945 FxDriverGlobals->ThreadTableLock.Acquire(&oldIrql); 946 947 if( FxDriverGlobals->ThreadTable != NULL ) { 948 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 949 return; 950 } 951 952 // Table must be kept as a power of 2 for hash algorithm 953 newEntries = VERIFIER_THREAD_HASHTABLE_SIZE; 954 955 newTable = (PLIST_ENTRY) FxPoolAllocateWithTag( 956 FxDriverGlobals, 957 NonPagedPool, 958 sizeof(LIST_ENTRY) * newEntries, 959 FxDriverGlobals->Tag); 960 961 if( newTable == NULL ) { 962 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 963 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 964 "No Memory to allocate thread table"); 965 return; 966 } 967 968 for(ULONG index=0; index < newEntries; index++ ) { 969 InitializeListHead(&newTable[index]); 970 } 971 972 FxDriverGlobals->ThreadTable = newTable; 973 974 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 975 976 return; 977 } 978 979 void 980 FxVerifierLock::FreeThreadTable( 981 __in PFX_DRIVER_GLOBALS FxDriverGlobals 982 ) 983 { 984 KIRQL oldIrql; 985 986 UNREFERENCED_PARAMETER(FxDriverGlobals); 987 988 FxDriverGlobals->ThreadTableLock.Acquire(&oldIrql); 989 990 if( FxDriverGlobals->ThreadTable == NULL ) { 991 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 992 return; 993 } 994 995 FxPoolFree(FxDriverGlobals->ThreadTable); 996 997 FxDriverGlobals->ThreadTable = NULL; 998 999 FxDriverGlobals->ThreadTableLock.Release(oldIrql); 1000 1001 return; 1002 } 1003 1004 void 1005 FxVerifierLock::DumpDetails( 1006 __in FxVerifierLock* Lock, 1007 __in MxThread curThread, 1008 __in FxVerifierLock* PerThreadList 1009 ) 1010 { 1011 PFX_DRIVER_GLOBALS FxDriverGlobals = Lock->GetDriverGlobals(); 1012 1013 FxVerifierLock* next; 1014 1015 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 1016 "Thread 0x%p Attempted to acquire lock on Object 0x%p, " 1017 "ObjectType 0x%x, at Level 0x%x out of sequence.", 1018 curThread,Lock->m_ParentObject, 1019 Lock->m_ParentObject->GetType(), 1020 Lock->m_Order); 1021 1022 next = PerThreadList; 1023 1024 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 1025 "Highest Lock Currently held is level 0x%x for " 1026 "Object 0x%p, ObjectType 0x%x", 1027 next->m_Order, 1028 next->m_ParentObject, 1029 next->m_ParentObject->GetType()); 1030 1031 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 1032 "List of Already Acquired Locks and Objects:"); 1033 1034 while( next != NULL ) { 1035 1036 DoTraceLevelMessage(FxDriverGlobals, TRACE_LEVEL_ERROR, TRACINGDEVICE, 1037 "Object 0x%p, ObjectType 0x%x, LockLevel 0x%x", 1038 next->m_ParentObject, 1039 next->m_ParentObject->GetType(), 1040 next->m_Order); 1041 1042 next = next->m_OwnedLink; 1043 } 1044 1045 FxVerifierDbgBreakPoint(FxDriverGlobals); 1046 1047 return; 1048 } 1049 1050 1051