ReactOS  0.4.13-dev-73-gcfe54aa
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
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
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 
97 VOID
100 {
101 #ifdef CONFIG_SMP
102  /* Make sure we are at DPC or above! */
104  {
105  /* We aren't -- bugcheck */
106  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
107  (ULONG_PTR)LockHandle->Lock,
109  0,
110  0);
111  }
112 
113  /* Do the inlined function */
115 #endif
116 }
117 
118 VOID
119 FASTCALL
121 {
122 #ifdef CONFIG_SMP
123  /* Make sure we are at DPC or above! */
125  {
126  /* We aren't -- bugcheck */
127  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
128  (ULONG_PTR)LockHandle->Lock,
130  0,
131  0);
132  }
133 
134  /* Do the inlined function */
136 #endif
137 }
138 
139 #endif
140 
141 /* PUBLIC FUNCTIONS **********************************************************/
142 
143 /*
144  * @implemented
145  */
146 KIRQL
147 NTAPI
149 {
150  KIRQL OldIrql;
151 
152  /* Raise IRQL */
153  KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
154 
155  /* Acquire spinlock on MP */
156  KeAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
157  return OldIrql;
158 }
159 
160 /*
161  * @implemented
162  */
163 VOID
164 NTAPI
166  IN KIRQL OldIrql)
167 {
168  /* Release lock on MP */
169  KeReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
170 
171  /* Lower IRQL */
173 }
174 
175 /*
176  * @implemented
177  */
178 VOID
179 NTAPI
181 {
182  /* Clear it */
183  *SpinLock = 0;
184 }
185 
186 /*
187  * @implemented
188  */
189 #undef KeAcquireSpinLockAtDpcLevel
190 VOID
191 NTAPI
193 {
194  /* Make sure we are at DPC or above! */
196  {
197  /* We aren't -- bugcheck */
198  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
201  0,
202  0);
203  }
204 
205  /* Do the inlined function */
207 }
208 
209 /*
210  * @implemented
211  */
212 #undef KeReleaseSpinLockFromDpcLevel
213 VOID
214 NTAPI
216 {
217  /* Make sure we are at DPC or above! */
219  {
220  /* We aren't -- bugcheck */
221  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
224  0,
225  0);
226  }
227 
228  /* Do the inlined function */
230 }
231 
232 /*
233  * @implemented
234  */
235 VOID
236 FASTCALL
238 {
239  /* Make sure we are at DPC or above! */
241  {
242  /* We aren't -- bugcheck */
243  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
246  0,
247  0);
248  }
249 
250  /* Do the inlined function */
252 }
253 
254 /*
255  * @implemented
256  */
257 VOID
258 FASTCALL
260 {
261  /* Make sure we are at DPC or above! */
263  {
264  /* We aren't -- bugcheck */
265  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
268  0,
269  0);
270  }
271 
272  /* Do the inlined function */
274 }
275 
276 /*
277  * @implemented
278  */
279 VOID
280 FASTCALL
282 {
283  /* Do the inlined function */
285 }
286 
287 /*
288  * @implemented
289  */
290 VOID
291 FASTCALL
293 {
294  /* Do the inlined function */
296 }
297 
298 /*
299  * @implemented
300  */
301 BOOLEAN
302 FASTCALL
304 {
305 #ifdef CONFIG_SMP
306  /* Check if it's already acquired */
307  if (!(*SpinLock))
308  {
309  /* Try to acquire it */
311  {
312  /* Someone else acquired it */
313  return FALSE;
314  }
315  }
316  else
317  {
318  /* It was already acquired */
319  return FALSE;
320  }
321 
322 #if DBG
323  /* On debug builds, we OR in the KTHREAD */
325 #endif
326 #endif
327 
328  /* All is well, return TRUE */
329  return TRUE;
330 }
331 
332 /*
333  * @implemented
334  */
335 VOID
336 FASTCALL
339 {
340 #ifdef CONFIG_SMP
341  /* Set it up properly */
344 #if 0
346 #else
347  /* Make sure we are at DPC or above! */
349  {
350  /* We aren't -- bugcheck */
351  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
354  0,
355  0);
356  }
357 
358  /* Acquire the lock */
360 #endif
361 #endif
362 }
363 
364 /*
365  * @implemented
366  */
367 VOID
368 FASTCALL
370 {
371 #ifdef CONFIG_SMP
372 #if 0
373  /* Call the internal function */
375 #else
376  /* Make sure we are at DPC or above! */
378  {
379  /* We aren't -- bugcheck */
380  KeBugCheckEx(IRQL_NOT_GREATER_OR_EQUAL,
383  0,
384  0);
385  }
386 
387  /* Release the lock */
389 #endif
390 #endif
391 }
392 
393 /*
394  * @unimplemented
395  */
396 KIRQL
397 FASTCALL
399 {
401  return 0;
402 }
403 
404 /*
405  * @unimplemented
406  */
407 VOID
408 FASTCALL
410  IN KIRQL OldIrql)
411 {
413 }
414 
415 /*
416  * @unimplemented
417  */
418 VOID
419 FASTCALL
422 {
424  return;
425 }
426 
427 /*
428  * @unimplemented
429  */
430 VOID
431 FASTCALL
433 {
435 }
436 
437 /*
438  * @implemented
439  */
440 BOOLEAN
441 FASTCALL
443 {
444  /* Test this spinlock */
445  if (*SpinLock)
446  {
447  /* Spinlock is busy, yield execution */
448  YieldProcessor();
449 
450  /* Return busy flag */
451  return FALSE;
452  }
453 
454  /* Spinlock appears to be free */
455  return TRUE;
456 }
457 
458 #ifdef _M_IX86
459 VOID
460 NTAPI
462 {
463  // FIXME: Handle flags
465 
466  /* Spin until it's unlocked */
467  while (*(volatile KSPIN_LOCK *)SpinLock & 1)
468  {
469  // FIXME: Check for timeout
470 
471  /* Yield and keep looping */
472  YieldProcessor();
473  }
474 }
475 #endif
VOID NTAPI _KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:180
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define IN
Definition: typedefs.h:38
PKSPIN_LOCK volatile Lock
Definition: ketypes.h:611
#define TRUE
Definition: types.h:120
VOID FASTCALL KeAcquireInStackQueuedSpinLockForDpc(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:420
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:323
VOID FASTCALL KeReleaseInStackQueuedSpinLockForDpc(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:432
FORCEINLINE VOID KxReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.h:35
VOID NTAPI KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:192
struct _KSPIN_LOCK_QUEUE *volatile Next
Definition: ketypes.h:610
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
#define FASTCALL
Definition: nt_native.h:50
_In_ PKSERVICE_ROUTINE _In_opt_ PVOID _In_opt_ PKSPIN_LOCK SpinLock
Definition: iofuncs.h:798
uint32_t ULONG_PTR
Definition: typedefs.h:63
FORCEINLINE VOID YieldProcessor(VOID)
Definition: ke.h:32
UCHAR KIRQL
Definition: env_spec_w32.h:591
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
NTSTATUS(* NTAPI)(IN PFILE_FULL_EA_INFORMATION EaBuffer, IN ULONG EaLength, OUT PULONG ErrorOffset)
Definition: IoEaTest.cpp:117
long LONG
Definition: pedump.c:60
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
VOID NTAPI KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt, IN KIRQL OldIrql)
Definition: spinlock.c:165
VOID FASTCALL KeReleaseSpinLockForDpc(IN PKSPIN_LOCK SpinLock, IN KIRQL OldIrql)
Definition: spinlock.c:409
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
FORCEINLINE VOID KxAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.h:20
BOOLEAN FASTCALL KeTestSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:442
#define InterlockedBitTestAndSet
Definition: interlocked.h:30
VOID FASTCALL KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:337
VOID FASTCALL KeReleaseQueuedSpinLockFromDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
Definition: spinlock.c:120
struct _KSPIN_LOCK_QUEUE * PKSPIN_LOCK_QUEUE
VOID NTAPI KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:215
KIRQL NTAPI KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
Definition: spinlock.c:148
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:803
#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:398
VOID NTAPI Kii386SpinOnSpinLock(PKSPIN_LOCK SpinLock, ULONG Flags)
VOID FASTCALL KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:292
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
#define LQ_OWN
Definition: spinlock.c:16
VOID FASTCALL KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:281
VOID NTAPI KeRaiseIrql(KIRQL NewIrql, PKIRQL OldIrql)
Definition: spinlock.c:27
VOID FASTCALL KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:259
#define OUT
Definition: typedefs.h:39
unsigned int ULONG
Definition: retypes.h:1
VOID FASTCALL KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:237
#define UNIMPLEMENTED
Definition: debug.h:114
#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:742
VOID FASTCALL KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:369
#define KeGetCurrentThread
Definition: hal.h:44
VOID NTAPI KeLowerIrql(KIRQL NewIrql)
Definition: spinlock.c:39
BOOLEAN FASTCALL KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock)
Definition: spinlock.c:303
VOID FASTCALL KeAcquireQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
Definition: spinlock.c:99
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:107