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