- KdDebuggerNotPresent should be FALSE by default.
[reactos.git] / reactos / ntoskrnl / ke / spinlock.c
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 <internal/debug.h>
14
15 #define LQ_WAIT 1
16 #define LQ_OWN 2
17
18 /* PRIVATE FUNCTIONS *********************************************************/
19
20 VOID
21 FASTCALL
22 KeAcquireQueuedSpinLockAtDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
23 {
24 #ifdef CONFIG_SMP
25 PKSPIN_LOCK_QUEUE Prev;
26
27 /* Set the new lock */
28 Prev = (PKSPIN_LOCK_QUEUE)
29 InterlockedExchange((PLONG)LockHandle->LockQueue.Lock,
30 (LONG)LockHandle);
31 if (!Prev)
32 {
33 /* There was nothing there before. We now own it */
34 *(ULONG_PTR*)&LockHandle->LockQueue.Lock |= LQ_OWN;
35 return;
36 }
37
38 /* Set the wait flag */
39 *(ULONG_PTR*)&LockHandle->LockQueue.Lock |= LQ_WAIT;
40
41 /* Link us */
42 Prev->Next = (PKSPIN_LOCK_QUEUE)LockHandle;
43
44 /* Loop and wait */
45 while ( *(ULONG_PTR*)&LockHandle->LockQueue.Lock & LQ_WAIT) YieldProcessor();
46 return;
47 #endif
48 }
49
50 VOID
51 FASTCALL
52 KeReleaseQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
53 {
54 #ifdef CONFIG_SMP
55 KSPIN_LOCK LockVal;
56 PKSPIN_LOCK_QUEUE Waiter;
57
58 /* Remove own and wait flags */
59 *(ULONG_PTR*)&LockHandle->LockQueue.Lock &= ~(LQ_OWN | LQ_WAIT);
60 LockVal = *LockHandle->LockQueue.Lock;
61
62 /* Check if we already own it */
63 if (LockVal == (KSPIN_LOCK)LockHandle)
64 {
65 /* Disown it */
66 LockVal = (KSPIN_LOCK)
67 InterlockedCompareExchangePointer(LockHandle->LockQueue.Lock,
68 NULL,
69 LockHandle);
70 }
71 if (LockVal == (KSPIN_LOCK)LockHandle) return;
72
73 /* Need to wait for it */
74 Waiter = LockHandle->LockQueue.Next;
75 while (!Waiter)
76 {
77 YieldProcessor();
78 Waiter = LockHandle->LockQueue.Next;
79 }
80
81 /* It's gone */
82 *(ULONG_PTR*)&Waiter->Lock ^= (LQ_OWN | LQ_WAIT);
83 LockHandle->LockQueue.Next = NULL;
84 #endif
85 }
86
87 /* PUBLIC FUNCTIONS **********************************************************/
88
89 /*
90 * @implemented
91 */
92 VOID
93 NTAPI
94 KeInitializeSpinLock(IN PKSPIN_LOCK SpinLock)
95 {
96 /* Clear it */
97 *SpinLock = 0;
98 }
99
100 /*
101 * @implemented
102 */
103 #undef KeAcquireSpinLockAtDpcLevel
104 VOID
105 NTAPI
106 KeAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
107 {
108 /* Do the inlined function */
109 KxAcquireSpinLock(SpinLock);
110 }
111
112 /*
113 * @implemented
114 */
115 #undef KeReleaseSpinLockFromDpcLevel
116 VOID
117 NTAPI
118 KeReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
119 {
120 /* Do the lined function */
121 KxReleaseSpinLock(SpinLock);
122 }
123
124 /*
125 * @implemented
126 */
127 VOID
128 FASTCALL
129 KefAcquireSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock)
130 {
131 /* Do the inlined function */
132 KxAcquireSpinLock(SpinLock);
133 }
134
135 /*
136 * @implemented
137 */
138 VOID
139 FASTCALL
140 KefReleaseSpinLockFromDpcLevel(IN PKSPIN_LOCK SpinLock)
141 {
142 /* Do the lined function */
143 KxReleaseSpinLock(SpinLock);
144 }
145
146 /*
147 * @implemented
148 */
149 VOID
150 FASTCALL
151 KiAcquireSpinLock(IN PKSPIN_LOCK SpinLock)
152 {
153 /* Do the inlined function */
154 KxAcquireSpinLock(SpinLock);
155 }
156
157 /*
158 * @implemented
159 */
160 VOID
161 FASTCALL
162 KiReleaseSpinLock(IN PKSPIN_LOCK SpinLock)
163 {
164 /* Do the lined function */
165 KxReleaseSpinLock(SpinLock);
166 }
167
168 /*
169 * @implemented
170 */
171 BOOLEAN
172 FASTCALL
173 KeTryToAcquireSpinLockAtDpcLevel(IN OUT PKSPIN_LOCK SpinLock)
174 {
175 #ifdef CONFIG_SMP
176 /* Check if it's already acquired */
177 if (!(*SpinLock))
178 {
179 /* Try to acquire it */
180 if (InterlockedBitTestAndSet((PLONG)SpinLock, 0))
181 {
182 /* Someone else acquired it */
183 return FALSE;
184 }
185 }
186 else
187 {
188 /* It was already acquired */
189 return FALSE;
190 }
191
192 #ifdef DBG
193 /* On debug builds, we OR in the KTHREAD */
194 *SpinLock = (ULONG_PTR)KeGetCurrentThread() | 1;
195 #endif
196 #endif
197
198 /* All is well, return TRUE */
199 return TRUE;
200 }
201
202 /*
203 * @implemented
204 */
205 VOID
206 FASTCALL
207 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock,
208 IN PKLOCK_QUEUE_HANDLE LockHandle)
209 {
210 #ifdef CONFIG_SMP
211 /* Set it up properly */
212 LockHandle->LockQueue.Next = NULL;
213 LockHandle->LockQueue.Lock = SpinLock;
214 KeAcquireQueuedSpinLockAtDpcLevel((PKLOCK_QUEUE_HANDLE)
215 &LockHandle->LockQueue.Next);
216 #endif
217 }
218
219 /*
220 * @implemented
221 */
222 VOID
223 FASTCALL
224 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
225 {
226 #ifdef CONFIG_SMP
227 /* Call the internal function */
228 KeReleaseQueuedSpinLockFromDpcLevel((PKLOCK_QUEUE_HANDLE)
229 &LockHandle->LockQueue.Next);
230 #endif
231 }
232
233 /*
234 * @implemented
235 */
236 KIRQL
237 NTAPI
238 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
239 {
240 KIRQL OldIrql;
241
242 /* Raise IRQL */
243 KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
244
245 /* Acquire spinlock on MP */
246 KefAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
247 return OldIrql;
248 }
249
250 /*
251 * @implemented
252 */
253 BOOLEAN
254 NTAPI
255 KeSynchronizeExecution(IN PKINTERRUPT Interrupt,
256 IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
257 IN PVOID SynchronizeContext)
258 {
259 KIRQL OldIrql;
260 BOOLEAN Status;
261
262 /* Raise IRQL and acquire lock on MP */
263 OldIrql = KeAcquireInterruptSpinLock(Interrupt);
264
265 /* Call the routine */
266 Status = SynchronizeRoutine(SynchronizeContext);
267
268 /* Release lock and lower IRQL */
269 KeReleaseInterruptSpinLock(Interrupt, OldIrql);
270
271 /* Return routine status */
272 return Status;
273 }
274
275 /*
276 * @implemented
277 */
278 VOID
279 NTAPI
280 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt,
281 IN KIRQL OldIrql)
282 {
283 /* Release lock on MP */
284 KefReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
285
286 /* Lower IRQL */
287 KeLowerIrql(OldIrql);
288 }
289
290 /* EOF */