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