pl-nk v0.4.5
Plonk|Plink|Plank are a set of cross-platform C/C++ frameworks for audio software development
plank_AtomicInline_Win_X86_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 #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 
 All Classes Functions Typedefs Enumerations Enumerator Properties