1 /*++
2 
3 Copyright (c) Microsoft Corporation
4 
5 Module Name:
6 
7     FxSpinLock.cpp
8 
9 Abstract:
10 
11     This module implements FxSpinLock
12 
13 Author:
14 
15 
16 
17 Environment:
18 
19    Both kernel and user mode
20 
21 Revision History:
22 
23 --*/
24 
25 #include "fxsupportpch.hpp"
26 #include "fxspinlock.hpp"
27 
28 extern "C" {
29 // #include "FxSpinLock.tmh"
30 }
31 
32 FxSpinLock::FxSpinLock(
33     __in PFX_DRIVER_GLOBALS FxDriverGlobals,
34     __in USHORT ExtraSize
35     ) :
36     FxObject(FX_TYPE_SPIN_LOCK, COMPUTE_OBJECT_SIZE(sizeof(FxSpinLock), ExtraSize), FxDriverGlobals)
37 {
38     FX_SPIN_LOCK_HISTORY* pHistory;
39 
40     m_Irql = 0;
41     m_InterruptLock = FALSE;
42 
43     pHistory = GetHistory();
44 
45     if (pHistory != NULL) {
46         RtlZeroMemory(pHistory, sizeof(FX_SPIN_LOCK_HISTORY));
47 
48         pHistory->CurrentHistory = &pHistory->History[0];
49     }
50 }
51 
52 
53 __drv_raisesIRQL(DISPATCH_LEVEL)
54 __drv_maxIRQL(DISPATCH_LEVEL)
55 VOID
56 FxSpinLock::AcquireLock(
57     __in PVOID CallersAddress
58     )
59 {
60     PFX_SPIN_LOCK_HISTORY pHistory;
61     KIRQL irql;
62 
63     m_SpinLock.Acquire(&irql);
64 
65     m_Irql = irql;
66 
67     pHistory = GetHistory();
68 
69     if (pHistory != NULL) {
70         PFX_SPIN_LOCK_HISTORY_ENTRY pCur;
71 
72         //
73         // This assert should never fire here, but this helps track ownership
74         // in the case of a release without an acquire.
75         //
76         ASSERT(pHistory->OwningThread == NULL);
77         pHistory->OwningThread = Mx::MxGetCurrentThread();
78 
79         pCur = pHistory->CurrentHistory;
80 
81         Mx::MxQueryTickCount(&pCur->AcquiredAtTime);
82         pCur->CallersAddress = CallersAddress;
83     }
84 }
85 
86 __drv_requiresIRQL(DISPATCH_LEVEL)
87 VOID
88 FxSpinLock::ReleaseLock(
89     VOID
90     )
91 {
92     PFX_SPIN_LOCK_HISTORY pHistory;
93 
94     pHistory = GetHistory();
95 
96     if (pHistory != NULL) {
97         LARGE_INTEGER now;
98         PFX_SPIN_LOCK_HISTORY_ENTRY pCur;
99 
100         if (pHistory->OwningThread != Mx::MxGetCurrentThread()) {
101             if (pHistory->OwningThread == NULL) {
102                 DoTraceLevelMessage(
103                     GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGERROR,
104                     "WDFSPINLOCK %p being released by thread 0x%p, but was "
105                     "never acquired!", GetObjectHandle(), Mx::MxGetCurrentThread());
106             }
107             else {
108                 DoTraceLevelMessage(
109                     GetDriverGlobals(), TRACE_LEVEL_ERROR, TRACINGERROR,
110                     "WDFSPINLOCK 0x%p not owned by thread 0x%p, owned by thread 0x%p",
111                     GetObjectHandle(), Mx::MxGetCurrentThread(),
112                     pHistory->OwningThread);
113             }
114 
115             FxVerifierBugCheck(GetDriverGlobals(),
116                                WDF_INVALID_LOCK_OPERATION,
117                                (ULONG_PTR) GetObjectHandle(),
118                                0x1);
119             //
120             // Will not get here
121             //
122             return;
123         }
124 
125         ASSERT(pHistory->OwningThread != NULL);
126 
127         Mx::MxQueryTickCount(&now);
128 
129         pCur = pHistory->CurrentHistory;
130         pCur->LockedDuraction = now.QuadPart - pCur->AcquiredAtTime.QuadPart;
131 
132         pHistory->CurrentHistory++;
133         if (pHistory->CurrentHistory >=
134             pHistory->History + FX_SPIN_LOCK_NUM_HISTORY_ENTRIES) {
135             pHistory->CurrentHistory = pHistory->History;
136         }
137 
138         pHistory->OwningThread = NULL;
139     }
140 
141     m_SpinLock.Release(m_Irql);
142 }
143