ReactOS  0.4.15-dev-3297-g037c744
spinlock.c
Go to the documentation of this file.
1 /*
2  * PROJECT: ReactOS Kernel
3  * LICENSE: GPL - See COPYING in the top level directory
4  * FILE: ntoskrnl/ke/spinlock.c
5  * PURPOSE: Spinlock and Queued Spinlock Support
6  * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 #define LQ_WAIT 1
16 #define LQ_OWN 2
17 
18 /* PRIVATE FUNCTIONS *********************************************************/
19 
20 #if 0
21 //
22 // FIXME: The queued spinlock routines are broken.
23 //
24 
25 VOID
27 KeAcquireQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
28 {
29 #ifdef CONFIG_SMP
30  PKSPIN_LOCK_QUEUE Prev;
31 
32  /* Set the new lock */
33  Prev = (PKSPIN_LOCK_QUEUE)
35  (LONG)LockHandle);
36  if (!Prev)
37  {
38  /* There was nothing there before. We now own it */
39  *LockHandle->Lock |= LQ_OWN;
40  return;
41  }
42 
43  /* Set the wait flag */
44  *LockHandle->Lock |= LQ_WAIT;
45 
46  /* Link us */
48 
49  /* Loop and wait */
50  while (*LockHandle->Lock & LQ_WAIT)
52 #endif
53 }
54 
55 VOID
57 KeReleaseQueuedSpinLockFromDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
58 {
59 #ifdef CONFIG_SMP
60  KSPIN_LOCK LockVal;
61  PKSPIN_LOCK_QUEUE Waiter;
62 
63  /* Remove own and wait flags */
64  *LockHandle->Lock &= ~(LQ_OWN | LQ_WAIT);
65  LockVal = *LockHandle->Lock;
66 
67  /* Check if we already own it */
68  if (LockVal == (KSPIN_LOCK)LockHandle)
69  {
70  /* Disown it */
71  LockVal = (KSPIN_LOCK)
73  NULL,
74  LockHandle);
75  }
76  if (LockVal == (KSPIN_LOCK)LockHandle) return;
77 
78  /* Need to wait for it */
79  Waiter = LockHandle->Next;
80  while (!Waiter)
81  {
83  Waiter = LockHandle->Next;
84  }
85 
86  /* It's gone */
87  *(ULONG_PTR*)&Waiter->Lock ^= (LQ_OWN | LQ_WAIT);
88  LockHandle->Next = NULL;
89 #endif
90 }
91 
92 #else
93 //
94 // HACK: Hacked to work like normal spinlocks
95 //
96 
100 VOID
101 FASTCALL
102 KeAcquireQueuedSpinLockAtDpcLevel(_Inout_ PKSPIN_LOCK_QUEUE LockHandle)
103 {
104 #if defined(CONFIG_SMP) || DBG
105  /* Make sure we are at DPC or above! */
107  {
108  /* We aren't -- bugcheck */
109  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
110  (ULONG_PTR)LockHandle->Lock,
112  0,
113  0);
114  }
115 #endif
116 
117  /* Do the inlined function */
118  KxAcquireSpinLock(LockHandle->Lock);
119 }
120 
124 VOID
125 FASTCALL
126 KeReleaseQueuedSpinLockFromDpcLevel(_Inout_ PKSPIN_LOCK_QUEUE LockHandle)
127 {
128 #if defined(CONFIG_SMP) || DBG
129  /* Make sure we are at DPC or above! */
131  {
132  /* We aren't -- bugcheck */
133  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
134  (ULONG_PTR)LockHandle->Lock,
136  0,
137  0);
138  }
139 #endif
140 
141  /* Do the inlined function */
142  KxReleaseSpinLock(LockHandle->Lock);
143 }
144 
145 #endif
146 
147 /* PUBLIC FUNCTIONS **********************************************************/
148 
149 /*
150  * @implemented
151  */
152 KIRQL
153 NTAPI
155 {
156  KIRQL OldIrql;
157 
158  /* Raise IRQL */
159  KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
160 
161  /* Acquire spinlock on MP */
163  return OldIrql;
164 }
165 
166 /*
167  * @implemented
168  */
169 VOID
170 NTAPI
172  IN KIRQL OldIrql)
173 {
174  /* Release lock on MP */
176 
177  /* Lower IRQL */
179 }
180 
181 /*
182  * @implemented
183  */
184 VOID
185 NTAPI
187 {
188  /* Clear it */
189  *SpinLock = 0;
190 }
191 
192 /*
193  * @implemented
194  */
195 #undef KeAcquireSpinLockAtDpcLevel
196 VOID
197 NTAPI
199 {
200  /* Make sure we are at DPC or above! */
202  {
203  /* We aren't -- bugcheck */
204  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
207  0,
208  0);
209  }
210 
211  /* Do the inlined function */
212  KxAcquireSpinLock(SpinLock);
213 }
214 
215 /*
216  * @implemented
217  */
218 #undef KeReleaseSpinLockFromDpcLevel
219 VOID
220 NTAPI
222 {
223  /* Make sure we are at DPC or above! */
225  {
226  /* We aren't -- bugcheck */
227  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
230  0,
231  0);
232  }
233 
234  /* Do the inlined function */
235  KxReleaseSpinLock(SpinLock);
236 }
237 
238 /*
239  * @implemented
240  */
241 VOID
242 FASTCALL
244 {
245  /* Make sure we are at DPC or above! */
247  {
248  /* We aren't -- bugcheck */
249  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
252  0,
253  0);
254  }
255 
256  /* Do the inlined function */
257  KxAcquireSpinLock(SpinLock);
258 }
259 
260 /*
261  * @implemented
262  */
263 VOID
264 FASTCALL
266 {
267  /* Make sure we are at DPC or above! */
269  {
270  /* We aren't -- bugcheck */
271  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
274  0,
275  0);
276  }
277 
278  /* Do the inlined function */
279  KxReleaseSpinLock(SpinLock);
280 }
281 
282 /*
283  * @implemented
284  */
285 VOID
286 FASTCALL
288 {
289  /* Do the inlined function */
290  KxAcquireSpinLock(SpinLock);
291 }
292 
293 /*
294  * @implemented
295  */
296 VOID
297 FASTCALL
299 {
300  /* Do the inlined function */
301  KxReleaseSpinLock(SpinLock);
302 }
303 
304 /*
305  * @implemented
306  */
307 BOOLEAN
308 FASTCALL
310 {
311 #if DBG
312  /* Make sure we are at DPC or above! */
314  {
315  /* We aren't -- bugcheck */
316  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
319  0,
320  0);
321  }
322 
323  /* Make sure that we don't own the lock already */
324  if (((KSPIN_LOCK)KeGetCurrentThread() | 1) == *SpinLock)
325  {
326  /* We do, bugcheck! */
327  KeBugCheckEx(SPIN_LOCK_ALREADY_OWNED, (ULONG_PTR)SpinLock, 0, 0, 0);
328  }
329 #endif
330 
331 #ifdef CONFIG_SMP
332  /* Check if it's already acquired */
333  if (!(*SpinLock))
334  {
335  /* Try to acquire it */
337  {
338  /* Someone else acquired it */
339  return FALSE;
340  }
341  }
342  else
343  {
344  /* It was already acquired */
345  return FALSE;
346  }
347 #endif
348 
349 #if DBG
350  /* On debug builds, we OR in the KTHREAD */
352 #endif
353 
354  /* All is well, return TRUE */
355  return TRUE;
356 }
357 
358 /*
359  * @implemented
360  */
361 VOID
362 FASTCALL
365 {
366  /* Set it up properly */
369 #ifdef CONFIG_SMP
370 #if 0
371  KeAcquireQueuedSpinLockAtDpcLevel(LockHandle->LockQueue.Next);
372 #else
373  /* Make sure we are at DPC or above! */
375  {
376  /* We aren't -- bugcheck */
377  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
380  0,
381  0);
382  }
383 #endif
384 #endif
385 
386  /* Acquire the lock */
387  KxAcquireSpinLock(LockHandle->LockQueue.Lock); // HACK
388 }
389 
390 /*
391  * @implemented
392  */
393 VOID
394 FASTCALL
396 {
397 #ifdef CONFIG_SMP
398 #if 0
399  /* Call the internal function */
400  KeReleaseQueuedSpinLockFromDpcLevel(LockHandle->LockQueue.Next);
401 #else
402  /* Make sure we are at DPC or above! */
404  {
405  /* We aren't -- bugcheck */
406  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
409  0,
410  0);
411  }
412 #endif
413 #endif
414 
415  /* Release the lock */
416  KxReleaseSpinLock(LockHandle->LockQueue.Lock); // HACK
417 }
418 
419 /*
420  * @unimplemented
421  */
422 KIRQL
423 FASTCALL
425 {
427  return 0;
428 }
429 
430 /*
431  * @unimplemented
432  */
433 VOID
434 FASTCALL
436  IN KIRQL OldIrql)
437 {
439 }
440 
441 /*
442  * @implemented
443  */
444 VOID
445 FASTCALL
448 {
452  else
454 }
455 
456 /*
457  * @implemented
458  */
459 VOID
460 FASTCALL
462 {
465  else
467 
468 }
469 
470 /*
471  * @implemented
472  */
473 BOOLEAN
474 FASTCALL
476 {
477  /* Test this spinlock */
478  if (*SpinLock)
479  {
480  /* Spinlock is busy, yield execution */
481  YieldProcessor();
482 
483  /* Return busy flag */
484  return FALSE;
485  }
486 
487  /* Spinlock appears to be free */
488  return TRUE;
489 }
490 
491 #ifdef _M_IX86
492 VOID
493 NTAPI
494 Kii386SpinOnSpinLock(PKSPIN_LOCK SpinLock, ULONG Flags)
495 {
496  // FIXME: Handle flags
498 
499  /* Spin until it's unlocked */
500  while (*(volatile KSPIN_LOCK *)SpinLock & 1)
501  {
502  // FIXME: Check for timeout
503 
504  /* Yield and keep looping */
505  YieldProcessor();
506  }
507 }
508 #endif
VOID NTAPI _KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:186
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define IN
Definition: typedefs.h:39
PKSPIN_LOCK volatile Lock
Definition: ketypes.h:611
#define _Inout_
Definition: ms_sal.h:378
VOID FASTCALL KeAcquireInStackQueuedSpinLockForDpc(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:446
#define TRUE
Definition: types.h:120
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
VOID FASTCALL KeReleaseInStackQueuedSpinLockForDpc(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:461
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:372
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:198
struct _KSPIN_LOCK_QUEUE *volatile Next
Definition: ketypes.h:610
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
_Acquires_exclusive_lock_(Vcb->Resource)) FINISHED FatAcquireExclusiveVcb_Real(IN PIRP_CONTEXT IrpContext
VOID FASTCALL KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:130
#define FASTCALL
Definition: nt_native.h:50
uint32_t ULONG_PTR
Definition: typedefs.h:65
FORCEINLINE VOID YieldProcessor(VOID)
Definition: ke.h:32
_Acquires_nonreentrant_lock_(SpinLock) FORCEINLINE VOID KxAcquireSpinLock(_Unreferenced_parameter_ PKSPIN_LOCK SpinLock)
Definition: spinlock.h:18
UCHAR KIRQL
Definition: env_spec_w32.h:591
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
#define FALSE
Definition: types.h:117
_Releases_nonreentrant_lock_(SpinLock) FORCEINLINE VOID KxReleaseSpinLock(_Unreferenced_parameter_ PKSPIN_LOCK SpinLock)
Definition: spinlock.h:69
long LONG
Definition: pedump.c:60
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFSPINLOCK * SpinLock
Definition: wdfsync.h:225
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
VOID NTAPI KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt, IN KIRQL OldIrql)
Definition: spinlock.c:171
_IRQL_requires_min_(DISPATCH_LEVEL)
Definition: spinlock.c:97
VOID FASTCALL KeReleaseSpinLockForDpc(IN PKSPIN_LOCK SpinLock, IN KIRQL OldIrql)
Definition: spinlock.c:435
unsigned char BOOLEAN
BOOLEAN FASTCALL KeTestSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:475
KIRQL OldIrql
Definition: mm.h:1502
#define InterlockedBitTestAndSet
Definition: interlocked.h:30
VOID FASTCALL KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:166
VOID FASTCALL KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:363
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
struct _KSPIN_LOCK_QUEUE * PKSPIN_LOCK_QUEUE
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:221
KIRQL NTAPI KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
Definition: spinlock.c:154
#define _Releases_exclusive_lock_(a)
Definition: btrfs_drv.h:209
#define InterlockedExchange
Definition: armddk.h:54
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
KIRQL FASTCALL KeAcquireSpinLockForDpc(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:424
VOID FASTCALL KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:298
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
#define LQ_OWN
Definition: spinlock.c:16
#define NULL
Definition: types.h:112
VOID FASTCALL KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:287
VOID NTAPI KeRaiseIrql(KIRQL NewIrql, PKIRQL OldIrql)
Definition: spinlock.c:27
VOID FASTCALL KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:265
#define OUT
Definition: typedefs.h:40
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:124
unsigned int ULONG
Definition: retypes.h:1
VOID FASTCALL KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:243
#define UNIMPLEMENTED
Definition: debug.h:115
#define ULONG_PTR
Definition: config.h:101
#define LQ_WAIT
Definition: spinlock.c:15
KSPIN_LOCK_QUEUE LockQueue
Definition: ketypes.h:615
*LockHandle LockHandle _Out_ PKLOCK_QUEUE_HANDLE LockHandle
Definition: kefuncs.h:729
VOID FASTCALL KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:395
#define KeGetCurrentThread
Definition: hal.h:55
VOID NTAPI KeLowerIrql(KIRQL NewIrql)
Definition: spinlock.c:39
BOOLEAN FASTCALL KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock)
Definition: spinlock.c:309
signed int * PLONG
Definition: retypes.h:5
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108