]> git.proxmox.com Git - mirror_edk2.git/blob - MdePkg/Library/BaseSynchronizationLib/SynchronizationMsc.c
MdePkg: Replace BSD License with BSD+Patent License
[mirror_edk2.git] / MdePkg / Library / BaseSynchronizationLib / SynchronizationMsc.c
1 /** @file
2 Implementation of synchronization functions.
3
4 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include "BaseSynchronizationLibInternals.h"
10
11 /**
12 Microsoft Visual Studio 7.1 Function Prototypes for read write barrier Intrinsics.
13 **/
14
15 void _ReadWriteBarrier (void);
16 #pragma intrinsic(_ReadWriteBarrier)
17
18
19 #define SPIN_LOCK_RELEASED ((UINTN) 1)
20 #define SPIN_LOCK_ACQUIRED ((UINTN) 2)
21
22 /**
23 Retrieves the architecture specific spin lock alignment requirements for
24 optimal spin lock performance.
25
26 This function retrieves the spin lock alignment requirements for optimal
27 performance on a given CPU architecture. The spin lock alignment is byte alignment.
28 It must be a power of two and is returned by this function. If there are no alignment
29 requirements, then 1 must be returned. The spin lock synchronization
30 functions must function correctly if the spin lock size and alignment values
31 returned by this function are not used at all. These values are hints to the
32 consumers of the spin lock synchronization functions to obtain optimal spin
33 lock performance.
34
35 @return The architecture specific spin lock alignment.
36
37 **/
38 UINTN
39 EFIAPI
40 GetSpinLockProperties (
41 VOID
42 )
43 {
44 return InternalGetSpinLockProperties ();
45 }
46
47 /**
48 Initializes a spin lock to the released state and returns the spin lock.
49
50 This function initializes the spin lock specified by SpinLock to the released
51 state, and returns SpinLock. Optimal performance can be achieved by calling
52 GetSpinLockProperties() to determine the size and alignment requirements for
53 SpinLock.
54
55 If SpinLock is NULL, then ASSERT().
56
57 @param SpinLock A pointer to the spin lock to initialize to the released
58 state.
59
60 @return SpinLock is in release state.
61
62 **/
63 SPIN_LOCK *
64 EFIAPI
65 InitializeSpinLock (
66 OUT SPIN_LOCK *SpinLock
67 )
68 {
69 ASSERT (SpinLock != NULL);
70
71 _ReadWriteBarrier();
72 *SpinLock = SPIN_LOCK_RELEASED;
73 _ReadWriteBarrier();
74
75 return SpinLock;
76 }
77
78 /**
79 Waits until a spin lock can be placed in the acquired state.
80
81 This function checks the state of the spin lock specified by SpinLock. If
82 SpinLock is in the released state, then this function places SpinLock in the
83 acquired state and returns SpinLock. Otherwise, this function waits
84 indefinitely for the spin lock to be released, and then places it in the
85 acquired state and returns SpinLock. All state transitions of SpinLock must
86 be performed using MP safe mechanisms.
87
88 If SpinLock is NULL, then ASSERT().
89 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
90 If PcdSpinLockTimeout is not zero, and SpinLock is can not be acquired in
91 PcdSpinLockTimeout microseconds, then ASSERT().
92
93 @param SpinLock A pointer to the spin lock to place in the acquired state.
94
95 @return SpinLock acquired the lock.
96
97 **/
98 SPIN_LOCK *
99 EFIAPI
100 AcquireSpinLock (
101 IN OUT SPIN_LOCK *SpinLock
102 )
103 {
104 UINT64 Current;
105 UINT64 Previous;
106 UINT64 Total;
107 UINT64 Start;
108 UINT64 End;
109 UINT64 Timeout;
110 INT64 Cycle;
111 INT64 Delta;
112
113 if (PcdGet32 (PcdSpinLockTimeout) == 0) {
114 while (!AcquireSpinLockOrFail (SpinLock)) {
115 CpuPause ();
116 }
117 } else if (!AcquireSpinLockOrFail (SpinLock)) {
118 //
119 // Get the current timer value
120 //
121 Current = GetPerformanceCounter();
122
123 //
124 // Initialize local variables
125 //
126 Start = 0;
127 End = 0;
128 Total = 0;
129
130 //
131 // Retrieve the performance counter properties and compute the number of performance
132 // counter ticks required to reach the timeout
133 //
134 Timeout = DivU64x32 (
135 MultU64x32 (
136 GetPerformanceCounterProperties (&Start, &End),
137 PcdGet32 (PcdSpinLockTimeout)
138 ),
139 1000000
140 );
141 Cycle = End - Start;
142 if (Cycle < 0) {
143 Cycle = -Cycle;
144 }
145 Cycle++;
146
147 while (!AcquireSpinLockOrFail (SpinLock)) {
148 CpuPause ();
149 Previous = Current;
150 Current = GetPerformanceCounter();
151 Delta = (INT64) (Current - Previous);
152 if (Start > End) {
153 Delta = -Delta;
154 }
155 if (Delta < 0) {
156 Delta += Cycle;
157 }
158 Total += Delta;
159 ASSERT (Total < Timeout);
160 }
161 }
162 return SpinLock;
163 }
164
165 /**
166 Attempts to place a spin lock in the acquired state.
167
168 This function checks the state of the spin lock specified by SpinLock. If
169 SpinLock is in the released state, then this function places SpinLock in the
170 acquired state and returns TRUE. Otherwise, FALSE is returned. All state
171 transitions of SpinLock must be performed using MP safe mechanisms.
172
173 If SpinLock is NULL, then ASSERT().
174 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
175
176 @param SpinLock A pointer to the spin lock to place in the acquired state.
177
178 @retval TRUE SpinLock was placed in the acquired state.
179 @retval FALSE SpinLock could not be acquired.
180
181 **/
182 BOOLEAN
183 EFIAPI
184 AcquireSpinLockOrFail (
185 IN OUT SPIN_LOCK *SpinLock
186 )
187 {
188 SPIN_LOCK LockValue;
189 VOID *Result;
190
191 ASSERT (SpinLock != NULL);
192
193 LockValue = *SpinLock;
194 ASSERT (LockValue == SPIN_LOCK_ACQUIRED || LockValue == SPIN_LOCK_RELEASED);
195
196 _ReadWriteBarrier ();
197 Result = InterlockedCompareExchangePointer (
198 (VOID**)SpinLock,
199 (VOID*)SPIN_LOCK_RELEASED,
200 (VOID*)SPIN_LOCK_ACQUIRED
201 );
202
203 _ReadWriteBarrier ();
204 return (BOOLEAN) (Result == (VOID*) SPIN_LOCK_RELEASED);
205 }
206
207 /**
208 Releases a spin lock.
209
210 This function places the spin lock specified by SpinLock in the release state
211 and returns SpinLock.
212
213 If SpinLock is NULL, then ASSERT().
214 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
215
216 @param SpinLock A pointer to the spin lock to release.
217
218 @return SpinLock released the lock.
219
220 **/
221 SPIN_LOCK *
222 EFIAPI
223 ReleaseSpinLock (
224 IN OUT SPIN_LOCK *SpinLock
225 )
226 {
227 SPIN_LOCK LockValue;
228
229 ASSERT (SpinLock != NULL);
230
231 LockValue = *SpinLock;
232 ASSERT (LockValue == SPIN_LOCK_ACQUIRED || LockValue == SPIN_LOCK_RELEASED);
233
234 _ReadWriteBarrier ();
235 *SpinLock = SPIN_LOCK_RELEASED;
236 _ReadWriteBarrier ();
237
238 return SpinLock;
239 }
240
241 /**
242 Performs an atomic increment of an 32-bit unsigned integer.
243
244 Performs an atomic increment of the 32-bit unsigned integer specified by
245 Value and returns the incremented value. The increment operation must be
246 performed using MP safe mechanisms.
247
248 If Value is NULL, then ASSERT().
249
250 @param Value A pointer to the 32-bit value to increment.
251
252 @return The incremented value.
253
254 **/
255 UINT32
256 EFIAPI
257 InterlockedIncrement (
258 IN volatile UINT32 *Value
259 )
260 {
261 ASSERT (Value != NULL);
262 return InternalSyncIncrement (Value);
263 }
264
265 /**
266 Performs an atomic decrement of an 32-bit unsigned integer.
267
268 Performs an atomic decrement of the 32-bit unsigned integer specified by
269 Value and returns the decremented value. The decrement operation must be
270 performed using MP safe mechanisms.
271
272 If Value is NULL, then ASSERT().
273
274 @param Value A pointer to the 32-bit value to decrement.
275
276 @return The decremented value.
277
278 **/
279 UINT32
280 EFIAPI
281 InterlockedDecrement (
282 IN volatile UINT32 *Value
283 )
284 {
285 ASSERT (Value != NULL);
286 return InternalSyncDecrement (Value);
287 }
288
289 /**
290 Performs an atomic compare exchange operation on a 16-bit unsigned integer.
291
292 Performs an atomic compare exchange operation on the 16-bit unsigned integer
293 specified by Value. If Value is equal to CompareValue, then Value is set to
294 ExchangeValue and CompareValue is returned. If Value is not equal to CompareValue,
295 then Value is returned. The compare exchange operation must be performed using
296 MP safe mechanisms.
297
298 If Value is NULL, then ASSERT().
299
300 @param Value A pointer to the 16-bit value for the compare exchange
301 operation.
302 @param CompareValue A 16-bit value used in a compare operation.
303 @param ExchangeValue A 16-bit value used in an exchange operation.
304
305 @return The original *Value before exchange.
306
307 **/
308 UINT16
309 EFIAPI
310 InterlockedCompareExchange16 (
311 IN OUT volatile UINT16 *Value,
312 IN UINT16 CompareValue,
313 IN UINT16 ExchangeValue
314 )
315 {
316 ASSERT (Value != NULL);
317 return InternalSyncCompareExchange16 (Value, CompareValue, ExchangeValue);
318 }
319
320 /**
321 Performs an atomic compare exchange operation on a 32-bit unsigned integer.
322
323 Performs an atomic compare exchange operation on the 32-bit unsigned integer
324 specified by Value. If Value is equal to CompareValue, then Value is set to
325 ExchangeValue and CompareValue is returned. If Value is not equal to CompareValue,
326 then Value is returned. The compare exchange operation must be performed using
327 MP safe mechanisms.
328
329 If Value is NULL, then ASSERT().
330
331 @param Value A pointer to the 32-bit value for the compare exchange
332 operation.
333 @param CompareValue A 32-bit value used in a compare operation.
334 @param ExchangeValue A 32-bit value used in an exchange operation.
335
336 @return The original *Value before exchange.
337
338 **/
339 UINT32
340 EFIAPI
341 InterlockedCompareExchange32 (
342 IN OUT volatile UINT32 *Value,
343 IN UINT32 CompareValue,
344 IN UINT32 ExchangeValue
345 )
346 {
347 ASSERT (Value != NULL);
348 return InternalSyncCompareExchange32 (Value, CompareValue, ExchangeValue);
349 }
350
351 /**
352 Performs an atomic compare exchange operation on a 64-bit unsigned integer.
353
354 Performs an atomic compare exchange operation on the 64-bit unsigned integer specified
355 by Value. If Value is equal to CompareValue, then Value is set to ExchangeValue and
356 CompareValue is returned. If Value is not equal to CompareValue, then Value is returned.
357 The compare exchange operation must be performed using MP safe mechanisms.
358
359 If Value is NULL, then ASSERT().
360
361 @param Value A pointer to the 64-bit value for the compare exchange
362 operation.
363 @param CompareValue A 64-bit value used in a compare operation.
364 @param ExchangeValue A 64-bit value used in an exchange operation.
365
366 @return The original *Value before exchange.
367
368 **/
369 UINT64
370 EFIAPI
371 InterlockedCompareExchange64 (
372 IN OUT volatile UINT64 *Value,
373 IN UINT64 CompareValue,
374 IN UINT64 ExchangeValue
375 )
376 {
377 ASSERT (Value != NULL);
378 return InternalSyncCompareExchange64 (Value, CompareValue, ExchangeValue);
379 }
380
381 /**
382 Performs an atomic compare exchange operation on a pointer value.
383
384 Performs an atomic compare exchange operation on the pointer value specified
385 by Value. If Value is equal to CompareValue, then Value is set to
386 ExchangeValue and CompareValue is returned. If Value is not equal to
387 CompareValue, then Value is returned. The compare exchange operation must be
388 performed using MP safe mechanisms.
389
390 If Value is NULL, then ASSERT().
391
392 @param Value A pointer to the pointer value for the compare exchange
393 operation.
394 @param CompareValue A pointer value used in a compare operation.
395 @param ExchangeValue A pointer value used in an exchange operation.
396
397 @return The original *Value before exchange.
398 **/
399 VOID *
400 EFIAPI
401 InterlockedCompareExchangePointer (
402 IN OUT VOID * volatile *Value,
403 IN VOID *CompareValue,
404 IN VOID *ExchangeValue
405 )
406 {
407 UINT8 SizeOfValue;
408
409 SizeOfValue = (UINT8) sizeof (*Value);
410
411 switch (SizeOfValue) {
412 case sizeof (UINT32):
413 return (VOID*)(UINTN)InterlockedCompareExchange32 (
414 (volatile UINT32*)Value,
415 (UINT32)(UINTN)CompareValue,
416 (UINT32)(UINTN)ExchangeValue
417 );
418 case sizeof (UINT64):
419 return (VOID*)(UINTN)InterlockedCompareExchange64 (
420 (volatile UINT64*)Value,
421 (UINT64)(UINTN)CompareValue,
422 (UINT64)(UINTN)ExchangeValue
423 );
424 default:
425 ASSERT (FALSE);
426 return NULL;
427 }
428 }