59d249229a16a6a6cadcdb058c9de79ed7fd9355
[reactos.git] / reactos / ntoskrnl / ke / spinlock.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/spinlock.c
6 * PURPOSE: Implements spinlocks
7 *
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
9 */
10
11 /*
12 * NOTE: On a uniprocessor machine spinlocks are implemented by raising
13 * the irq level
14 */
15
16 /* INCLUDES ****************************************************************/
17
18 #include <ntoskrnl.h>
19 #define NDEBUG
20 #include <internal/debug.h>
21
22 /* FUNCTIONS ***************************************************************/
23
24 /*
25 * @implemented
26 */
27 BOOLEAN STDCALL
28 KeSynchronizeExecution (PKINTERRUPT Interrupt,
29 PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
30 PVOID SynchronizeContext)
31 /*
32 * FUNCTION: Synchronizes the execution of a given routine with the ISR
33 * of a given interrupt object
34 * ARGUMENTS:
35 * Interrupt = Interrupt object to synchronize with
36 * SynchronizeRoutine = Routine to call whose execution is
37 * synchronized with the ISR
38 * SynchronizeContext = Parameter to pass to the synchronized routine
39 * RETURNS: TRUE if the operation succeeded
40 */
41 {
42 KIRQL oldlvl;
43 BOOLEAN ret;
44
45 oldlvl = KeAcquireInterruptSpinLock(Interrupt);
46
47 ret = SynchronizeRoutine(SynchronizeContext);
48
49 KeReleaseInterruptSpinLock(Interrupt, oldlvl);
50
51 return(ret);
52 }
53
54 /*
55 * @implemented
56 */
57 KIRQL
58 STDCALL
59 KeAcquireInterruptSpinLock(
60 IN PKINTERRUPT Interrupt
61 )
62 {
63 KIRQL oldIrql;
64
65 KeRaiseIrql(Interrupt->SynchronizeIrql, &oldIrql);
66 KiAcquireSpinLock(Interrupt->ActualLock);
67 return oldIrql;
68 }
69
70 /*
71 * @implemented
72 */
73 VOID STDCALL
74 KeInitializeSpinLock (PKSPIN_LOCK SpinLock)
75 /*
76 * FUNCTION: Initalizes a spinlock
77 * ARGUMENTS:
78 * SpinLock = Caller supplied storage for the spinlock
79 */
80 {
81 *SpinLock = 0;
82 }
83
84 #undef KefAcquireSpinLockAtDpcLevel
85
86 /*
87 * @implemented
88 */
89 VOID FASTCALL
90 KefAcquireSpinLockAtDpcLevel(PKSPIN_LOCK SpinLock)
91 {
92 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
93 KiAcquireSpinLock(SpinLock);
94 }
95
96 #undef KeAcquireSpinLockAtDpcLevel
97
98 /*
99 * @implemented
100 */
101 VOID STDCALL
102 KeAcquireSpinLockAtDpcLevel (PKSPIN_LOCK SpinLock)
103 /*
104 * FUNCTION: Acquires a spinlock when the caller is already running at
105 * dispatch level
106 * ARGUMENTS:
107 * SpinLock = Spinlock to acquire
108 */
109 {
110 KefAcquireSpinLockAtDpcLevel(SpinLock);
111 }
112
113
114 /*
115 * @unimplemented
116 */
117 VOID
118 FASTCALL
119 KeAcquireInStackQueuedSpinLockAtDpcLevel(
120 IN PKSPIN_LOCK SpinLock,
121 IN PKLOCK_QUEUE_HANDLE LockHandle
122 )
123 {
124 UNIMPLEMENTED;
125 }
126
127
128 #undef KefReleaseSpinLockFromDpcLevel
129
130 /*
131 * @implemented
132 */
133 VOID FASTCALL
134 KefReleaseSpinLockFromDpcLevel(PKSPIN_LOCK SpinLock)
135 {
136 ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
137 KiReleaseSpinLock(SpinLock);
138 }
139
140 #undef KeReleaseSpinLockFromDpcLevel
141
142 /*
143 * @implemented
144 */
145 VOID STDCALL
146 KeReleaseSpinLockFromDpcLevel (PKSPIN_LOCK SpinLock)
147 /*
148 * FUNCTION: Releases a spinlock when the caller was running at dispatch
149 * level before acquiring it
150 * ARGUMENTS:
151 * SpinLock = Spinlock to release
152 */
153 {
154 KefReleaseSpinLockFromDpcLevel(SpinLock);
155 }
156
157 /*
158 * @unimplemented
159 */
160 VOID
161 FASTCALL
162 KeReleaseInStackQueuedSpinLockFromDpcLevel(
163 IN PKLOCK_QUEUE_HANDLE LockHandle
164 )
165 {
166 UNIMPLEMENTED;
167 }
168
169 /*
170 * @implemented
171 */
172 VOID FASTCALL
173 KiAcquireSpinLock(PKSPIN_LOCK SpinLock)
174 {
175 ULONG i;
176
177 /*
178 * FIXME: This depends on gcc assembling this test to a single load from
179 * the spinlock's value.
180 */
181 ASSERT(*SpinLock < 2);
182
183 while ((i = InterlockedExchangeUL(SpinLock, 1)) == 1)
184 {
185 #ifdef CONFIG_SMP
186 /* Avoid reading the value again too fast */
187 #if 1
188 __asm__ __volatile__ ("1:\n\t"
189 "cmpl $0,(%0)\n\t"
190 "jne 1b\n\t"
191 :
192 : "r" (SpinLock));
193 #else
194 while (0 != *(volatile KSPIN_LOCK*)SpinLock);
195 #endif
196 #else
197 DbgPrint("Spinning on spinlock %x current value %x\n", SpinLock, i);
198 KEBUGCHECKEX(SPIN_LOCK_ALREADY_OWNED, (ULONG)SpinLock, 0, 0, 0);
199 #endif /* CONFIG_SMP */
200 }
201 }
202
203 /*
204 * @implemented
205 */
206 VOID
207 STDCALL
208 KeReleaseInterruptSpinLock(
209 IN PKINTERRUPT Interrupt,
210 IN KIRQL OldIrql
211 )
212 {
213 KiReleaseSpinLock(Interrupt->ActualLock);
214 KeLowerIrql(OldIrql);
215 }
216
217 /*
218 * @implemented
219 */
220 VOID FASTCALL
221 KiReleaseSpinLock(PKSPIN_LOCK SpinLock)
222 {
223 if (*SpinLock != 1)
224 {
225 DbgPrint("Releasing unacquired spinlock %x\n", SpinLock);
226 KEBUGCHECKEX(SPIN_LOCK_NOT_OWNED, (ULONG)SpinLock, 0, 0, 0);
227 }
228 (void)InterlockedExchangeUL(SpinLock, 0);
229 }
230
231 /* EOF */