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