LCOV - code coverage report
Current view: top level - port - cpl_atomic_ops.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 7 7 100.0 %
Date: 2024-04-28 23:18:46 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /**********************************************************************
       2             :  *
       3             :  * Name:     cpl_atomic_ops.cpp
       4             :  * Project:  CPL - Common Portability Library
       5             :  * Purpose:  Atomic operation functions.
       6             :  * Author:   Even Rouault, <even dot rouault at spatialys.com>
       7             :  *
       8             :  **********************************************************************
       9             :  * Copyright (c) 2009-2010, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * Permission is hereby granted, free of charge, to any person obtaining a
      12             :  * copy of this software and associated documentation files (the "Software"),
      13             :  * to deal in the Software without restriction, including without limitation
      14             :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15             :  * and/or sell copies of the Software, and to permit persons to whom the
      16             :  * Software is furnished to do so, subject to the following conditions:
      17             :  *
      18             :  * The above copyright notice and this permission notice shall be included
      19             :  * in all copies or substantial portions of the Software.
      20             :  *
      21             :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22             :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23             :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      24             :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25             :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26             :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      27             :  * DEALINGS IN THE SOFTWARE.
      28             :  ****************************************************************************/
      29             : 
      30             : #include "cpl_atomic_ops.h"
      31             : 
      32             : #include "cpl_config.h"
      33             : 
      34             : // TODO: If C++11, use #include <atomic>.
      35             : 
      36             : #if defined(_MSC_VER)
      37             : 
      38             : #include <windows.h>
      39             : 
      40             : int CPLAtomicAdd(volatile int *ptr, int increment)
      41             : {
      42             :     return InterlockedExchangeAdd((volatile LONG *)(ptr), (LONG)(increment)) +
      43             :            increment;
      44             : }
      45             : 
      46             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
      47             : {
      48             :     return (LONG)InterlockedCompareExchange((volatile LONG *)(ptr),
      49             :                                             (LONG)newval,
      50             :                                             (LONG)oldval) == (LONG)oldval;
      51             : }
      52             : 
      53             : #elif defined(__MINGW32__) && defined(__i386__)
      54             : 
      55             : #include <windows.h>
      56             : 
      57             : int CPLAtomicAdd(volatile int *ptr, int increment)
      58             : {
      59             :     return InterlockedExchangeAdd((LONG *)(ptr), (LONG)(increment)) + increment;
      60             : }
      61             : 
      62             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
      63             : {
      64             :     return (LONG)InterlockedCompareExchange((LONG *)(ptr), (LONG)newval,
      65             :                                             (LONG)oldval) == (LONG)oldval;
      66             : }
      67             : 
      68             : #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
      69             : 
      70    27764800 : int CPLAtomicAdd(volatile int *ptr, int increment)
      71             : {
      72    27764800 :     int temp = increment;
      73             :     __asm__ __volatile__("lock; xaddl %0,%1"
      74             :                          : "+r"(temp), "+m"(*ptr)
      75             :                          :
      76    27764800 :                          : "memory");
      77    27764800 :     return temp + increment;
      78             : }
      79             : 
      80     2977790 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
      81             : {
      82             :     unsigned char ret;
      83             : 
      84             :     __asm__ __volatile__(" lock; cmpxchgl %2,%1\n"
      85             :                          " sete %0\n"
      86             :                          : "=q"(ret), "=m"(*ptr)
      87             :                          : "r"(newval), "m"(*ptr), "a"(oldval)
      88     2977790 :                          : "memory");
      89             : 
      90     2977790 :     return static_cast<int>(ret);
      91             : }
      92             : 
      93             : #elif defined(HAVE_GCC_ATOMIC_BUILTINS)
      94             : // Starting with GCC 4.1.0, built-in functions for atomic memory access are
      95             : // provided.  See:
      96             : //   http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
      97             : // We use a ./configure test to determine whether this builtins are available.
      98             : // as it appears that the GCC 4.1 version used on debian etch is broken when
      99             : // linking such instructions.
     100             : int CPLAtomicAdd(volatile int *ptr, int increment)
     101             : {
     102             :     if (increment > 0)
     103             :         return __sync_add_and_fetch(ptr, increment);
     104             : 
     105             :     return __sync_sub_and_fetch(ptr, -increment);
     106             : }
     107             : 
     108             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
     109             : {
     110             :     return __sync_bool_compare_and_swap(ptr, oldval, newval);
     111             : }
     112             : 
     113             : #elif defined(__MACH__) && defined(__APPLE__)
     114             : 
     115             : #include <libkern/OSAtomic.h>
     116             : 
     117             : int CPLAtomicAdd(volatile int *ptr, int increment)
     118             : {
     119             :     return OSAtomicAdd32(increment, (int *)(ptr));
     120             : }
     121             : 
     122             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
     123             : {
     124             :     return OSAtomicCompareAndSwap32(oldval, newval, (int *)(ptr));
     125             : }
     126             : 
     127             : #elif !defined(CPL_MULTIPROC_PTHREAD)
     128             : #warning "Needs real lock API to implement properly atomic increment"
     129             : 
     130             : // Dummy implementation.
     131             : int CPLAtomicAdd(volatile int *ptr, int increment)
     132             : {
     133             :     (*ptr) += increment;
     134             :     return *ptr;
     135             : }
     136             : 
     137             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
     138             : {
     139             :     if (*ptr == oldval)
     140             :     {
     141             :         *ptr = newval;
     142             :         return TRUE;
     143             :     }
     144             :     return FALSE;
     145             : }
     146             : 
     147             : #else
     148             : 
     149             : #include "cpl_multiproc.h"
     150             : 
     151             : static CPLLock *hAtomicOpLock = nullptr;
     152             : 
     153             : // Slow, but safe, implementation using a mutex.
     154             : int CPLAtomicAdd(volatile int *ptr, int increment)
     155             : {
     156             :     CPLLockHolderD(&hAtomicOpLock, LOCK_SPIN);
     157             :     (*ptr) += increment;
     158             :     return *ptr;
     159             : }
     160             : 
     161             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
     162             : {
     163             :     CPLLockHolderD(&hAtomicOpLock, LOCK_SPIN);
     164             :     if (*ptr == oldval)
     165             :     {
     166             :         *ptr = newval;
     167             :         return TRUE;
     168             :     }
     169             :     return FALSE;
     170             : }
     171             : 
     172             : #endif

Generated by: LCOV version 1.14