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