Process Hacker
queuedlock.h
Go to the documentation of this file.
1 #ifndef _PH_QUEUEDLOCK_H
2 #define _PH_QUEUEDLOCK_H
3 
4 #ifdef __cplusplus
5 extern "C" {
6 #endif
7 
8 #define PH_QUEUED_LOCK_OWNED ((ULONG_PTR)0x1)
9 #define PH_QUEUED_LOCK_OWNED_SHIFT 0
10 #define PH_QUEUED_LOCK_WAITERS ((ULONG_PTR)0x2)
11 
12 // Valid only if Waiters = 0
13 #define PH_QUEUED_LOCK_SHARED_INC ((ULONG_PTR)0x4)
14 #define PH_QUEUED_LOCK_SHARED_SHIFT 2
15 
16 // Valid only if Waiters = 1
17 #define PH_QUEUED_LOCK_TRAVERSING ((ULONG_PTR)0x4)
18 #define PH_QUEUED_LOCK_MULTIPLE_SHARED ((ULONG_PTR)0x8)
19 
20 #define PH_QUEUED_LOCK_FLAGS ((ULONG_PTR)0xf)
21 
22 #define PhGetQueuedLockSharedOwners(Value) \
23  ((ULONG_PTR)(Value) >> PH_QUEUED_LOCK_SHARED_SHIFT)
24 #define PhGetQueuedLockWaitBlock(Value) \
25  ((PPH_QUEUED_WAIT_BLOCK)((ULONG_PTR)(Value) & ~PH_QUEUED_LOCK_FLAGS))
26 
27 typedef struct _PH_QUEUED_LOCK
28 {
29  ULONG_PTR Value;
31 
32 #define PH_QUEUED_LOCK_INIT { 0 }
33 
34 #define PH_QUEUED_WAITER_EXCLUSIVE 0x1
35 #define PH_QUEUED_WAITER_SPINNING 0x2
36 #define PH_QUEUED_WAITER_SPINNING_SHIFT 1
37 
38 typedef struct DECLSPEC_ALIGN(16) _PH_QUEUED_WAIT_BLOCK
39 {
42  struct _PH_QUEUED_WAIT_BLOCK *Next;
45  struct _PH_QUEUED_WAIT_BLOCK *Previous;
48  struct _PH_QUEUED_WAIT_BLOCK *Last;
49 
50  ULONG SharedOwners;
51  ULONG Flags;
53 
55  VOID
56  );
57 
59  _Out_ PPH_QUEUED_LOCK QueuedLock
60  )
61 {
62  QueuedLock->Value = 0;
63 }
64 
66 VOID
69  _Inout_ PPH_QUEUED_LOCK QueuedLock
70  );
71 
73 VOID
76  _Inout_ PPH_QUEUED_LOCK QueuedLock
77  );
78 
80 VOID
83  _Inout_ PPH_QUEUED_LOCK QueuedLock
84  );
85 
87 VOID
90  _Inout_ PPH_QUEUED_LOCK QueuedLock
91  );
92 
94 VOID
97  _Inout_ PPH_QUEUED_LOCK QueuedLock
98  );
99 
100 PHLIBAPI
101 VOID
102 FASTCALL
104  _Inout_ PPH_QUEUED_LOCK QueuedLock,
105  _In_ ULONG_PTR Value
106  );
107 
108 #define PhPulseCondition PhfPulseCondition
109 PHLIBAPI
110 VOID
111 FASTCALL
113  _Inout_ PPH_QUEUED_LOCK Condition
114  );
115 
116 #define PhPulseAllCondition PhfPulseAllCondition
117 PHLIBAPI
118 VOID
119 FASTCALL
121  _Inout_ PPH_QUEUED_LOCK Condition
122  );
123 
124 #define PhWaitForCondition PhfWaitForCondition
125 PHLIBAPI
126 VOID
127 FASTCALL
129  _Inout_ PPH_QUEUED_LOCK Condition,
130  _Inout_ PPH_QUEUED_LOCK Lock,
131  _In_opt_ PLARGE_INTEGER Timeout
132  );
133 
134 #define PH_CONDITION_WAIT_QUEUED_LOCK 0x1
135 #define PH_CONDITION_WAIT_CRITICAL_SECTION 0x2
136 #define PH_CONDITION_WAIT_FAST_LOCK 0x4
137 #define PH_CONDITION_WAIT_LOCK_TYPE_MASK 0xfff
138 
139 #define PH_CONDITION_WAIT_SHARED 0x1000
140 #define PH_CONDITION_WAIT_SPIN 0x2000
141 
142 #define PhWaitForConditionEx PhfWaitForConditionEx
143 PHLIBAPI
144 VOID
145 FASTCALL
147  _Inout_ PPH_QUEUED_LOCK Condition,
148  _Inout_ PVOID Lock,
149  _In_ ULONG Flags,
150  _In_opt_ PLARGE_INTEGER Timeout
151  );
152 
153 #define PhQueueWakeEvent PhfQueueWakeEvent
154 PHLIBAPI
155 VOID
156 FASTCALL
158  _Inout_ PPH_QUEUED_LOCK WakeEvent,
159  _Out_ PPH_QUEUED_WAIT_BLOCK WaitBlock
160  );
161 
162 PHLIBAPI
163 VOID
164 FASTCALL
166  _Inout_ PPH_QUEUED_LOCK WakeEvent,
167  _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock
168  );
169 
170 #define PhWaitForWakeEvent PhfWaitForWakeEvent
171 PHLIBAPI
172 NTSTATUS
173 FASTCALL
175  _Inout_ PPH_QUEUED_LOCK WakeEvent,
176  _Inout_ PPH_QUEUED_WAIT_BLOCK WaitBlock,
177  _In_ BOOLEAN Spin,
178  _In_opt_ PLARGE_INTEGER Timeout
179  );
180 
181 // Inline functions
182 
183 _Acquires_exclusive_lock_(*QueuedLock)
185  _Inout_ PPH_QUEUED_LOCK QueuedLock
186  )
187 {
188  if (_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))
189  {
190  // Owned bit was already set. Slow path.
191  PhfAcquireQueuedLockExclusive(QueuedLock);
192  }
193 }
194 
195 _Acquires_shared_lock_(*QueuedLock)
197  _Inout_ PPH_QUEUED_LOCK QueuedLock
198  )
199 {
200  if ((ULONG_PTR)_InterlockedCompareExchangePointer(
201  (PVOID *)&QueuedLock->Value,
203  (PVOID)0
204  ) != 0)
205  {
206  PhfAcquireQueuedLockShared(QueuedLock);
207  }
208 }
209 
210 _When_(return != 0, _Acquires_exclusive_lock_(*QueuedLock))
211 FORCEINLINE BOOLEAN PhTryAcquireQueuedLockExclusive(
212  _Inout_ PPH_QUEUED_LOCK QueuedLock
213  )
214 {
215  if (!_InterlockedBitTestAndSetPointer((PLONG_PTR)&QueuedLock->Value, PH_QUEUED_LOCK_OWNED_SHIFT))
216  {
217  return TRUE;
218  }
219  else
220  {
221  return FALSE;
222  }
223 }
224 
225 _Releases_exclusive_lock_(*QueuedLock)
227  _Inout_ PPH_QUEUED_LOCK QueuedLock
228  )
229 {
230  ULONG_PTR value;
231 
232  value = (ULONG_PTR)_InterlockedExchangeAddPointer((PLONG_PTR)&QueuedLock->Value, -(LONG_PTR)PH_QUEUED_LOCK_OWNED);
233 
235  {
237  }
238 }
239 
240 _Releases_shared_lock_(*QueuedLock)
242  _Inout_ PPH_QUEUED_LOCK QueuedLock
243  )
244 {
245  ULONG_PTR value;
246 
248 
249  if ((ULONG_PTR)_InterlockedCompareExchangePointer(
250  (PVOID *)&QueuedLock->Value,
251  (PVOID)0,
252  (PVOID)value
253  ) != value)
254  {
255  PhfReleaseQueuedLockShared(QueuedLock);
256  }
257 }
258 
260  _Inout_ PPH_QUEUED_LOCK QueuedLock
261  )
262 {
263  BOOLEAN owned;
264 
265  MemoryBarrier();
266  owned = !!(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);
267  MemoryBarrier();
268 
269  if (owned)
270  {
271  PhAcquireQueuedLockExclusive(QueuedLock);
272  PhReleaseQueuedLockExclusive(QueuedLock);
273  }
274 }
275 
277  _Inout_ PPH_QUEUED_LOCK QueuedLock
278  )
279 {
280  BOOLEAN owned;
281 
282  // Need two memory barriers because we don't want the
283  // compiler re-ordering the following check in either
284  // direction.
285  MemoryBarrier();
286  owned = !(QueuedLock->Value & PH_QUEUED_LOCK_OWNED);
287  MemoryBarrier();
288 
289  return owned;
290 }
291 
292 FORCEINLINE VOID PhSetWakeEvent(
293  _Inout_ PPH_QUEUED_LOCK WakeEvent,
294  _Inout_opt_ PPH_QUEUED_WAIT_BLOCK WaitBlock
295  )
296 {
297  // The wake event is similar to a synchronization event
298  // in that it does not have thread-safe pulsing; we can
299  // simply skip the function call if there's nothing to
300  // wake. However, if we're cancelling a wait
301  // (WaitBlock != NULL) we need to make the call.
302 
303  if (WakeEvent->Value || WaitBlock)
304  PhfSetWakeEvent(WakeEvent, WaitBlock);
305 }
306 
307 #ifdef __cplusplus
308 }
309 #endif
310 
311 #endif