![]() |
pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
|
00001 /* 00002 ------------------------------------------------------------------------------- 00003 This file is part of the Plink, Plonk, Plank libraries 00004 by Martin Robinson 00005 00006 http://code.google.com/p/pl-nk/ 00007 00008 Copyright University of the West of England, Bristol 2011-14 00009 All rights reserved. 00010 00011 Redistribution and use in source and binary forms, with or without 00012 modification, are permitted provided that the following conditions are met: 00013 00014 * Redistributions of source code must retain the above copyright 00015 notice, this list of conditions and the following disclaimer. 00016 * Redistributions in binary form must reproduce the above copyright 00017 notice, this list of conditions and the following disclaimer in the 00018 documentation and/or other materials provided with the distribution. 00019 * Neither the name of University of the West of England, Bristol nor 00020 the names of its contributors may be used to endorse or promote products 00021 derived from this software without specific prior written permission. 00022 00023 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 00024 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00025 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00026 DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF THE WEST OF ENGLAND, BRISTOL BE 00027 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 00028 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE 00029 GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00030 HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00031 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 00032 OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00033 00034 This software makes use of third party libraries. For more information see: 00035 doc/license.txt included in the distribution. 00036 ------------------------------------------------------------------------------- 00037 */ 00038 00039 // help prevent accidental inclusion other than via the intended header 00040 #if PLANK_INLINING_FUNCTIONS 00041 00042 // Linux 64 and Android 64 00043 00044 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 00045 00046 #define PLANK_ATOMIC_XBITS 64 00047 #define PLANK_ATOMIC_XREFCOUNTBITS 32 00048 #define PLANK_ATOMIC_XWEAKCOUNTBITS 32 00049 #define PLANK_ATOMIC_XREFCOUNTMAX 0x00000000FFFFFFFFUL 00050 #define PLANK_ATOMIC_XREFCOUNTMASK PLANK_ATOMIC_XREFCOUNTMAX 00051 #define PLANK_ATOMIC_XWEAKCOUNTMAX 0x00000000FFFFFFFFUL 00052 #define PLANK_ATOMIC_XWEAKCOUNTMASK 0xFFFFFFFF00000000UL 00053 #define PLANK_ATOMIC_XMAX 0xFFFFFFFFFFFFFFFFUL 00054 #define PLANK_ATOMIC_PMASK 0xFFFFFFFFFFFFFFFFUL 00055 00056 #if !DOXYGEN 00057 typedef struct PlankAtomicI 00058 { 00059 volatile PlankI value; 00060 } PlankAtomicI PLANK_ALIGN(4); 00061 00062 typedef struct PlankAtomicF 00063 { 00064 volatile PlankF value; 00065 } PlankAtomicF PLANK_ALIGN(4); 00066 00067 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00068 typedef struct PlankAtomicL 00069 { 00070 volatile PlankL value; 00071 } PlankAtomicL PLANK_ALIGN(8); 00072 00073 typedef struct PlankAtomicLL 00074 { 00075 volatile PlankLL value; 00076 } PlankAtomicLL PLANK_ALIGN(8); 00077 00078 typedef struct PlankAtomicD 00079 { 00080 volatile PlankD value; 00081 } PlankAtomicD PLANK_ALIGN(8); 00082 00083 typedef struct PlankAtomicP 00084 { 00085 volatile PlankP ptr; 00086 } PlankAtomicP PLANK_ALIGN(8); 00087 #else //!__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00088 #include "../../../core/plank_SpinLock.h" 00089 typedef struct PlankAtomicL 00090 { 00091 volatile PlankL value; 00092 PlankSpinLock lock; 00093 } PlankAtomicL PLANK_ALIGN(8); 00094 00095 typedef struct PlankAtomicLL 00096 { 00097 volatile PlankLL value; 00098 PlankSpinLock lock; 00099 } PlankAtomicLL PLANK_ALIGN(8); 00100 00101 typedef struct PlankAtomicD 00102 { 00103 volatile PlankD value; 00104 PlankSpinLock lock; 00105 } PlankAtomicD PLANK_ALIGN(8); 00106 00107 typedef struct PlankAtomicP 00108 { 00109 volatile PlankP ptr; 00110 PlankSpinLock lock; 00111 } PlankAtomicP PLANK_ALIGN(8); 00112 #endif 00113 00114 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 00115 typedef struct PlankAtomicPX 00116 { 00117 volatile PlankP ptr; 00118 volatile PlankUL extra; 00119 } PlankAtomicPX PLANK_ALIGN(16); 00120 #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) 00121 #include "../../../core/plank_ThreadSpinLock.h" 00122 typedef struct PlankAtomicPX 00123 { 00124 volatile PlankP ptr; 00125 volatile PlankUL extra; 00126 PlankThreadSpinLock lock; 00127 } PlankAtomicPX PLANK_ALIGN(16); 00128 #else 00129 #include "../../../core/plank_SpinLock.h" 00130 typedef struct PlankAtomicPX 00131 { 00132 volatile PlankP ptr; 00133 volatile PlankUL extra; 00134 PlankSpinLock lock; 00135 } PlankAtomicPX PLANK_ALIGN(16); 00136 #endif 00137 00138 #endif 00139 00140 static inline void pl_AtomicMemoryBarrier() 00141 { 00142 __sync_synchronize(); 00143 } 00144 00145 //------------------------------------------------------------------------------ 00146 00147 static inline PlankResult pl_AtomicI_Init (PlankAtomicIRef p) 00148 { 00149 if (p == PLANK_NULL) 00150 return PlankResult_MemoryError; 00151 00152 pl_MemoryZero (p, sizeof (PlankAtomicI)); 00153 00154 return PlankResult_OK; 00155 } 00156 00157 static inline PlankResult pl_AtomicI_DeInit (PlankAtomicIRef p) 00158 { 00159 if (p == PLANK_NULL) 00160 return PlankResult_MemoryError; 00161 return PlankResult_OK; 00162 } 00163 00164 static inline PlankI pl_AtomicI_Get (PlankAtomicIRef p) 00165 { 00166 return p->value; // should be aligned anyway and volatile so OK // pl_AtomicI_Add (p, 0); 00167 } 00168 00169 static inline PlankI pl_AtomicI_GetUnchecked (PlankAtomicIRef p) 00170 { 00171 return p->value; 00172 } 00173 00174 static inline PlankI pl_AtomicI_Swap (PlankAtomicIRef p, PlankI newValue) 00175 { 00176 PlankI oldValue; 00177 PlankB success; 00178 00179 do { 00180 oldValue = *(PlankI*)p; 00181 success = pl_AtomicI_CompareAndSwap (p, oldValue, newValue); 00182 } while (!success); 00183 00184 return oldValue; 00185 } 00186 00187 static inline void pl_AtomicI_SwapOther (PlankAtomicIRef p1, PlankAtomicIRef p2) 00188 { 00189 PlankI value1, value2; 00190 PlankB success; 00191 00192 do { 00193 value1 = *(PlankI*)p1; 00194 value2 = *(PlankI*)p2; 00195 success = pl_AtomicI_CompareAndSwap (p1, value1, value2); 00196 } while (!success); 00197 00198 *(PlankI*)p2 = value1; 00199 } 00200 00201 static inline void pl_AtomicI_Set (PlankAtomicIRef p, PlankI newValue) 00202 { 00203 pl_AtomicI_Swap (p, newValue); 00204 } 00205 00206 static inline PlankI pl_AtomicI_Add (PlankAtomicIRef p, PlankI operand) 00207 { 00208 return __sync_add_and_fetch ((volatile PlankI*)p, operand); 00209 } 00210 00211 static inline PlankB pl_AtomicI_CompareAndSwap (PlankAtomicIRef p, PlankI oldValue, PlankI newValue) 00212 { 00213 return __sync_bool_compare_and_swap ((volatile PlankI*)p, 00214 oldValue, 00215 newValue); 00216 } 00217 00218 static inline PlankI pl_AtomicI_Subtract (PlankAtomicIRef p, PlankI operand) 00219 { 00220 return pl_AtomicI_Add (p, -operand); 00221 } 00222 00223 static inline PlankI pl_AtomicI_Increment (PlankAtomicIRef p) 00224 { 00225 return pl_AtomicI_Add (p, 1); 00226 } 00227 00228 static inline PlankI pl_AtomicI_Decrement (PlankAtomicIRef p) 00229 { 00230 return pl_AtomicI_Add (p, -1); 00231 } 00232 00233 //------------------------------------------------------------------------------ 00234 00235 static inline PlankResult pl_AtomicL_Init (PlankAtomicLRef p) 00236 { 00237 if (p == PLANK_NULL) 00238 return PlankResult_MemoryError; 00239 00240 pl_MemoryZero (p, sizeof (PlankAtomicL)); 00241 00242 return PlankResult_OK; 00243 } 00244 00245 static inline PlankResult pl_AtomicL_DeInit (PlankAtomicLRef p) 00246 { 00247 if (p == PLANK_NULL) 00248 return PlankResult_MemoryError; 00249 return PlankResult_OK; 00250 } 00251 00252 static inline PlankL pl_AtomicL_Get (PlankAtomicLRef p) 00253 { 00254 return p->value; // should be aligned anyway and volatile so OK // pl_AtomicL_Add (p, (PlankL)0); 00255 } 00256 00257 static inline PlankL pl_AtomicL_GetUnchecked (PlankAtomicLRef p) 00258 { 00259 return p->value; 00260 } 00261 00262 static inline PlankL pl_AtomicL_Swap (PlankAtomicLRef p, PlankL newValue) 00263 { 00264 PlankL oldValue; 00265 PlankB success; 00266 00267 do { 00268 oldValue = *(PlankL*)p; 00269 success = pl_AtomicL_CompareAndSwap (p, oldValue, newValue); 00270 } while (!success); 00271 00272 return oldValue; 00273 } 00274 00275 static inline void pl_AtomicL_SwapOther (PlankAtomicLRef p1, PlankAtomicLRef p2) 00276 { 00277 PlankL value1, value2; 00278 PlankB success; 00279 00280 do { 00281 value1 = *(PlankL*)p1; 00282 value2 = *(PlankL*)p2; 00283 success = pl_AtomicL_CompareAndSwap (p1, value1, value2); 00284 } while (!success); 00285 00286 *(PlankL*)p2 = value1; 00287 } 00288 00289 static inline void pl_AtomicL_Set (PlankAtomicLRef p, PlankL newValue) 00290 { 00291 pl_AtomicL_Swap (p, newValue); 00292 } 00293 00294 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00295 static inline PlankL pl_AtomicL_Add (PlankAtomicLRef p, PlankL operand) 00296 { 00297 return __sync_add_and_fetch ((volatile PlankL*)p, operand); 00298 } 00299 00300 static inline PlankB pl_AtomicL_CompareAndSwap (PlankAtomicLRef p, PlankL oldValue, PlankL newValue) 00301 { 00302 return __sync_bool_compare_and_swap ((volatile PlankL*)p, 00303 oldValue, 00304 newValue); 00305 } 00306 #else 00307 static inline PlankL pl_AtomicL_Add (PlankAtomicLRef p, PlankL operand) 00308 { 00309 PlankL oldValue, newValue; 00310 PlankB success; 00311 00312 do { 00313 oldValue = *(PlankLL*)p; 00314 newValue = oldValue + operand; 00315 success = pl_AtomicL_CompareAndSwap (p, oldValue, newValue); 00316 } while (!success); 00317 00318 return newValue; 00319 } 00320 00321 static inline PlankB pl_AtomicL_CompareAndSwap (PlankAtomicLRef p, PlankL oldValue, PlankL newValue) 00322 { 00323 if (! pl_SpinLock_TryLock (&p->lock)) 00324 return PLANK_FALSE; 00325 00326 if (p->value != oldValue) 00327 { 00328 pl_SpinLock_Unlock (&p->lock); 00329 return PLANK_FALSE; 00330 } 00331 00332 p->value = newValue; 00333 pl_SpinLock_Unlock (&p->lock); 00334 00335 return PLANK_TRUE; 00336 } 00337 #endif 00338 00339 static inline PlankL pl_AtomicL_Subtract (PlankAtomicLRef p, PlankL operand) 00340 { 00341 return pl_AtomicL_Add (p, -operand); 00342 } 00343 00344 static inline PlankL pl_AtomicL_Increment (PlankAtomicLRef p) 00345 { 00346 return pl_AtomicL_Add (p, (PlankL)1); 00347 } 00348 00349 static inline PlankL pl_AtomicL_Decrement (PlankAtomicLRef p) 00350 { 00351 return pl_AtomicL_Add (p, (PlankL)(-1)); 00352 } 00353 00354 //------------------------------------------------------------------------------ 00355 00356 static inline PlankResult pl_AtomicLL_Init (PlankAtomicLLRef p) 00357 { 00358 PlankResult result = PlankResult_OK; 00359 00360 if (p == PLANK_NULL) 00361 { 00362 result = PlankResult_MemoryError; 00363 goto exit; 00364 } 00365 00366 pl_MemoryZero (p, sizeof (PlankAtomicLL)); 00367 00368 exit: 00369 return result; 00370 } 00371 00372 static inline PlankResult pl_AtomicLL_DeInit (PlankAtomicLLRef p) 00373 { 00374 PlankResult result = PlankResult_OK; 00375 00376 if (p == PLANK_NULL) 00377 { 00378 result = PlankResult_MemoryError; 00379 goto exit; 00380 } 00381 00382 exit: 00383 return result; 00384 } 00385 00386 static inline PlankLL pl_AtomicLL_Get (PlankAtomicLLRef p) 00387 { 00388 return p->value; // should be aligned anyway and volatile so OK // pl_AtomicL_Add (p, (PlankL)0); 00389 } 00390 00391 static inline PlankLL pl_AtomicLL_GetUnchecked (PlankAtomicLLRef p) 00392 { 00393 return p->value; 00394 } 00395 00396 static inline PlankLL pl_AtomicLL_Swap (PlankAtomicLLRef p, PlankLL newValue) 00397 { 00398 PlankLL oldValue; 00399 PlankB success; 00400 00401 do { 00402 oldValue = *(PlankLL*)p; 00403 success = pl_AtomicLL_CompareAndSwap (p, oldValue, newValue); 00404 } while (!success); 00405 00406 return oldValue; 00407 } 00408 00409 static inline void pl_AtomicLL_SwapOther (PlankAtomicLLRef p1, PlankAtomicLLRef p2) 00410 { 00411 PlankLL value1, value2; 00412 PlankB success; 00413 00414 do { 00415 value1 = *(PlankLL*)p1; 00416 value2 = *(PlankLL*)p2; 00417 success = pl_AtomicLL_CompareAndSwap (p1, value1, value2); 00418 } while (!success); 00419 00420 *(PlankLL*)p2 = value1; 00421 } 00422 00423 static inline void pl_AtomicLL_Set (PlankAtomicLLRef p, PlankLL newValue) 00424 { 00425 pl_AtomicLL_Swap (p, newValue); 00426 } 00427 00428 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00429 static inline PlankLL pl_AtomicLL_Add (PlankAtomicLLRef p, PlankLL operand) 00430 { 00431 return __sync_add_and_fetch ((volatile PlankLL*)p, operand); 00432 } 00433 00434 static inline PlankB pl_AtomicLL_CompareAndSwap (PlankAtomicLLRef p, PlankLL oldValue, PlankLL newValue) 00435 { 00436 return __sync_bool_compare_and_swap ((volatile PlankLL*)p, 00437 oldValue, 00438 newValue); 00439 } 00440 #else 00441 static inline PlankLL pl_AtomicLL_Add (PlankAtomicLLRef p, PlankLL operand) 00442 { 00443 PlankLL oldValue, newValue; 00444 PlankB success; 00445 00446 do { 00447 oldValue = *(PlankLL*)p; 00448 newValue = oldValue + operand; 00449 success = pl_AtomicLL_CompareAndSwap (p, oldValue, newValue); 00450 } while (!success); 00451 00452 return newValue; 00453 } 00454 00455 static inline PlankB pl_AtomicLL_CompareAndSwap (PlankAtomicLLRef p, PlankLL oldValue, PlankLL newValue) 00456 { 00457 if (! pl_SpinLock_TryLock (&p->lock)) 00458 return PLANK_FALSE; 00459 00460 if (p->value != oldValue) 00461 { 00462 pl_SpinLock_Unlock (&p->lock); 00463 return PLANK_FALSE; 00464 } 00465 00466 p->value = newValue; 00467 pl_SpinLock_Unlock (&p->lock); 00468 00469 return PLANK_TRUE; 00470 } 00471 #endif 00472 00473 static inline PlankLL pl_AtomicLL_Subtract (PlankAtomicLLRef p, PlankLL operand) 00474 { 00475 return pl_AtomicLL_Add (p, -operand); 00476 } 00477 00478 static inline PlankLL pl_AtomicLL_Increment (PlankAtomicLLRef p) 00479 { 00480 return pl_AtomicLL_Add (p, (PlankLL)1); 00481 } 00482 00483 static inline PlankLL pl_AtomicLL_Decrement (PlankAtomicLLRef p) 00484 { 00485 return pl_AtomicLL_Add (p, (PlankLL)(-1)); 00486 } 00487 00488 //------------------------------------------------------------------------------ 00489 00490 static inline PlankResult pl_AtomicF_Init (PlankAtomicFRef p) 00491 { 00492 if (p == PLANK_NULL) 00493 return PlankResult_MemoryError; 00494 00495 pl_MemoryZero (p, sizeof (PlankAtomicF)); 00496 00497 return PlankResult_OK; 00498 } 00499 00500 static inline PlankResult pl_AtomicF_DeInit (PlankAtomicFRef p) 00501 { 00502 if (p == PLANK_NULL) 00503 return PlankResult_MemoryError; 00504 return PlankResult_OK; 00505 } 00506 00507 static inline PlankF pl_AtomicF_Get (PlankAtomicFRef p) 00508 { 00509 return p->value; // should be aligned anyway and volatile so OK 00510 } 00511 00512 static inline PlankF pl_AtomicF_GetUnchecked (PlankAtomicFRef p) 00513 { 00514 return p->value; 00515 } 00516 00517 static inline PlankF pl_AtomicF_Swap (PlankAtomicFRef p, PlankF newValue) 00518 { 00519 PlankF oldValue; 00520 PlankB success; 00521 00522 do 00523 { 00524 oldValue = *(PlankF*)p; 00525 success = pl_AtomicF_CompareAndSwap (p, oldValue, newValue); 00526 } while (!success); 00527 00528 return oldValue; 00529 } 00530 00531 static inline void pl_AtomicF_SwapOther (PlankAtomicFRef p1, PlankAtomicFRef p2) 00532 { 00533 PlankF value1, value2; 00534 PlankB success; 00535 00536 do { 00537 value1 = *(PlankF*)p1; 00538 value2 = *(PlankF*)p2; 00539 success = pl_AtomicF_CompareAndSwap (p1, value1, value2); 00540 } while (!success); 00541 00542 *(PlankF*)p2 = value1; 00543 } 00544 00545 static inline void pl_AtomicF_Set (PlankAtomicFRef p, PlankF newValue) 00546 { 00547 pl_AtomicF_Swap (p, newValue); 00548 } 00549 00550 static inline PlankF pl_AtomicF_Add (PlankAtomicFRef p, PlankF operand) 00551 { 00552 PlankF newValue, oldValue; 00553 PlankB success; 00554 00555 do { 00556 oldValue = *(PlankF*)p; 00557 newValue = oldValue + operand; 00558 success = pl_AtomicF_CompareAndSwap (p, oldValue, newValue); 00559 } while (!success); 00560 00561 return newValue; 00562 } 00563 00564 static inline PlankB pl_AtomicF_CompareAndSwap (PlankAtomicFRef p, PlankF oldValue, PlankF newValue) 00565 { 00566 return __sync_bool_compare_and_swap ((volatile PlankI*)p, 00567 *(PlankI*)&oldValue, 00568 *(PlankI*)&newValue); 00569 } 00570 00571 static inline PlankF pl_AtomicF_Subtract (PlankAtomicFRef p, PlankF operand) 00572 { 00573 return pl_AtomicF_Add (p, -operand); 00574 } 00575 00576 static inline PlankF pl_AtomicF_Increment (PlankAtomicFRef p) 00577 { 00578 return pl_AtomicF_Add (p, 1.f); 00579 } 00580 00581 static inline PlankF pl_AtomicF_Decrement (PlankAtomicFRef p) 00582 { 00583 return pl_AtomicF_Add (p, -1.f); 00584 } 00585 00586 //------------------------------------------------------------------------------ 00587 00588 static inline PlankResult pl_AtomicD_Init (PlankAtomicDRef p) 00589 { 00590 PlankResult result = PlankResult_OK; 00591 00592 if (p == PLANK_NULL) 00593 { 00594 result = PlankResult_MemoryError; 00595 goto exit; 00596 } 00597 00598 pl_MemoryZero (p, sizeof (PlankAtomicD)); 00599 00600 exit: 00601 return result; 00602 } 00603 00604 static inline PlankResult pl_AtomicD_DeInit (PlankAtomicDRef p) 00605 { 00606 PlankResult result = PlankResult_OK; 00607 00608 if (p == PLANK_NULL) 00609 { 00610 result = PlankResult_MemoryError; 00611 goto exit; 00612 } 00613 00614 exit: 00615 return result; 00616 } 00617 00618 static inline PlankD pl_AtomicD_Get (PlankAtomicDRef p) 00619 { 00620 return p->value; // should be aligned anyway and volatile so OK 00621 } 00622 00623 static inline PlankD pl_AtomicD_GetUnchecked (PlankAtomicDRef p) 00624 { 00625 return p->value; 00626 } 00627 00628 static inline PlankD pl_AtomicD_Swap (PlankAtomicDRef p, PlankD newValue) 00629 { 00630 PlankD oldValue; 00631 PlankB success; 00632 00633 do { 00634 oldValue = *(PlankD*)p; 00635 success = pl_AtomicD_CompareAndSwap (p, oldValue, newValue); 00636 } while (!success); 00637 00638 return oldValue; 00639 } 00640 00641 static inline void pl_AtomicD_SwapOther (PlankAtomicDRef p1, PlankAtomicDRef p2) 00642 { 00643 PlankD value1, value2; 00644 PlankB success; 00645 00646 do { 00647 value1 = *(PlankD*)p1; 00648 value2 = *(PlankD*)p2; 00649 success = pl_AtomicD_CompareAndSwap (p1, value1, value2); 00650 } while (!success); 00651 00652 *(PlankD*)p2 = value1; 00653 } 00654 00655 static inline void pl_AtomicD_Set (PlankAtomicDRef p, PlankD newValue) 00656 { 00657 pl_AtomicD_Swap (p, newValue); 00658 } 00659 00660 static inline PlankD pl_AtomicD_Add (PlankAtomicDRef p, PlankD operand) 00661 { 00662 PlankD newValue, oldValue; 00663 PlankB success; 00664 00665 do { 00666 oldValue = *(PlankD*)p; 00667 newValue = oldValue + operand; 00668 success = pl_AtomicD_CompareAndSwap (p, oldValue, newValue); 00669 } while (!success); 00670 00671 return newValue; 00672 } 00673 00674 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00675 static inline PlankB pl_AtomicD_CompareAndSwap (PlankAtomicDRef p, PlankD oldValue, PlankD newValue) 00676 { 00677 return __sync_bool_compare_and_swap ((volatile PlankLL*)p, 00678 *(PlankLL*)&oldValue, 00679 *(PlankLL*)&newValue); 00680 } 00681 #else 00682 static inline PlankB pl_AtomicD_CompareAndSwap (PlankAtomicDRef p, PlankD oldValue, PlankD newValue) 00683 { 00684 // must use an integer compare since comparing floating point 00685 // values doesn't do a bitwise comparison 00686 return pl_AtomicLL_CompareAndSwap ((PlankAtomicLLRef)p, 00687 *(PlankLL*)&oldValue, 00688 *(PlankLL*)&newValue); 00689 } 00690 #endif 00691 00692 static inline PlankD pl_AtomicD_Subtract (PlankAtomicDRef p, PlankD operand) 00693 { 00694 return pl_AtomicD_Add (p, -operand); 00695 } 00696 00697 static inline PlankD pl_AtomicD_Increment (PlankAtomicDRef p) 00698 { 00699 return pl_AtomicD_Add (p, 1.0); 00700 } 00701 00702 static inline PlankD pl_AtomicD_Decrement (PlankAtomicDRef p) 00703 { 00704 return pl_AtomicD_Add (p, -1.0); 00705 } 00706 00707 //------------------------------------------------------------------------------ 00708 00709 static inline PlankResult pl_AtomicP_Init (PlankAtomicPRef p) 00710 { 00711 if (p == PLANK_NULL) 00712 return PlankResult_MemoryError; 00713 00714 pl_MemoryZero (p, sizeof (PlankAtomicP)); 00715 00716 return PlankResult_OK; 00717 } 00718 00719 static inline PlankResult pl_AtomicP_DeInit (PlankAtomicPRef p) 00720 { 00721 if (p == PLANK_NULL) 00722 return PlankResult_MemoryError; 00723 return PlankResult_OK; 00724 } 00725 00726 static inline PlankP pl_AtomicP_Get (PlankAtomicPRef p) 00727 { 00728 return p->ptr; // should be aligned anyway and volatile so OK // pl_AtomicP_Add (p, (PlankL)0); 00729 } 00730 00731 static inline PlankP pl_AtomicP_GetUnchecked (PlankAtomicPRef p) 00732 { 00733 return p->ptr; 00734 } 00735 00736 static inline PlankP pl_AtomicP_Swap (PlankAtomicPRef p, PlankP newPtr) 00737 { 00738 PlankP oldPtr; 00739 PlankB success; 00740 00741 do { 00742 oldPtr = *(PlankP*)p; 00743 success = pl_AtomicP_CompareAndSwap (p, oldPtr, newPtr); 00744 } while (!success); 00745 00746 return oldPtr; 00747 } 00748 00749 static inline void pl_AtomicP_SwapOther (PlankAtomicPRef p1, PlankAtomicPRef p2) 00750 { 00751 PlankP value1, value2; 00752 PlankB success; 00753 00754 do { 00755 value1 = *(PlankP*)p1; 00756 value2 = *(PlankP*)p2; 00757 success = pl_AtomicP_CompareAndSwap (p1, value1, value2); 00758 } while (!success); 00759 00760 *(PlankP*)p2 = value1; 00761 } 00762 00763 static inline void pl_AtomicP_Set (PlankAtomicPRef p, PlankP newPtr) 00764 { 00765 pl_AtomicP_Swap (p, newPtr); 00766 } 00767 00768 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00769 static inline PlankP pl_AtomicP_Add (PlankAtomicPRef p, PlankL operand) 00770 { 00771 return (PlankP)__sync_add_and_fetch ((volatile PlankL*)p, operand); 00772 } 00773 00774 static inline PlankB pl_AtomicP_CompareAndSwap (PlankAtomicPRef p, PlankP oldValue, PlankP newValue) 00775 { 00776 return __sync_bool_compare_and_swap ((volatile PlankL*)p, 00777 *(PlankL*)&oldValue, 00778 *(PlankL*)&newValue); 00779 } 00780 #else 00781 static inline PlankP pl_AtomicP_Add (PlankAtomicPRef p, PlankL operand) 00782 { 00783 PlankP oldPtr, newPtr; 00784 PlankB success; 00785 00786 do { 00787 oldValue = *(PlankP*)p; 00788 newValue = (PlankUC*)oldValue + operand; 00789 success = pl_AtomicP_CompareAndSwap (p, oldPtr, newPtr); 00790 } while (!success); 00791 00792 return newValue; 00793 } 00794 00795 static inline PlankB pl_AtomicLL_CompareAndSwap (PlankAtomicPRef p, PlankP oldValue, PlankP newValue) 00796 { 00797 if (! pl_SpinLock_TryLock (&p->lock)) 00798 return PLANK_FALSE; 00799 00800 if (p->ptr != oldValue) 00801 { 00802 pl_SpinLock_Unlock (&p->lock); 00803 return PLANK_FALSE; 00804 } 00805 00806 p->ptr = newValue; 00807 pl_SpinLock_Unlock (&p->lock); 00808 00809 return PLANK_TRUE; 00810 } 00811 #endif 00812 00813 static inline PlankP pl_AtomicP_Subtract (PlankAtomicPRef p, PlankL operand) 00814 { 00815 return pl_AtomicP_Add (p, -operand); 00816 } 00817 00818 static inline PlankP pl_AtomicP_Increment (PlankAtomicPRef p) 00819 { 00820 return pl_AtomicP_Add (p, (PlankL)1); 00821 } 00822 00823 static inline PlankP pl_AtomicP_Decrement (PlankAtomicPRef p) 00824 { 00825 return pl_AtomicP_Add (p, (PlankL)(-1)); 00826 } 00827 00828 //------------------------------------------------------------------------------ 00829 00830 static inline PlankAtomicPXRef pl_AtomicPX_CreateAndInit() 00831 { 00832 PlankAtomicPXRef p = pl_AtomicPX_Create(); 00833 if (p != PLANK_NULL) pl_AtomicPX_Init (p); 00834 return p; 00835 } 00836 00837 static inline PlankAtomicPXRef pl_AtomicPX_Create() 00838 { 00839 PlankMemoryRef m; 00840 PlankAtomicPXRef p; 00841 00842 m = pl_MemoryGlobal(); 00843 p = (PlankAtomicPXRef)pl_Memory_AllocateBytes (m, sizeof (PlankAtomicPX)); 00844 00845 if (p != PLANK_NULL) 00846 pl_MemoryZero (p, sizeof (PlankAtomicPX)); 00847 00848 return p; 00849 } 00850 00851 static inline PlankResult pl_AtomicPX_Init (PlankAtomicPXRef p) 00852 { 00853 PlankResult result = PlankResult_OK; 00854 00855 if (p == PLANK_NULL) 00856 { 00857 result = PlankResult_MemoryError; 00858 goto exit; 00859 } 00860 00861 pl_MemoryZero (p, sizeof (PlankAtomicPX)); 00862 00863 exit: 00864 return result; 00865 } 00866 00867 static inline PlankResult pl_AtomicPX_DeInit (PlankAtomicPXRef p) 00868 { 00869 PlankResult result = PlankResult_OK; 00870 00871 if (p == PLANK_NULL) 00872 { 00873 result = PlankResult_MemoryError; 00874 goto exit; 00875 } 00876 00877 exit: 00878 return result; 00879 } 00880 00881 static inline PlankResult pl_AtomicPX_Destroy (PlankAtomicPXRef p) 00882 { 00883 PlankResult result; 00884 PlankMemoryRef m; 00885 00886 result = PlankResult_OK; 00887 m = pl_MemoryGlobal(); 00888 00889 if ((result = pl_AtomicPX_DeInit (p)) != PlankResult_OK) 00890 goto exit; 00891 00892 result = pl_Memory_Free (m, p); 00893 00894 exit: 00895 return result; 00896 } 00897 00898 static inline PlankP pl_AtomicPX_Get (PlankAtomicPXRef p) 00899 { 00900 return p->ptr; // should be aligned anyway and volatile so OK // pl_AtomicP_Get ((PlankAtomicPRef)p); 00901 } 00902 00903 static inline PlankP pl_AtomicPX_GetUnchecked (PlankAtomicPXRef p) 00904 { 00905 return p->ptr; 00906 } 00907 00908 static inline PlankUL pl_AtomicPX_GetExtra (PlankAtomicPXRef p) 00909 { 00910 return p->extra; // should be aligned anyway and volatile so OK // pl_AtomicL_Get ((PlankAtomicLRef)&(p->extra)); 00911 } 00912 00913 static inline PlankUL pl_AtomicPX_GetExtraUnchecked (PlankAtomicPXRef p) 00914 { 00915 return p->extra; 00916 } 00917 00918 static inline PlankP pl_AtomicPX_SwapAll (PlankAtomicPXRef p, PlankP newPtr, PlankUL newExtra, PlankUL* oldExtraPtr) 00919 { 00920 PlankP oldPtr; 00921 PlankUL oldExtra; 00922 PlankB success; 00923 00924 do { 00925 oldPtr = p->ptr; 00926 oldExtra = p->extra; 00927 success = pl_AtomicPX_CompareAndSwap (p, oldPtr, oldExtra, newPtr, newExtra); 00928 } while (!success); 00929 00930 if (oldExtraPtr != PLANK_NULL) 00931 *oldExtraPtr = oldExtra; 00932 00933 return oldPtr; 00934 } 00935 00936 static inline PlankP pl_AtomicPX_Swap (PlankAtomicPXRef p, PlankP newPtr) 00937 { 00938 PlankP oldPtr; 00939 PlankUL oldExtra; 00940 PlankB success; 00941 00942 do { 00943 oldPtr = p->ptr; 00944 oldExtra = p->extra; 00945 success = pl_AtomicPX_CompareAndSwap (p, oldPtr, oldExtra, newPtr, oldExtra + 1); 00946 } while (!success); 00947 00948 return oldPtr; 00949 } 00950 00951 static inline void pl_AtomicPX_SwapOther (PlankAtomicPXRef p1, PlankAtomicPXRef p2) 00952 { 00953 PlankAtomicPX tmp1, tmp2; 00954 PlankB success; 00955 00956 do { 00957 tmp1 = *p1; 00958 tmp2 = *p2; 00959 success = pl_AtomicPX_CompareAndSwap (p1, tmp1.ptr, tmp1.extra, tmp2.ptr, tmp1.extra + 1); 00960 } while (!success); 00961 00962 pl_AtomicPX_Set (p2, tmp1.ptr); 00963 } 00964 00965 static inline void pl_AtomicPX_SetAll (PlankAtomicPXRef p, PlankP newPtr, PlankUL newExtra) 00966 { 00967 pl_AtomicPX_SwapAll (p, newPtr, newExtra, (PlankUL*)PLANK_NULL); 00968 } 00969 00970 static inline void pl_AtomicPX_Set (PlankAtomicPXRef p, PlankP newPtr) 00971 { 00972 PlankP oldPtr; 00973 PlankUL oldExtra; 00974 PlankB success; 00975 00976 do { 00977 oldPtr = p->ptr; 00978 oldExtra = p->extra; 00979 success = pl_AtomicPX_CompareAndSwap (p, oldPtr, oldExtra, newPtr, oldExtra + 1); 00980 } while (!success); 00981 } 00982 00983 static inline PlankP pl_AtomicPX_Add (PlankAtomicPXRef p, PlankL operand) 00984 { 00985 PlankP newPtr, oldPtr; 00986 PlankUL oldExtra; 00987 PlankB success; 00988 00989 do { 00990 oldPtr = p->ptr; 00991 oldExtra = p->extra; 00992 newPtr = (PlankUC*)oldPtr + operand; 00993 success = pl_AtomicPX_CompareAndSwap (p, oldPtr, oldExtra, newPtr, oldExtra + 1); 00994 } while (!success); 00995 00996 return newPtr; 00997 } 00998 00999 static inline PlankP pl_AtomicPX_Subtract (PlankAtomicPXRef p, PlankL operand) 01000 { 01001 return pl_AtomicPX_Add (p, -operand); 01002 } 01003 01004 static inline PlankP pl_AtomicPX_Increment (PlankAtomicPXRef p) 01005 { 01006 return pl_AtomicPX_Add (p, (PlankL)1); 01007 } 01008 01009 static inline PlankP pl_AtomicPX_Decrement (PlankAtomicPXRef p) 01010 { 01011 return pl_AtomicPX_Add (p, (PlankL)(-1)); 01012 } 01013 01014 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_16 01015 static inline PlankB pl_AtomicPX_CompareAndSwap (PlankAtomicPXRef p, PlankP oldPtr, PlankUL oldExtra, PlankP newPtr, PlankUL newExtra) 01016 { 01017 PlankAtomicPX oldAll = { oldPtr, oldExtra }; 01018 PlankAtomicPX newAll = { newPtr, newExtra }; 01019 01020 return __sync_bool_compare_and_swap ((volatile (__int128_t*)p, 01021 *(__int128_t*)&oldAll, 01022 *(__int128_t*)&newAll); 01023 } 01024 #elif defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8) 01025 static inline PlankB pl_AtomicPX_CompareAndSwap (PlankAtomicPXRef p, PlankP oldPtr, PlankUL oldExtra, PlankP newPtr, PlankUL newExtra) 01026 { 01027 if (! pl_ThreadSpinLock_TryLock (&p->lock)) 01028 return PLANK_FALSE; 01029 01030 if ((p->ptr != oldPtr) || (p->extra != oldExtra)) 01031 { 01032 pl_ThreadSpinLock_Unlock (&p->lock); 01033 return PLANK_FALSE; 01034 } 01035 01036 p->ptr = newPtr; 01037 p->extra = newExtra; 01038 pl_ThreadSpinLock_Unlock (&p->lock); 01039 01040 return PLANK_TRUE; 01041 } 01042 #else 01043 static inline PlankB pl_AtomicPX_CompareAndSwap (PlankAtomicPXRef p, PlankP oldPtr, PlankUL oldExtra, PlankP newPtr, PlankUL newExtra) 01044 { 01045 if (! pl_SpinLock_TryLock (&p->lock)) 01046 return PLANK_FALSE; 01047 01048 if ((p->ptr != oldPtr) || (p->extra != oldExtra)) 01049 { 01050 pl_SpinLock_Unlock (&p->lock); 01051 return PLANK_FALSE; 01052 } 01053 01054 p->ptr = newPtr; 01055 p->extra = newExtra; 01056 pl_SpinLock_Unlock (&p->lock); 01057 01058 return PLANK_TRUE; 01059 } 01060 #endif 01061 01062 static inline PlankB pl_AtomicPX_CompareAndSwapP (PlankAtomicPXRef p, PlankP oldPtr, PlankP newPtr) 01063 { 01064 return pl_AtomicP_CompareAndSwap ((PlankAtomicPRef)p, oldPtr, newPtr); 01065 } 01066 01067 static inline void pl_AtomicPX_SetAllUnchecked (PlankAtomicPXRef p, PlankP newPtr, PlankUL newExtra) 01068 { 01069 p->ptr = newPtr; 01070 p->extra = newExtra; 01071 } 01072 01073 #define PLANK_ATOMICS_DEFINED 1 01074 01075 #endif // __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 01076 #endif // PLANK_INLINING_FUNCTIONS 01077