Process Hacker
fastlock.c
Go to the documentation of this file.
1 /*
2  * Process Hacker -
3  * fast resource lock
4  *
5  * Copyright (C) 2009-2010 wj32
6  *
7  * This file is part of Process Hacker.
8  *
9  * Process Hacker is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * Process Hacker is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with Process Hacker. If not, see <http://www.gnu.org/licenses/>.
21  */
22 
23 #include <phbase.h>
24 
25 // FastLock is a port of FastResourceLock from PH 1.x.
26 //
27 // The code contains no comments because it is a direct
28 // port. Please see FastResourceLock.cs in PH 1.x for
29 // details.
30 
31 // The fast lock is around 7% faster than the critical
32 // section when there is no contention, when used
33 // solely for mutual exclusion. It is also much smaller
34 // than the critical section.
35 
36 #define PH_LOCK_OWNED 0x1
37 #define PH_LOCK_EXCLUSIVE_WAKING 0x2
38 
39 #define PH_LOCK_SHARED_OWNERS_SHIFT 2
40 #define PH_LOCK_SHARED_OWNERS_MASK 0x3ff
41 #define PH_LOCK_SHARED_OWNERS_INC 0x4
42 
43 #define PH_LOCK_SHARED_WAITERS_SHIFT 12
44 #define PH_LOCK_SHARED_WAITERS_MASK 0x3ff
45 #define PH_LOCK_SHARED_WAITERS_INC 0x1000
46 
47 #define PH_LOCK_EXCLUSIVE_WAITERS_SHIFT 22
48 #define PH_LOCK_EXCLUSIVE_WAITERS_MASK 0x3ff
49 #define PH_LOCK_EXCLUSIVE_WAITERS_INC 0x400000
50 
51 #define PH_LOCK_EXCLUSIVE_MASK \
52  (PH_LOCK_EXCLUSIVE_WAKING | \
53  (PH_LOCK_EXCLUSIVE_WAITERS_MASK << PH_LOCK_EXCLUSIVE_WAITERS_SHIFT))
54 
56  _Out_ PPH_FAST_LOCK FastLock
57  )
58 {
59  FastLock->Value = 0;
60  FastLock->ExclusiveWakeEvent = NULL;
61  FastLock->SharedWakeEvent = NULL;
62 }
63 
65  _Inout_ PPH_FAST_LOCK FastLock
66  )
67 {
68  if (FastLock->ExclusiveWakeEvent)
69  {
70  NtClose(FastLock->ExclusiveWakeEvent);
71  FastLock->ExclusiveWakeEvent = NULL;
72  }
73 
74  if (FastLock->SharedWakeEvent)
75  {
76  NtClose(FastLock->SharedWakeEvent);
77  FastLock->SharedWakeEvent = NULL;
78  }
79 }
80 
82  _Inout_ PHANDLE Handle
83  )
84 {
85  HANDLE handle;
86 
87  if (*Handle != NULL)
88  return;
89 
90  NtCreateSemaphore(&handle, SEMAPHORE_ALL_ACCESS, NULL, 0, MAXLONG);
91 
93  Handle,
94  handle,
95  NULL
96  ) != NULL)
97  {
98  NtClose(handle);
99  }
100 }
101 
102 FORCEINLINE ULONG PhpGetSpinCount(
103  VOID
104  )
105 {
107  return 4000;
108  else
109  return 0;
110 }
111 
113  _Inout_ PPH_FAST_LOCK FastLock
114  )
115 {
116  ULONG value;
117  ULONG i = 0;
118  ULONG spinCount;
119 
120  spinCount = PhpGetSpinCount();
121 
122  while (TRUE)
123  {
124  value = FastLock->Value;
125 
126  if (!(value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING)))
127  {
128  if (_InterlockedCompareExchange(
129  &FastLock->Value,
130  value + PH_LOCK_OWNED,
131  value
132  ) == value)
133  break;
134  }
135  else if (i >= spinCount)
136  {
137  PhpEnsureEventCreated(&FastLock->ExclusiveWakeEvent);
138 
139  if (_InterlockedCompareExchange(
140  &FastLock->Value,
142  value
143  ) == value)
144  {
145  if (NtWaitForSingleObject(
146  FastLock->ExclusiveWakeEvent,
147  FALSE,
148  NULL
149  ) != STATUS_WAIT_0)
150  PhRaiseStatus(STATUS_UNSUCCESSFUL);
151 
152  do
153  {
154  value = FastLock->Value;
155  } while (_InterlockedCompareExchange(
156  &FastLock->Value,
158  value
159  ) != value);
160 
161  break;
162  }
163  }
164 
165  i++;
166  YieldProcessor();
167  }
168 }
169 
171  _Inout_ PPH_FAST_LOCK FastLock
172  )
173 {
174  ULONG value;
175  ULONG i = 0;
176  ULONG spinCount;
177 
178  spinCount = PhpGetSpinCount();
179 
180  while (TRUE)
181  {
182  value = FastLock->Value;
183 
184  if (!(value & (
185  PH_LOCK_OWNED |
188  )))
189  {
190  if (_InterlockedCompareExchange(
191  &FastLock->Value,
193  value
194  ) == value)
195  break;
196  }
197  else if (
198  (value & PH_LOCK_OWNED) &&
200  !(value & PH_LOCK_EXCLUSIVE_MASK)
201  )
202  {
203  if (_InterlockedCompareExchange(
204  &FastLock->Value,
206  value
207  ) == value)
208  break;
209  }
210  else if (i >= spinCount)
211  {
212  PhpEnsureEventCreated(&FastLock->SharedWakeEvent);
213 
214  if (_InterlockedCompareExchange(
215  &FastLock->Value,
217  value
218  ) == value)
219  {
220  if (NtWaitForSingleObject(
221  FastLock->SharedWakeEvent,
222  FALSE,
223  NULL
224  ) != STATUS_WAIT_0)
225  PhRaiseStatus(STATUS_UNSUCCESSFUL);
226 
227  continue;
228  }
229  }
230 
231  i++;
232  YieldProcessor();
233  }
234 }
235 
237  _Inout_ PPH_FAST_LOCK FastLock
238  )
239 {
240  ULONG value;
241 
242  while (TRUE)
243  {
244  value = FastLock->Value;
245 
247  {
248  if (_InterlockedCompareExchange(
249  &FastLock->Value,
251  value
252  ) == value)
253  {
254  NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL);
255 
256  break;
257  }
258  }
259  else
260  {
261  ULONG sharedWaiters;
262 
263  sharedWaiters = (value >> PH_LOCK_SHARED_WAITERS_SHIFT) & PH_LOCK_SHARED_WAITERS_MASK;
264 
265  if (_InterlockedCompareExchange(
266  &FastLock->Value,
268  value
269  ) == value)
270  {
271  if (sharedWaiters)
272  NtReleaseSemaphore(FastLock->SharedWakeEvent, sharedWaiters, 0);
273 
274  break;
275  }
276  }
277 
278  YieldProcessor();
279  }
280 }
281 
283  _Inout_ PPH_FAST_LOCK FastLock
284  )
285 {
286  ULONG value;
287 
288  while (TRUE)
289  {
290  value = FastLock->Value;
291 
293  {
294  if (_InterlockedCompareExchange(
295  &FastLock->Value,
297  value
298  ) == value)
299  break;
300  }
302  {
303  if (_InterlockedCompareExchange(
304  &FastLock->Value,
307  value
308  ) == value)
309  {
310  NtReleaseSemaphore(FastLock->ExclusiveWakeEvent, 1, NULL);
311 
312  break;
313  }
314  }
315  else
316  {
317  if (_InterlockedCompareExchange(
318  &FastLock->Value,
320  value
321  ) == value)
322  break;
323  }
324 
325  YieldProcessor();
326  }
327 }
328 
330  _Inout_ PPH_FAST_LOCK FastLock
331  )
332 {
333  ULONG value;
334 
335  value = FastLock->Value;
336 
337  if (value & (PH_LOCK_OWNED | PH_LOCK_EXCLUSIVE_WAKING))
338  return FALSE;
339 
340  return _InterlockedCompareExchange(
341  &FastLock->Value,
342  value + PH_LOCK_OWNED,
343  value
344  ) == value;
345 }
346 
348  _Inout_ PPH_FAST_LOCK FastLock
349  )
350 {
351  ULONG value;
352 
353  value = FastLock->Value;
354 
355  if (value & PH_LOCK_EXCLUSIVE_MASK)
356  return FALSE;
357 
358  if (!(value & PH_LOCK_OWNED))
359  {
360  return _InterlockedCompareExchange(
361  &FastLock->Value,
362  value + PH_LOCK_OWNED + PH_LOCK_SHARED_OWNERS_INC,
363  value
364  ) == value;
365  }
367  {
368  return _InterlockedCompareExchange(
369  &FastLock->Value,
371  value
372  ) == value;
373  }
374  else
375  {
376  return FALSE;
377  }
378 }