Updated MSA file for EBC.
[mirror_edk2.git] / MdePkg / Library / BaseLib / SynchronizationMsc.c
1 /** @file
2 Implementation of synchronization functions.
3
4 Copyright (c) 2006 - 2007, Intel Corporation<BR>
5 All rights reserved. This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 Module Name: SynchronizationMsc.c
14
15 **/
16
17 #include "BaseLibInternals.h"
18
19 //
20 // Microsoft Visual Studio 7.1 Function Prototypes for read write barrier Intrinsics
21 //
22 void _ReadWriteBarrier (void);
23 #pragma intrinsic(_ReadWriteBarrier)
24
25
26 #define SPIN_LOCK_RELEASED ((UINTN) 1)
27 #define SPIN_LOCK_ACQUIRED ((UINTN) 2)
28
29 /**
30 Retrieves the architecture specific spin lock alignment requirements for
31 optimal spin lock performance.
32
33 This function retrieves the spin lock alignment requirements for optimal
34 performance on a given CPU architecture. The spin lock alignment must be a
35 power of two and is returned by this function. If there are no alignment
36 requirements, then 1 must be returned. The spin lock synchronization
37 functions must function correctly if the spin lock size and alignment values
38 returned by this function are not used at all. These values are hints to the
39 consumers of the spin lock synchronization functions to obtain optimal spin
40 lock performance.
41
42 @return The architecture specific spin lock alignment.
43
44 **/
45 UINTN
46 EFIAPI
47 GetSpinLockProperties (
48 VOID
49 )
50 {
51 // @bug May use a PCD entry to determine this alignment.
52 return 32;
53 }
54
55 /**
56 Initializes a spin lock to the released state and returns the spin lock.
57
58 This function initializes the spin lock specified by SpinLock to the released
59 state, and returns SpinLock. Optimal performance can be achieved by calling
60 GetSpinLockProperties() to determine the size and alignment requirements for
61 SpinLock.
62
63 If SpinLock is NULL, then ASSERT().
64
65 @param SpinLock A pointer to the spin lock to initialize to the released
66 state.
67
68 @return SpinLock
69
70 **/
71 SPIN_LOCK *
72 EFIAPI
73 InitializeSpinLock (
74 OUT SPIN_LOCK *SpinLock
75 )
76 {
77 ASSERT (SpinLock != NULL);
78
79 _ReadWriteBarrier();
80 *SpinLock = SPIN_LOCK_RELEASED;
81 _ReadWriteBarrier();
82
83 return SpinLock;
84 }
85
86 /**
87 Waits until a spin lock can be placed in the acquired state.
88
89 This function checks the state of the spin lock specified by SpinLock. If
90 SpinLock is in the released state, then this function places SpinLock in the
91 acquired state and returns SpinLock. Otherwise, this function waits
92 indefinitely for the spin lock to be released, and then places it in the
93 acquired state and returns SpinLock. All state transitions of SpinLock must
94 be performed using MP safe mechanisms.
95
96 If SpinLock is NULL, then ASSERT().
97 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
98 If PcdSpinLockTimeout is not zero, and SpinLock is can not be acquired in
99 PcdSpinLockTimeout microseconds, then ASSERT().
100
101 @param SpinLock A pointer to the spin lock to place in the acquired state.
102
103 @return SpinLock
104
105 **/
106 SPIN_LOCK *
107 EFIAPI
108 AcquireSpinLock (
109 IN OUT SPIN_LOCK *SpinLock
110 )
111 {
112 UINT64 Tick;
113 UINT64 Start, End;
114 UINT64 Timeout;
115
116 Tick = 0;
117 Start = 0;
118 End = 0;
119 if (PcdGet32 (PcdSpinLockTimeout) > 0) {
120 Tick = GetPerformanceCounter ();
121 Timeout = DivU64x32 (
122 MultU64x32 (
123 GetPerformanceCounterProperties (&Start, &End),
124 PcdGet32 (PcdSpinLockTimeout)
125 ),
126 1000000
127 );
128 if (Start < End) {
129 Tick += Timeout;
130 } else {
131 Tick -= Timeout;
132 }
133 }
134
135 while (!AcquireSpinLockOrFail (SpinLock)) {
136 CpuPause ();
137 ASSERT ((Start < End) ^ (Tick <= GetPerformanceCounter ()));
138 }
139 return SpinLock;
140 }
141
142 /**
143 Attempts to place a spin lock in the acquired state.
144
145 This function checks the state of the spin lock specified by SpinLock. If
146 SpinLock is in the released state, then this function places SpinLock in the
147 acquired state and returns TRUE. Otherwise, FALSE is returned. All state
148 transitions of SpinLock must be performed using MP safe mechanisms.
149
150 If SpinLock is NULL, then ASSERT().
151 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
152
153 @param SpinLock A pointer to the spin lock to place in the acquired state.
154
155 @retval TRUE SpinLock was placed in the acquired state.
156 @retval FALSE SpinLock could not be acquired.
157
158 **/
159 BOOLEAN
160 EFIAPI
161 AcquireSpinLockOrFail (
162 IN OUT SPIN_LOCK *SpinLock
163 )
164 {
165 SPIN_LOCK LockValue;
166 VOID *Result;
167
168 ASSERT (SpinLock != NULL);
169
170 LockValue = *SpinLock;
171 ASSERT (LockValue == SPIN_LOCK_ACQUIRED || LockValue == SPIN_LOCK_RELEASED);
172
173 _ReadWriteBarrier ();
174 Result = InterlockedCompareExchangePointer (
175 (VOID**)SpinLock,
176 (VOID*)SPIN_LOCK_RELEASED,
177 (VOID*)SPIN_LOCK_ACQUIRED
178 );
179
180 _ReadWriteBarrier ();
181 return (BOOLEAN) (Result == (VOID*) SPIN_LOCK_RELEASED);
182 }
183
184 /**
185 Releases a spin lock.
186
187 This function places the spin lock specified by SpinLock in the release state
188 and returns SpinLock.
189
190 If SpinLock is NULL, then ASSERT().
191 If SpinLock was not initialized with InitializeSpinLock(), then ASSERT().
192
193 @param SpinLock A pointer to the spin lock to release.
194
195 @return SpinLock
196
197 **/
198 SPIN_LOCK *
199 EFIAPI
200 ReleaseSpinLock (
201 IN OUT SPIN_LOCK *SpinLock
202 )
203 {
204 SPIN_LOCK LockValue;
205
206 ASSERT (SpinLock != NULL);
207
208 LockValue = *SpinLock;
209 ASSERT (LockValue == SPIN_LOCK_ACQUIRED || LockValue == SPIN_LOCK_RELEASED);
210
211 _ReadWriteBarrier ();
212 *SpinLock = SPIN_LOCK_RELEASED;
213 _ReadWriteBarrier ();
214
215 return SpinLock;
216 }
217
218 /**
219 Performs an atomic increment of an 32-bit unsigned integer.
220
221 Performs an atomic increment of the 32-bit unsigned integer specified by
222 Value and returns the incremented value. The increment operation must be
223 performed using MP safe mechanisms. The state of the return value is not
224 guaranteed to be MP safe.
225
226 If Value is NULL, then ASSERT().
227
228 @param Value A pointer to the 32-bit value to increment.
229
230 @return The incremented value.
231
232 **/
233 UINT32
234 EFIAPI
235 InterlockedIncrement (
236 IN UINT32 *Value
237 )
238 {
239 ASSERT (Value != NULL);
240 return InternalSyncIncrement (Value);
241 }
242
243 /**
244 Performs an atomic decrement of an 32-bit unsigned integer.
245
246 Performs an atomic decrement of the 32-bit unsigned integer specified by
247 Value and returns the decremented value. The decrement operation must be
248 performed using MP safe mechanisms. The state of the return value is not
249 guaranteed to be MP safe.
250
251 If Value is NULL, then ASSERT().
252
253 @param Value A pointer to the 32-bit value to decrement.
254
255 @return The decremented value.
256
257 **/
258 UINT32
259 EFIAPI
260 InterlockedDecrement (
261 IN UINT32 *Value
262 )
263 {
264 ASSERT (Value != NULL);
265 return InternalSyncDecrement (Value);
266 }
267
268 /**
269 Performs an atomic compare exchange operation on a 32-bit unsigned integer.
270
271 Performs an atomic compare exchange operation on the 32-bit unsigned integer
272 specified by Value. If Value is equal to CompareValue, then Value is set to
273 ExchangeValue and CompareValue is returned. If Value is not equal to CompareValue,
274 then Value is returned. The compare exchange operation must be performed using
275 MP safe mechanisms.
276
277 If Value is NULL, then ASSERT().
278
279 @param Value A pointer to the 32-bit value for the compare exchange
280 operation.
281 @param CompareValue 32-bit value used in compare operation.
282 @param ExchangeValue 32-bit value used in exchange operation.
283
284 @return The original *Value before exchange.
285
286 **/
287 UINT32
288 EFIAPI
289 InterlockedCompareExchange32 (
290 IN OUT UINT32 *Value,
291 IN UINT32 CompareValue,
292 IN UINT32 ExchangeValue
293 )
294 {
295 ASSERT (Value != NULL);
296 return InternalSyncCompareExchange32 (Value, CompareValue, ExchangeValue);
297 }
298
299 /**
300 Performs an atomic compare exchange operation on a 64-bit unsigned integer.
301
302 Performs an atomic compare exchange operation on the 64-bit unsigned integer specified
303 by Value. If Value is equal to CompareValue, then Value is set to ExchangeValue and
304 CompareValue is returned. If Value is not equal to CompareValue, then Value is returned.
305 The compare exchange operation must be performed using MP safe mechanisms.
306
307 If Value is NULL, then ASSERT().
308
309 @param Value A pointer to the 64-bit value for the compare exchange
310 operation.
311 @param CompareValue 64-bit value used in compare operation.
312 @param ExchangeValue 64-bit value used in exchange operation.
313
314 @return The original *Value before exchange.
315
316 **/
317 UINT64
318 EFIAPI
319 InterlockedCompareExchange64 (
320 IN OUT UINT64 *Value,
321 IN UINT64 CompareValue,
322 IN UINT64 ExchangeValue
323 )
324 {
325 ASSERT (Value != NULL);
326 return InternalSyncCompareExchange64 (Value, CompareValue, ExchangeValue);
327 }
328
329 /**
330 Performs an atomic compare exchange operation on a pointer value.
331
332 Performs an atomic compare exchange operation on the pointer value specified
333 by Value. If Value is equal to CompareValue, then Value is set to
334 ExchangeValue and CompareValue is returned. If Value is not equal to
335 CompareValue, then Value is returned. The compare exchange operation must be
336 performed using MP safe mechanisms.
337
338 If Value is NULL, then ASSERT().
339
340 @param Value A pointer to the pointer value for the compare exchange
341 operation.
342 @param CompareValue Pointer value used in compare operation.
343 @param ExchangeValue Pointer value used in exchange operation.
344
345 **/
346 VOID *
347 EFIAPI
348 InterlockedCompareExchangePointer (
349 IN OUT VOID **Value,
350 IN VOID *CompareValue,
351 IN VOID *ExchangeValue
352 )
353 {
354 UINT8 SizeOfValue;
355
356 SizeOfValue = sizeof (*Value);
357
358 switch (SizeOfValue) {
359 case sizeof (UINT32):
360 return (VOID*)(UINTN)InterlockedCompareExchange32 (
361 (UINT32*)Value,
362 (UINT32)(UINTN)CompareValue,
363 (UINT32)(UINTN)ExchangeValue
364 );
365 case sizeof (UINT64):
366 return (VOID*)(UINTN)InterlockedCompareExchange64 (
367 (UINT64*)Value,
368 (UINT64)(UINTN)CompareValue,
369 (UINT64)(UINTN)ExchangeValue
370 );
371 default:
372 ASSERT (FALSE);
373 return NULL;
374 }
375 }