ReactOS 0.4.15-dev-7958-gcd0bb1a
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
25VOID
27KeAcquireQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK_QUEUE LockHandle)
28{
29#ifdef CONFIG_SMP
31
32 /* Set the new lock */
33 Prev = (PKSPIN_LOCK_QUEUE)
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
55VOID
57KeReleaseQueuedSpinLockFromDpcLevel(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,
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
100VOID
102KeAcquireQueuedSpinLockAtDpcLevel(_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
124VOID
126KeReleaseQueuedSpinLockFromDpcLevel(_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 */
152KIRQL
153NTAPI
155{
157
158 /* Raise IRQL */
159 KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
160
161 /* Acquire spinlock on MP */
163 return OldIrql;
164}
165
166/*
167 * @implemented
168 */
169VOID
170NTAPI
173{
174 /* Release lock on MP */
176
177 /* Lower IRQL */
179}
180
181/*
182 * @implemented
183 */
184VOID
185NTAPI
187{
188 /* Clear it */
189 *SpinLock = 0;
190}
191
192/*
193 * @implemented
194 */
195#undef KeAcquireSpinLockAtDpcLevel
196VOID
197NTAPI
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
219VOID
220NTAPI
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 */
241VOID
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 */
263VOID
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 */
285VOID
288{
289 /* Do the inlined function */
290 KxAcquireSpinLock(SpinLock);
291}
292
293/*
294 * @implemented
295 */
296VOID
299{
300 /* Do the inlined function */
301 KxReleaseSpinLock(SpinLock);
302}
303
304/*
305 * @implemented
306 */
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 */
361VOID
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 */
393VOID
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 */
422KIRQL
425{
427 return 0;
428}
429
430/*
431 * @unimplemented
432 */
433VOID
437{
439}
440
441/*
442 * @implemented
443 */
444VOID
448{
452 else
454}
455
456/*
457 * @implemented
458 */
459VOID
462{
465 else
467
468}
469
470/*
471 * @implemented
472 */
476{
477 /* Test this spinlock */
478 if (*SpinLock)
479 {
480 /* Spinlock is busy, yield execution */
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
492VOID
493NTAPI
494Kii386SpinOnSpinLock(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 */
506 }
507}
508#endif
unsigned char BOOLEAN
#define InterlockedExchange
Definition: armddk.h:54
#define UNIMPLEMENTED
Definition: debug.h:115
#define _Releases_exclusive_lock_(lock)
#define _Acquires_nonreentrant_lock_(lock)
#define _Acquires_exclusive_lock_(lock)
#define _Releases_nonreentrant_lock_(lock)
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define ULONG_PTR
Definition: config.h:101
#define _IRQL_requires_min_(irql)
Definition: driverspecs.h:231
UCHAR KIRQL
Definition: env_spec_w32.h:591
ULONG KSPIN_LOCK
Definition: env_spec_w32.h:72
#define KeRaiseIrql(irql, oldIrql)
Definition: env_spec_w32.h:597
KSPIN_LOCK * PKSPIN_LOCK
Definition: env_spec_w32.h:73
#define KeLowerIrql(oldIrql)
Definition: env_spec_w32.h:602
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define DISPATCH_LEVEL
Definition: env_spec_w32.h:696
VOID FASTCALL KeAcquireInStackQueuedSpinLock(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:130
VOID FASTCALL KeReleaseInStackQueuedSpinLock(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:166
#define KeGetCurrentThread
Definition: hal.h:55
#define InterlockedCompareExchangePointer
Definition: interlocked.h:129
#define InterlockedBitTestAndSet
Definition: interlocked.h:30
#define _Inout_
Definition: ms_sal.h:378
#define FASTCALL
Definition: nt_native.h:50
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:317
VOID FASTCALL KeReleaseInStackQueuedSpinLockForDpc(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:461
BOOLEAN FASTCALL KeTestSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:475
KIRQL NTAPI KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
Definition: spinlock.c:154
VOID FASTCALL KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:363
VOID FASTCALL KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:395
#define LQ_WAIT
Definition: spinlock.c:15
VOID FASTCALL KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:265
#define LQ_OWN
Definition: spinlock.c:16
VOID FASTCALL KeReleaseSpinLockForDpc(IN PKSPIN_LOCK SpinLock, IN KIRQL OldIrql)
Definition: spinlock.c:435
VOID NTAPI KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt, IN KIRQL OldIrql)
Definition: spinlock.c:171
BOOLEAN FASTCALL KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock)
Definition: spinlock.c:309
VOID FASTCALL KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:287
VOID FASTCALL KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:298
KIRQL FASTCALL KeAcquireSpinLockForDpc(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:424
VOID NTAPI _KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:186
VOID FASTCALL KeAcquireInStackQueuedSpinLockForDpc(IN PKSPIN_LOCK SpinLock, IN PKLOCK_QUEUE_HANDLE LockHandle)
Definition: spinlock.c:446
VOID FASTCALL KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
Definition: spinlock.c:243
long LONG
Definition: pedump.c:60
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
#define YieldProcessor
Definition: ke.h:48
#define KeAcquireSpinLockAtDpcLevel(SpinLock)
Definition: ke.h:125
#define KeReleaseSpinLockFromDpcLevel(SpinLock)
Definition: ke.h:135
KSPIN_LOCK_QUEUE LockQueue
Definition: ketypes.h:627
struct _KSPIN_LOCK_QUEUE *volatile Next
Definition: ketypes.h:622
PKSPIN_LOCK volatile Lock
Definition: ketypes.h:623
#define NTAPI
Definition: typedefs.h:36
uint32_t ULONG_PTR
Definition: typedefs.h:65
#define IN
Definition: typedefs.h:39
int32_t * PLONG
Definition: typedefs.h:58
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:379
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFSPINLOCK * SpinLock
Definition: wdfsync.h:228
_Must_inspect_result_ _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWAITLOCK * Lock
Definition: wdfsync.h:127
_Must_inspect_result_ _In_ ULONG Flags
Definition: wsk.h:170
_Requires_lock_held_ Interrupt _Releases_lock_ Interrupt _In_ _IRQL_restores_ KIRQL OldIrql
Definition: kefuncs.h:778
*LockHandle LockHandle _Out_ PKLOCK_QUEUE_HANDLE LockHandle
Definition: kefuncs.h:717
struct _KSPIN_LOCK_QUEUE * PKSPIN_LOCK_QUEUE