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