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