![]() |
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 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 00043 00044 #define PLANK_ATOMIC_XBITS 32 00045 #define PLANK_ATOMIC_XREFCOUNTBITS 16 00046 #define PLANK_ATOMIC_XWEAKCOUNTBITS 16 00047 #define PLANK_ATOMIC_XREFCOUNTMAX 0x0000FFFFUL 00048 #define PLANK_ATOMIC_XREFCOUNTMASK PLANK_ATOMIC_XREFCOUNTMAX 00049 #define PLANK_ATOMIC_XWEAKCOUNTMAX 0x0000FFFFUL 00050 #define PLANK_ATOMIC_XWEAKCOUNTMASK 0xFFFF0000UL 00051 #define PLANK_ATOMIC_XMAX 0xFFFFFFFFUL 00052 #define PLANK_ATOMIC_PMASK 0xFFFFFFFFUL 00053 00054 #if !DOXYGEN 00055 typedef struct PlankAtomicI 00056 { 00057 volatile PlankI value; 00058 } PlankAtomicI PLANK_ALIGN(4); 00059 00060 typedef struct PlankAtomicL 00061 { 00062 volatile PlankL value; 00063 } PlankAtomicL PLANK_ALIGN(4); 00064 00065 typedef struct PlankAtomicF 00066 { 00067 volatile PlankF value; 00068 } PlankAtomicF PLANK_ALIGN(4); 00069 00070 typedef struct PlankAtomicP 00071 { 00072 volatile PlankP ptr; 00073 } PlankAtomicP PLANK_ALIGN(4); 00074 00075 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00076 typedef struct PlankAtomicD 00077 { 00078 volatile PlankD value; 00079 } PlankAtomicD PLANK_ALIGN(8); 00080 00081 typedef struct PlankAtomicLL 00082 { 00083 volatile PlankLL value; 00084 } PlankAtomicLL PLANK_ALIGN(8); 00085 00086 typedef struct PlankAtomicPX 00087 { 00088 volatile PlankP ptr; 00089 volatile PlankUL extra; 00090 } PlankAtomicPX PLANK_ALIGN(8); 00091 #else //!__GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00092 #include "../../../core/plank_ThreadSpinLock.h" 00093 typedef struct PlankAtomicD 00094 { 00095 volatile PlankD value; 00096 ThreadSpinLock lock; 00097 } PlankAtomicD PLANK_ALIGN(8); 00098 00099 typedef struct PlankAtomicLL 00100 { 00101 volatile PlankLL value; 00102 ThreadSpinLock lock; 00103 } PlankAtomicLL PLANK_ALIGN(8); 00104 00105 typedef struct PlankAtomicPX 00106 { 00107 volatile PlankP ptr; 00108 volatile PlankUL extra; 00109 ThreadSpinLock lock; 00110 } PlankAtomicPX PLANK_ALIGN(8); 00111 #endif 00112 00113 static inline void pl_AtomicMemoryBarrier() 00114 { 00115 __sync_synchronize(); 00116 } 00117 00118 //------------------------------------------------------------------------------ 00119 00120 static inline PlankResult pl_AtomicI_Init (PlankAtomicIRef p) 00121 { 00122 if (p == PLANK_NULL) 00123 return PlankResult_MemoryError; 00124 00125 pl_MemoryZero (p, sizeof (PlankAtomicI)); 00126 00127 return PlankResult_OK; 00128 } 00129 00130 static inline PlankResult pl_AtomicI_DeInit (PlankAtomicIRef p) 00131 { 00132 if (p == PLANK_NULL) 00133 return PlankResult_MemoryError; 00134 return PlankResult_OK; 00135 } 00136 00137 static inline PlankI pl_AtomicI_Get (PlankAtomicIRef p) 00138 { 00139 return p->value; // should be aligned anyway and volatile so OK // pl_AtomicI_Add (p, 0); 00140 } 00141 00142 static inline PlankI pl_AtomicI_GetUnchecked (PlankAtomicIRef p) 00143 { 00144 return p->value; 00145 } 00146 00147 static inline PlankI pl_AtomicI_Swap (PlankAtomicIRef p, PlankI newValue) 00148 { 00149 PlankI oldValue; 00150 PlankB success; 00151 00152 do { 00153 oldValue = *(PlankI*)p; 00154 success = pl_AtomicI_CompareAndSwap (p, oldValue, newValue); 00155 } while (!success); 00156 00157 return oldValue; 00158 } 00159 00160 static inline void pl_AtomicI_SwapOther (PlankAtomicIRef p1, PlankAtomicIRef p2) 00161 { 00162 PlankI value1, value2; 00163 PlankB success; 00164 00165 do { 00166 value1 = *(PlankI*)p1; 00167 value2 = *(PlankI*)p2; 00168 success = pl_AtomicI_CompareAndSwap (p1, value1, value2); 00169 } while (!success); 00170 00171 *(PlankI*)p2 = value1; 00172 } 00173 00174 static inline void pl_AtomicI_Set (PlankAtomicIRef p, PlankI newValue) 00175 { 00176 pl_AtomicI_Swap (p, newValue); 00177 } 00178 00179 static inline PlankI pl_AtomicI_Add (PlankAtomicIRef p, PlankI operand) 00180 { 00181 return __sync_add_and_fetch ((volatile PlankI*)p, operand); 00182 } 00183 00184 static inline PlankB pl_AtomicI_CompareAndSwap (PlankAtomicIRef p, PlankI oldValue, PlankI newValue) 00185 { 00186 return __sync_bool_compare_and_swap ((volatile PlankI*)p, 00187 oldValue, 00188 newValue); 00189 } 00190 00191 static inline PlankI pl_AtomicI_Subtract (PlankAtomicIRef p, PlankI operand) 00192 { 00193 return pl_AtomicI_Add (p, -operand); 00194 } 00195 00196 static inline PlankI pl_AtomicI_Increment (PlankAtomicIRef p) 00197 { 00198 return pl_AtomicI_Add (p, 1); 00199 } 00200 00201 static inline PlankI pl_AtomicI_Decrement (PlankAtomicIRef p) 00202 { 00203 return pl_AtomicI_Add (p, -1); 00204 } 00205 00206 //------------------------------------------------------------------------------ 00207 00208 static inline PlankResult pl_AtomicL_Init (PlankAtomicLRef p) 00209 { 00210 if (p == PLANK_NULL) 00211 return PlankResult_MemoryError; 00212 00213 pl_MemoryZero (p, sizeof (PlankAtomicL)); 00214 00215 return PlankResult_OK; 00216 } 00217 00218 static inline PlankResult pl_AtomicL_DeInit (PlankAtomicLRef p) 00219 { 00220 if (p == PLANK_NULL) 00221 return PlankResult_MemoryError; 00222 return PlankResult_OK; 00223 } 00224 00225 static inline PlankL pl_AtomicL_Get (PlankAtomicLRef p) 00226 { 00227 return p->value; // should be aligned anyway and volatile so OK // pl_AtomicL_Add (p, (PlankL)0); 00228 } 00229 00230 static inline PlankL pl_AtomicL_GetUnchecked (PlankAtomicLRef p) 00231 { 00232 return p->value; 00233 } 00234 00235 static inline PlankL pl_AtomicL_Swap (PlankAtomicLRef p, PlankL newValue) 00236 { 00237 PlankL oldValue; 00238 PlankB success; 00239 00240 do { 00241 oldValue = *(PlankL*)p; 00242 success = pl_AtomicL_CompareAndSwap (p, oldValue, newValue); 00243 } while (!success); 00244 00245 return oldValue; 00246 } 00247 00248 static inline void pl_AtomicL_SwapOther (PlankAtomicLRef p1, PlankAtomicLRef p2) 00249 { 00250 PlankL value1, value2; 00251 PlankB success; 00252 00253 do { 00254 value1 = *(PlankL*)p1; 00255 value2 = *(PlankL*)p2; 00256 success = pl_AtomicL_CompareAndSwap (p1, value1, value2); 00257 } while (!success); 00258 00259 *(PlankL*)p2 = value1; 00260 } 00261 00262 static inline void pl_AtomicL_Set (PlankAtomicLRef p, PlankL newValue) 00263 { 00264 pl_AtomicL_Swap (p, newValue); 00265 } 00266 00267 static inline PlankL pl_AtomicL_Add (PlankAtomicLRef p, PlankL operand) 00268 { 00269 return __sync_add_and_fetch ((volatile PlankL*)p, operand); 00270 } 00271 00272 static inline PlankB pl_AtomicL_CompareAndSwap (PlankAtomicLRef p, PlankL oldValue, PlankL newValue) 00273 { 00274 return __sync_bool_compare_and_swap ((volatile PlankL*)p, 00275 oldValue, 00276 newValue); 00277 } 00278 00279 static inline PlankL pl_AtomicL_Subtract (PlankAtomicLRef p, PlankL operand) 00280 { 00281 return pl_AtomicL_Add (p, -operand); 00282 } 00283 00284 static inline PlankL pl_AtomicL_Increment (PlankAtomicLRef p) 00285 { 00286 return pl_AtomicL_Add (p, (PlankL)1); 00287 } 00288 00289 static inline PlankL pl_AtomicL_Decrement (PlankAtomicLRef p) 00290 { 00291 return pl_AtomicL_Add (p, (PlankL)(-1)); 00292 } 00293 00294 //------------------------------------------------------------------------------ 00295 00296 static inline PlankResult pl_AtomicLL_Init (PlankAtomicLLRef p) 00297 { 00298 PlankResult result = PlankResult_OK; 00299 00300 if (p == PLANK_NULL) 00301 { 00302 result = PlankResult_MemoryError; 00303 goto exit; 00304 } 00305 00306 pl_MemoryZero (p, sizeof (PlankAtomicLL)); 00307 00308 exit: 00309 return result; 00310 } 00311 00312 static inline PlankResult pl_AtomicLL_DeInit (PlankAtomicLLRef p) 00313 { 00314 PlankResult result = PlankResult_OK; 00315 00316 if (p == PLANK_NULL) 00317 { 00318 result = PlankResult_MemoryError; 00319 goto exit; 00320 } 00321 00322 exit: 00323 return result; 00324 } 00325 00326 static inline PlankLL pl_AtomicLL_Get (PlankAtomicLLRef p) 00327 { 00328 return pl_AtomicLL_Add (p, (PlankLL)0); 00329 } 00330 00331 static inline PlankLL pl_AtomicLL_GetUnchecked (PlankAtomicLLRef p) 00332 { 00333 return p->value; 00334 } 00335 00336 static inline PlankLL pl_AtomicLL_Swap (PlankAtomicLLRef p, PlankLL newValue) 00337 { 00338 PlankLL oldValue; 00339 PlankB success; 00340 00341 do { 00342 oldValue = *(PlankLL*)p; 00343 success = pl_AtomicLL_CompareAndSwap (p, oldValue, newValue); 00344 } while (!success); 00345 00346 return oldValue; 00347 } 00348 00349 static inline void pl_AtomicLL_SwapOther (PlankAtomicLLRef p1, PlankAtomicLLRef p2) 00350 { 00351 PlankLL value1, value2; 00352 PlankB success; 00353 00354 do { 00355 value1 = *(PlankLL*)p1; 00356 value2 = *(PlankLL*)p2; 00357 success = pl_AtomicLL_CompareAndSwap (p1, value1, value2); 00358 } while (!success); 00359 00360 *(PlankLL*)p2 = value1; 00361 } 00362 00363 static inline void pl_AtomicLL_Set (PlankAtomicLLRef p, PlankLL newValue) 00364 { 00365 pl_AtomicLL_Swap (p, newValue); 00366 } 00367 00368 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00369 static inline PlankLL pl_AtomicLL_Add (PlankAtomicLLRef p, PlankLL operand) 00370 { 00371 return __sync_add_and_fetch ((volatile PlankLL*)p, operand); 00372 } 00373 00374 static inline PlankB pl_AtomicLL_CompareAndSwap (PlankAtomicLLRef p, PlankLL oldValue, PlankLL newValue) 00375 { 00376 return __sync_bool_compare_and_swap ((volatile PlankLL*)p, 00377 oldValue, 00378 newValue); 00379 } 00380 #else 00381 static inline PlankLL pl_AtomicLL_Add (PlankAtomicLLRef p, PlankLL operand) 00382 { 00383 PlankLL oldValue, newValue; 00384 PlankB success; 00385 00386 do { 00387 oldValue = *(PlankLL*)p; 00388 newValue = oldValue + operand; 00389 success = pl_AtomicLL_CompareAndSwap (p, oldValue, newValue); 00390 } while (!success); 00391 00392 return newValue; 00393 } 00394 00395 static inline PlankB pl_AtomicLL_CompareAndSwap (PlankAtomicLLRef p, PlankLL oldValue, PlankLL newValue) 00396 { 00397 if (! pl_ThreadSpinLock_TryLock (&p->lock)) 00398 return PLANK_FALSE; 00399 00400 if (p->value != oldValue) 00401 { 00402 pl_ThreadSpinLock_Unlock (&p->lock); 00403 return PLANK_FALSE; 00404 } 00405 00406 p->value = newValue; 00407 pl_ThreadSpinLock_Unlock (&p->lock); 00408 00409 return PLANK_TRUE; 00410 } 00411 #endif 00412 00413 static inline PlankLL pl_AtomicLL_Subtract (PlankAtomicLLRef p, PlankLL operand) 00414 { 00415 return pl_AtomicLL_Add (p, -operand); 00416 } 00417 00418 static inline PlankLL pl_AtomicLL_Increment (PlankAtomicLLRef p) 00419 { 00420 return pl_AtomicLL_Add (p, (PlankLL)1); 00421 } 00422 00423 static inline PlankLL pl_AtomicLL_Decrement (PlankAtomicLLRef p) 00424 { 00425 return pl_AtomicLL_Add (p, (PlankLL)(-1)); 00426 } 00427 00428 //------------------------------------------------------------------------------ 00429 00430 static inline PlankResult pl_AtomicF_Init (PlankAtomicFRef p) 00431 { 00432 if (p == PLANK_NULL) 00433 return PlankResult_MemoryError; 00434 00435 pl_MemoryZero (p, sizeof (PlankAtomicF)); 00436 00437 return PlankResult_OK; 00438 } 00439 00440 static inline PlankResult pl_AtomicF_DeInit (PlankAtomicFRef p) 00441 { 00442 if (p == PLANK_NULL) 00443 return PlankResult_MemoryError; 00444 return PlankResult_OK; 00445 } 00446 00447 static inline PlankF pl_AtomicF_Get (PlankAtomicFRef p) 00448 { 00449 return p->value; // should be aligned anyway and volatile so OK 00450 } 00451 00452 static inline PlankF pl_AtomicF_GetUnchecked (PlankAtomicFRef p) 00453 { 00454 return p->value; 00455 } 00456 00457 static inline PlankF pl_AtomicF_Swap (PlankAtomicFRef p, PlankF newValue) 00458 { 00459 PlankF oldValue; 00460 PlankB success; 00461 00462 do 00463 { 00464 oldValue = *(PlankF*)p; 00465 success = pl_AtomicF_CompareAndSwap (p, oldValue, newValue); 00466 } while (!success); 00467 00468 return oldValue; 00469 } 00470 00471 static inline void pl_AtomicF_SwapOther (PlankAtomicFRef p1, PlankAtomicFRef p2) 00472 { 00473 PlankF value1, value2; 00474 PlankB success; 00475 00476 do { 00477 value1 = *(PlankF*)p1; 00478 value2 = *(PlankF*)p2; 00479 success = pl_AtomicF_CompareAndSwap (p1, value1, value2); 00480 } while (!success); 00481 00482 *(PlankF*)p2 = value1; 00483 } 00484 00485 static inline void pl_AtomicF_Set (PlankAtomicFRef p, PlankF newValue) 00486 { 00487 pl_AtomicF_Swap (p, newValue); 00488 } 00489 00490 static inline PlankF pl_AtomicF_Add (PlankAtomicFRef p, PlankF operand) 00491 { 00492 PlankF newValue, oldValue; 00493 PlankB success; 00494 00495 do { 00496 oldValue = *(PlankF*)p; 00497 newValue = oldValue + operand; 00498 success = pl_AtomicF_CompareAndSwap (p, oldValue, newValue); 00499 } while (!success); 00500 00501 return newValue; 00502 } 00503 00504 static inline PlankB pl_AtomicF_CompareAndSwap (PlankAtomicFRef p, PlankF oldValue, PlankF newValue) 00505 { 00506 return __sync_bool_compare_and_swap ((volatile PlankI*)p, 00507 *(PlankI*)&oldValue, 00508 *(PlankI*)&newValue); 00509 } 00510 00511 static inline PlankF pl_AtomicF_Subtract (PlankAtomicFRef p, PlankF operand) 00512 { 00513 return pl_AtomicF_Add (p, -operand); 00514 } 00515 00516 static inline PlankF pl_AtomicF_Increment (PlankAtomicFRef p) 00517 { 00518 return pl_AtomicF_Add (p, 1.f); 00519 } 00520 00521 static inline PlankF pl_AtomicF_Decrement (PlankAtomicFRef p) 00522 { 00523 return pl_AtomicF_Add (p, -1.f); 00524 } 00525 00526 //------------------------------------------------------------------------------ 00527 00528 static inline PlankResult pl_AtomicD_Init (PlankAtomicDRef p) 00529 { 00530 PlankResult result = PlankResult_OK; 00531 00532 if (p == PLANK_NULL) 00533 { 00534 result = PlankResult_MemoryError; 00535 goto exit; 00536 } 00537 00538 pl_MemoryZero (p, sizeof (PlankAtomicD)); 00539 00540 exit: 00541 return result; 00542 } 00543 00544 static inline PlankResult pl_AtomicD_DeInit (PlankAtomicDRef p) 00545 { 00546 PlankResult result = PlankResult_OK; 00547 00548 if (p == PLANK_NULL) 00549 { 00550 result = PlankResult_MemoryError; 00551 goto exit; 00552 } 00553 00554 exit: 00555 return result; 00556 } 00557 00558 static inline PlankD pl_AtomicD_Get (PlankAtomicDRef p) 00559 { 00560 PlankLL bits = pl_AtomicLL_Add ((PlankAtomicLLRef)p, (PlankLL)0); // use the LL version 00561 return *(PlankD*)&bits; 00562 } 00563 00564 static inline PlankD pl_AtomicD_GetUnchecked (PlankAtomicDRef p) 00565 { 00566 return p->value; 00567 } 00568 00569 static inline PlankD pl_AtomicD_Swap (PlankAtomicDRef p, PlankD newValue) 00570 { 00571 PlankD oldValue; 00572 PlankB success; 00573 00574 do { 00575 oldValue = *(PlankD*)p; 00576 success = pl_AtomicD_CompareAndSwap (p, oldValue, newValue); 00577 } while (!success); 00578 00579 return oldValue; 00580 } 00581 00582 static inline void pl_AtomicD_SwapOther (PlankAtomicDRef p1, PlankAtomicDRef p2) 00583 { 00584 PlankD value1, value2; 00585 PlankB success; 00586 00587 do { 00588 value1 = *(PlankD*)p1; 00589 value2 = *(PlankD*)p2; 00590 success = pl_AtomicD_CompareAndSwap (p1, value1, value2); 00591 } while (!success); 00592 00593 *(PlankD*)p2 = value1; 00594 } 00595 00596 static inline void pl_AtomicD_Set (PlankAtomicDRef p, PlankD newValue) 00597 { 00598 pl_AtomicD_Swap (p, newValue); 00599 } 00600 00601 static inline PlankD pl_AtomicD_Add (PlankAtomicDRef p, PlankD operand) 00602 { 00603 PlankD newValue, oldValue; 00604 PlankB success; 00605 00606 do { 00607 oldValue = *(PlankD*)p; 00608 newValue = oldValue + operand; 00609 success = pl_AtomicD_CompareAndSwap (p, oldValue, newValue); 00610 } while (!success); 00611 00612 return newValue; 00613 } 00614 00615 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00616 static inline PlankB pl_AtomicD_CompareAndSwap (PlankAtomicDRef p, PlankD oldValue, PlankD newValue) 00617 { 00618 return __sync_bool_compare_and_swap ((volatile PlankLL*)p, 00619 *(PlankLL*)&oldValue, 00620 *(PlankLL*)&newValue); 00621 } 00622 #else 00623 static inline PlankB pl_AtomicD_CompareAndSwap (PlankAtomicDRef p, PlankD oldValue, PlankD newValue) 00624 { 00625 // must use an integer compare since comparing floating point 00626 // values doesn't do a bitwise comparison 00627 return pl_AtomicLL_CompareAndSwap ((PlankAtomicLLRef)p, 00628 *(PlankLL*)&oldValue, 00629 *(PlankLL*)&newValue); 00630 } 00631 #endif 00632 00633 static inline PlankD pl_AtomicD_Subtract (PlankAtomicDRef p, PlankD operand) 00634 { 00635 return pl_AtomicD_Add (p, -operand); 00636 } 00637 00638 static inline PlankD pl_AtomicD_Increment (PlankAtomicDRef p) 00639 { 00640 return pl_AtomicD_Add (p, 1.0); 00641 } 00642 00643 static inline PlankD pl_AtomicD_Decrement (PlankAtomicDRef p) 00644 { 00645 return pl_AtomicD_Add (p, -1.0); 00646 } 00647 00648 //------------------------------------------------------------------------------ 00649 00650 static inline PlankResult pl_AtomicP_Init (PlankAtomicPRef p) 00651 { 00652 if (p == PLANK_NULL) 00653 return PlankResult_MemoryError; 00654 00655 pl_MemoryZero (p, sizeof (PlankAtomicP)); 00656 00657 return PlankResult_OK; 00658 } 00659 00660 static inline PlankResult pl_AtomicP_DeInit (PlankAtomicPRef p) 00661 { 00662 if (p == PLANK_NULL) 00663 return PlankResult_MemoryError; 00664 return PlankResult_OK; 00665 } 00666 00667 static inline PlankP pl_AtomicP_Get (PlankAtomicPRef p) 00668 { 00669 return p->ptr; // should be aligned anyway and volatile so OK // pl_AtomicP_Add (p, (PlankL)0); 00670 } 00671 00672 static inline PlankP pl_AtomicP_GetUnchecked (PlankAtomicPRef p) 00673 { 00674 return p->ptr; 00675 } 00676 00677 static inline PlankP pl_AtomicP_Swap (PlankAtomicPRef p, PlankP newPtr) 00678 { 00679 PlankP oldPtr; 00680 PlankB success; 00681 00682 do { 00683 oldPtr = *(PlankP*)p; 00684 success = pl_AtomicP_CompareAndSwap (p, oldPtr, newPtr); 00685 } while (!success); 00686 00687 return oldPtr; 00688 } 00689 00690 static inline void pl_AtomicP_SwapOther (PlankAtomicPRef p1, PlankAtomicPRef p2) 00691 { 00692 PlankP value1, value2; 00693 PlankB success; 00694 00695 do { 00696 value1 = *(PlankP*)p1; 00697 value2 = *(PlankP*)p2; 00698 success = pl_AtomicP_CompareAndSwap (p1, value1, value2); 00699 } while (!success); 00700 00701 *(PlankP*)p2 = value1; 00702 } 00703 00704 static inline void pl_AtomicP_Set (PlankAtomicPRef p, PlankP newPtr) 00705 { 00706 pl_AtomicP_Swap (p, newPtr); 00707 } 00708 00709 static inline PlankP pl_AtomicP_Add (PlankAtomicPRef p, PlankL operand) 00710 { 00711 return (PlankP)__sync_add_and_fetch ((volatile PlankL*)p, operand); 00712 } 00713 00714 static inline PlankB pl_AtomicP_CompareAndSwap (PlankAtomicPRef p, PlankP oldValue, PlankP newValue) 00715 { 00716 return __sync_bool_compare_and_swap ((volatile PlankL*)p, 00717 *(PlankL*)&oldValue, 00718 *(PlankL*)&newValue); 00719 } 00720 00721 static inline PlankP pl_AtomicP_Subtract (PlankAtomicPRef p, PlankL operand) 00722 { 00723 return pl_AtomicP_Add (p, -operand); 00724 } 00725 00726 static inline PlankP pl_AtomicP_Increment (PlankAtomicPRef p) 00727 { 00728 return pl_AtomicP_Add (p, (PlankL)1); 00729 } 00730 00731 static inline PlankP pl_AtomicP_Decrement (PlankAtomicPRef p) 00732 { 00733 return pl_AtomicP_Add (p, (PlankL)(-1)); 00734 } 00735 00736 //------------------------------------------------------------------------------ 00737 00738 static inline PlankAtomicPXRef pl_AtomicPX_CreateAndInit() 00739 { 00740 PlankAtomicPXRef p = pl_AtomicPX_Create(); 00741 if (p != PLANK_NULL) pl_AtomicPX_Init (p); 00742 return p; 00743 } 00744 00745 static inline PlankAtomicPXRef pl_AtomicPX_Create() 00746 { 00747 PlankMemoryRef m; 00748 PlankAtomicPXRef p; 00749 00750 m = pl_MemoryGlobal(); 00751 p = (PlankAtomicPXRef)pl_Memory_AllocateBytes (m, sizeof (PlankAtomicPX)); 00752 00753 if (p != PLANK_NULL) 00754 pl_MemoryZero (p, sizeof (PlankAtomicPX)); 00755 00756 return p; 00757 } 00758 00759 static inline PlankResult pl_AtomicPX_Init (PlankAtomicPXRef p) 00760 { 00761 PlankResult result = PlankResult_OK; 00762 00763 if (p == PLANK_NULL) 00764 { 00765 result = PlankResult_MemoryError; 00766 goto exit; 00767 } 00768 00769 pl_MemoryZero (p, sizeof (PlankAtomicPX)); 00770 00771 exit: 00772 return result; 00773 } 00774 00775 static inline PlankResult pl_AtomicPX_DeInit (PlankAtomicPXRef p) 00776 { 00777 PlankResult result = PlankResult_OK; 00778 00779 if (p == PLANK_NULL) 00780 { 00781 result = PlankResult_MemoryError; 00782 goto exit; 00783 } 00784 00785 exit: 00786 return result; 00787 } 00788 00789 static inline PlankResult pl_AtomicPX_Destroy (PlankAtomicPXRef p) 00790 { 00791 PlankResult result; 00792 PlankMemoryRef m; 00793 00794 result = PlankResult_OK; 00795 m = pl_MemoryGlobal(); 00796 00797 if ((result = pl_AtomicPX_DeInit (p)) != PlankResult_OK) 00798 goto exit; 00799 00800 result = pl_Memory_Free (m, p); 00801 00802 exit: 00803 return result; 00804 } 00805 00806 static inline PlankP pl_AtomicPX_Get (PlankAtomicPXRef p) 00807 { 00808 return p->ptr; // should be aligned anyway and volatile so OK // pl_AtomicP_Get ((PlankAtomicPRef)p); 00809 } 00810 00811 static inline PlankP pl_AtomicPX_GetUnchecked (PlankAtomicPXRef p) 00812 { 00813 return p->ptr; 00814 } 00815 00816 static inline PlankUL pl_AtomicPX_GetExtra (PlankAtomicPXRef p) 00817 { 00818 return p->extra; // should be aligned anyway and volatile so OK // pl_AtomicL_Get ((PlankAtomicLRef)&(p->extra)); 00819 } 00820 00821 static inline PlankUL pl_AtomicPX_GetExtraUnchecked (PlankAtomicPXRef p) 00822 { 00823 return p->extra; 00824 } 00825 00826 static inline PlankP pl_AtomicPX_SwapAll (PlankAtomicPXRef p, PlankP newPtr, PlankUL newExtra, PlankUL* oldExtraPtr) 00827 { 00828 PlankP oldPtr; 00829 PlankUL oldExtra; 00830 PlankB success; 00831 00832 do { 00833 oldPtr = p->ptr; 00834 oldExtra = p->extra; 00835 success = pl_AtomicPX_CompareAndSwap (p, oldPtr, oldExtra, newPtr, newExtra); 00836 } while (!success); 00837 00838 if (oldExtraPtr != PLANK_NULL) 00839 *oldExtraPtr = oldExtra; 00840 00841 return oldPtr; 00842 } 00843 00844 static inline PlankP pl_AtomicPX_Swap (PlankAtomicPXRef p, PlankP newPtr) 00845 { 00846 PlankP oldPtr; 00847 PlankUL oldExtra; 00848 PlankB success; 00849 00850 do { 00851 oldPtr = p->ptr; 00852 oldExtra = p->extra; 00853 success = pl_AtomicPX_CompareAndSwap (p, oldPtr, oldExtra, newPtr, oldExtra + 1); 00854 } while (!success); 00855 00856 return oldPtr; 00857 } 00858 00859 static inline void pl_AtomicPX_SwapOther (PlankAtomicPXRef p1, PlankAtomicPXRef p2) 00860 { 00861 PlankAtomicPX tmp1, tmp2; 00862 PlankB success; 00863 00864 do { 00865 tmp1 = *p1; 00866 tmp2 = *p2; 00867 success = pl_AtomicPX_CompareAndSwap (p1, tmp1.ptr, tmp1.extra, tmp2.ptr, tmp1.extra + 1); 00868 } while (!success); 00869 00870 pl_AtomicPX_Set (p2, tmp1.ptr); 00871 } 00872 00873 static inline void pl_AtomicPX_SetAll (PlankAtomicPXRef p, PlankP newPtr, PlankUL newExtra) 00874 { 00875 pl_AtomicPX_SwapAll (p, newPtr, newExtra, (PlankUL*)PLANK_NULL); 00876 } 00877 00878 static inline void pl_AtomicPX_Set (PlankAtomicPXRef p, PlankP newPtr) 00879 { 00880 PlankP oldPtr; 00881 PlankUL oldExtra; 00882 PlankB success; 00883 00884 do { 00885 oldPtr = p->ptr; 00886 oldExtra = p->extra; 00887 success = pl_AtomicPX_CompareAndSwap (p, oldPtr, oldExtra, newPtr, oldExtra + 1); 00888 } while (!success); 00889 } 00890 00891 static inline PlankP pl_AtomicPX_Add (PlankAtomicPXRef p, PlankL operand) 00892 { 00893 PlankP newPtr, oldPtr; 00894 PlankUL oldExtra; 00895 PlankB success; 00896 00897 do { 00898 oldPtr = p->ptr; 00899 oldExtra = p->extra; 00900 newPtr = (PlankUC*)oldPtr + operand; 00901 success = pl_AtomicPX_CompareAndSwap (p, oldPtr, oldExtra, newPtr, oldExtra + 1); 00902 } while (!success); 00903 00904 return newPtr; 00905 } 00906 00907 static inline PlankP pl_AtomicPX_Subtract (PlankAtomicPXRef p, PlankL operand) 00908 { 00909 return pl_AtomicPX_Add (p, -operand); 00910 } 00911 00912 static inline PlankP pl_AtomicPX_Increment (PlankAtomicPXRef p) 00913 { 00914 return pl_AtomicPX_Add (p, (PlankL)1); 00915 } 00916 00917 static inline PlankP pl_AtomicPX_Decrement (PlankAtomicPXRef p) 00918 { 00919 return pl_AtomicPX_Add (p, (PlankL)(-1)); 00920 } 00921 00922 #ifdef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8 00923 static inline PlankB pl_AtomicPX_CompareAndSwap (PlankAtomicPXRef p, PlankP oldPtr, PlankUL oldExtra, PlankP newPtr, PlankUL newExtra) 00924 { 00925 PlankAtomicPX oldAll = { oldPtr, oldExtra }; 00926 PlankAtomicPX newAll = { newPtr, newExtra }; 00927 00928 return __sync_bool_compare_and_swap ((volatile PlankLL*)p, 00929 *(PlankLL*)&oldAll, 00930 *(PlankLL*)&newAll); 00931 } 00932 #else 00933 static inline PlankB pl_AtomicPX_CompareAndSwap (PlankAtomicPXRef p, PlankP oldPtr, PlankUL oldExtra, PlankP newPtr, PlankL newExtra) 00934 { 00935 PlankAtomicPX oldAll = { oldPtr, oldExtra, { { 0 } } }; 00936 PlankAtomicPX newAll = { newPtr, newExtra, { { 0 } } }; 00937 00938 return pl_AtomicLL_CompareAndSwap ((PlankAtomicLLRef)p, 00939 *(PlankLL*)&oldAll, 00940 *(PlankLL*)&newAll); 00941 } 00942 #endif 00943 00944 static inline PlankB pl_AtomicPX_CompareAndSwapP (PlankAtomicPXRef p, PlankP oldPtr, PlankP newPtr) 00945 { 00946 return pl_AtomicP_CompareAndSwap ((PlankAtomicPRef)p, oldPtr, newPtr); 00947 } 00948 00949 static inline void pl_AtomicPX_SetAllUnchecked (PlankAtomicPXRef p, PlankP newPtr, PlankUL newExtra) 00950 { 00951 p->ptr = newPtr; 00952 p->extra = newExtra; 00953 } 00954 00955 #define PLANK_ATOMICS_DEFINED 1 00956 00957 #endif // __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 00958 #endif // PLANK_INLINING_FUNCTIONS 00959