Make BusyLoop volatile. Spotted by Thomas.
[reactos.git] / reactos / drivers / net / ndis / ndis / control.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS NDIS library
4 * FILE: ndis/control.c
5 * PURPOSE: Program control routines
6 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Vizzini (vizzini@plasmic.com)
8 * REVISIONS:
9 * CSH 01/08-2000 Created
10 * 3 Oct 2003 Vizzini - Formatting and minor bugfixes
11 */
12
13 #include "ndissys.h"
14
15 \f
16 /*
17 * @implemented
18 */
19 VOID
20 EXPORT
21 NdisInitializeReadWriteLock(
22 IN PNDIS_RW_LOCK Lock)
23 /*
24 * FUNCTION: Initialize a NDIS_RW_LOCK
25 * ARGUMENTS:
26 * Lock: pointer to the lock to initialize
27 * NOTES:
28 * NDIS 5.0
29 */
30 {
31 RtlZeroMemory(Lock, sizeof(NDIS_RW_LOCK));
32 }
33
34 \f
35 /*
36 * @implemented
37 */
38 VOID
39 EXPORT
40 NdisAcquireReadWriteLock(
41 IN PNDIS_RW_LOCK Lock,
42 IN BOOLEAN fWrite,
43 IN PLOCK_STATE LockState)
44 /*
45 * FUNCTION:
46 * ARGUMENTS:
47 * NOTES:
48 * NDIS 5.0
49 */
50 {
51 ULONG RefCount;
52 UCHAR ProcessorNumber;
53 volatile UCHAR BusyLoop;
54
55 ASSERT_IRQL(DISPATCH_LEVEL);
56
57 if (fWrite) {
58 if (Lock->Context == PsGetCurrentThread()) {
59 LockState->LockState = 2;
60 } else {
61 KeAcquireSpinLock(&Lock->SpinLock, &LockState->OldIrql);
62 /* Check if any other processor helds a shared lock. */
63 for (ProcessorNumber = KeNumberProcessors; ProcessorNumber--; ) {
64 if (ProcessorNumber != KeGetCurrentProcessorNumber()) {
65 /* Wait till the shared lock is released. */
66 while (Lock->RefCount[ProcessorNumber].RefCount != 0) {
67 for (BusyLoop = 32; BusyLoop--; )
68 ;
69 }
70 }
71 }
72 Lock->Context = PsGetCurrentThread();
73 LockState->LockState = 4;
74 }
75 } else {
76 KeRaiseIrql(DISPATCH_LEVEL, &LockState->OldIrql);
77 RefCount = InterlockedIncrement((PLONG)&Lock->RefCount[KeGetCurrentProcessorNumber()].RefCount);
78 /* Racing with a exclusive write lock case. */
79 if (Lock->SpinLock != 0) {
80 if (RefCount == 1) {
81 if (Lock->Context != PsGetCurrentThread()) {
82 /* Wait for the exclusive lock to be released. */
83 Lock->RefCount[KeGetCurrentProcessorNumber()].RefCount--;
84 KefAcquireSpinLockAtDpcLevel(&Lock->SpinLock);
85 Lock->RefCount[KeGetCurrentProcessorNumber()].RefCount++;
86 KefReleaseSpinLockFromDpcLevel(&Lock->SpinLock);
87 }
88 }
89 }
90 LockState->LockState = 3;
91 }
92 }
93
94 \f
95 /*
96 * @implemented
97 */
98 VOID
99 EXPORT
100 NdisReleaseReadWriteLock(
101 IN PNDIS_RW_LOCK Lock,
102 IN PLOCK_STATE LockState)
103 /*
104 * FUNCTION:
105 * ARGUMENTS:
106 * NOTES:
107 * NDIS 5.0
108 */
109 {
110 switch (LockState->LockState) {
111 case 2: /* Exclusive write lock, recursive */
112 return;
113
114 case 3: /* Shared read lock */
115 Lock->RefCount[KeGetCurrentProcessorNumber()].RefCount--;
116 LockState->LockState = -1;
117 if (LockState->OldIrql < DISPATCH_LEVEL)
118 KeLowerIrql(LockState->OldIrql);
119 return;
120
121 case 4: /* Exclusive write lock */
122 Lock->Context = NULL;
123 LockState->LockState = -1;
124 KfReleaseSpinLock(&Lock->SpinLock, LockState->OldIrql);
125 return;
126 }
127 }
128
129 \f
130 /*
131 * @implemented
132 */
133 #undef NdisAcquireSpinLock
134 VOID
135 EXPORT
136 NdisAcquireSpinLock(
137 IN PNDIS_SPIN_LOCK SpinLock)
138 /*
139 * FUNCTION: Acquires a spin lock for exclusive access to a resource
140 * ARGUMENTS:
141 * SpinLock = Pointer to the initialized NDIS spin lock to be acquired
142 */
143 {
144 KeAcquireSpinLock(&SpinLock->SpinLock, &SpinLock->OldIrql);
145 }
146
147 \f
148 /*
149 * @implemented
150 */
151 #undef NdisAllocateSpinLock
152 VOID
153 EXPORT
154 NdisAllocateSpinLock(
155 IN PNDIS_SPIN_LOCK SpinLock)
156 /*
157 * FUNCTION: Initializes for an NDIS spin lock
158 * ARGUMENTS:
159 * SpinLock = Pointer to an NDIS spin lock structure
160 */
161 {
162 KeInitializeSpinLock(&SpinLock->SpinLock);
163 }
164
165 \f
166 /*
167 * @implemented
168 */
169 #undef NdisDprAcquireSpinLock
170 VOID
171 EXPORT
172 NdisDprAcquireSpinLock(
173 IN PNDIS_SPIN_LOCK SpinLock)
174 /*
175 * FUNCTION: Acquires a spin lock from IRQL DISPATCH_LEVEL
176 * ARGUMENTS:
177 * SpinLock = Pointer to the initialized NDIS spin lock to be acquired
178 */
179 {
180 KeAcquireSpinLockAtDpcLevel(&SpinLock->SpinLock);
181 SpinLock->OldIrql = DISPATCH_LEVEL;
182 }
183
184 \f
185 /*
186 * @implemented
187 */
188 #undef NdisDprReleaseSpinLock
189 VOID
190 EXPORT
191 NdisDprReleaseSpinLock(
192 IN PNDIS_SPIN_LOCK SpinLock)
193 /*
194 * FUNCTION: Releases an acquired spin lock from IRQL DISPATCH_LEVEL
195 * ARGUMENTS:
196 * SpinLock = Pointer to the acquired NDIS spin lock to be released
197 */
198 {
199 KeReleaseSpinLockFromDpcLevel(&SpinLock->SpinLock);
200 }
201
202 \f
203 /*
204 * @implemented
205 */
206 #undef NdisFreeSpinLock
207 VOID
208 EXPORT
209 NdisFreeSpinLock(
210 IN PNDIS_SPIN_LOCK SpinLock)
211 /*
212 * FUNCTION: Releases a spin lock initialized with NdisAllocateSpinLock
213 * ARGUMENTS:
214 * SpinLock = Pointer to an initialized NDIS spin lock
215 */
216 {
217 /* Nothing to do here! */
218 }
219
220 \f
221 /*
222 * @unimplemented
223 */
224 VOID
225 EXPORT
226 NdisGetCurrentProcessorCpuUsage(
227 PULONG pCpuUsage)
228 /*
229 * FUNCTION: Returns how busy the current processor is as a percentage
230 * ARGUMENTS:
231 * pCpuUsage = Pointer to a buffer to place CPU usage
232 */
233 {
234 UNIMPLEMENTED
235 }
236
237
238 /*
239 * @implemented
240 */
241 VOID
242 EXPORT
243 NdisInitializeEvent(
244 IN PNDIS_EVENT Event)
245 /*
246 * FUNCTION: Initializes an event to be used for synchronization
247 * ARGUMENTS:
248 * Event = Pointer to an NDIS event structure to be initialized
249 */
250 {
251 KeInitializeEvent(&Event->Event, NotificationEvent, FALSE);
252 }
253
254
255 /*
256 * @implemented
257 */
258 #undef NdisReleaseSpinLock
259 VOID
260 EXPORT
261 NdisReleaseSpinLock(
262 IN PNDIS_SPIN_LOCK SpinLock)
263 /*
264 * FUNCTION: Releases a spin lock previously acquired with NdisAcquireSpinLock
265 * ARGUMENTS:
266 * SpinLock = Pointer to the acquired NDIS spin lock to be released
267 */
268 {
269 KeReleaseSpinLock(&SpinLock->SpinLock, SpinLock->OldIrql);
270 }
271
272
273 /*
274 * @implemented
275 */
276 VOID
277 EXPORT
278 NdisResetEvent(
279 IN PNDIS_EVENT Event)
280 /*
281 * FUNCTION: Clears the signaled state of an event
282 * ARGUMENTS:
283 * Event = Pointer to the initialized event object to be reset
284 */
285 {
286 KeResetEvent(&Event->Event);
287 }
288
289
290 /*
291 * @implemented
292 */
293 VOID
294 EXPORT
295 NdisSetEvent(
296 IN PNDIS_EVENT Event)
297 /*
298 * FUNCTION: Sets an event to a signaled state if not already signaled
299 * ARGUMENTS:
300 * Event = Pointer to the initialized event object to be set
301 */
302 {
303 KeSetEvent(&Event->Event, IO_NO_INCREMENT, FALSE);
304 }
305
306
307 /*
308 * @implemented
309 */
310 BOOLEAN
311 EXPORT
312 NdisWaitEvent(
313 IN PNDIS_EVENT Event,
314 IN UINT MsToWait)
315 /*
316 * FUNCTION: Waits for an event to become signaled
317 * ARGUMENTS:
318 * Event = Pointer to the initialized event object to wait for
319 * MsToWait = Maximum milliseconds to wait for the event to become signaled
320 * RETURNS:
321 * TRUE if the event is in the signaled state
322 */
323 {
324 LARGE_INTEGER Timeout;
325 NTSTATUS Status;
326
327 Timeout.QuadPart = MsToWait * -10000LL;
328
329 Status = KeWaitForSingleObject(&Event->Event, Executive, KernelMode, TRUE, &Timeout);
330
331 return (Status == STATUS_SUCCESS);
332 }
333
334 /* EOF */
335