- Renamed device.c to config.c and removed all irrelevant code from it, leaving only...
[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 VOID
172 FASTCALL
173 KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock,
174 IN PKLOCK_QUEUE_HANDLE LockHandle)
175 {
176 #ifdef CONFIG_SMP
177 /* Set it up properly */
178 LockHandle->LockQueue.Next = NULL;
179 LockHandle->LockQueue.Lock = SpinLock;
180 KeAcquireQueuedSpinLockAtDpcLevel((PKLOCK_QUEUE_HANDLE)
181 &LockHandle->LockQueue.Next);
182 #endif
183 }
184
185 /*
186 * @implemented
187 */
188 VOID
189 FASTCALL
190 KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
191 {
192 #ifdef CONFIG_SMP
193 /* Call the internal function */
194 KeReleaseQueuedSpinLockFromDpcLevel((PKLOCK_QUEUE_HANDLE)
195 &LockHandle->LockQueue.Next);
196 #endif
197 }
198
199 /*
200 * @implemented
201 */
202 KIRQL
203 NTAPI
204 KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
205 {
206 KIRQL OldIrql;
207
208 /* Raise IRQL */
209 KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
210
211 /* Acquire spinlock on MP */
212 KefAcquireSpinLockAtDpcLevel(Interrupt->ActualLock);
213 return OldIrql;
214 }
215
216 /*
217 * @implemented
218 */
219 BOOLEAN
220 NTAPI
221 KeSynchronizeExecution(IN PKINTERRUPT Interrupt,
222 IN PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
223 IN PVOID SynchronizeContext)
224 {
225 KIRQL OldIrql;
226 BOOLEAN Status;
227
228 /* Raise IRQL and acquire lock on MP */
229 OldIrql = KeAcquireInterruptSpinLock(Interrupt);
230
231 /* Call the routine */
232 Status = SynchronizeRoutine(SynchronizeContext);
233
234 /* Release lock and lower IRQL */
235 KeReleaseInterruptSpinLock(Interrupt, OldIrql);
236
237 /* Return routine status */
238 return Status;
239 }
240
241 /*
242 * @implemented
243 */
244 VOID
245 NTAPI
246 KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt,
247 IN KIRQL OldIrql)
248 {
249 /* Release lock on MP */
250 KefReleaseSpinLockFromDpcLevel(Interrupt->ActualLock);
251
252 /* Lower IRQL */
253 KeLowerIrql(OldIrql);
254 }
255
256 /* EOF */