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-11-21 22:18:42 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             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_atomic_ops.h"
      15             : 
      16             : #include "cpl_config.h"
      17             : 
      18             : // TODO: If C++11, use #include <atomic>.
      19             : 
      20             : #if defined(_MSC_VER)
      21             : 
      22             : #include <windows.h>
      23             : 
      24             : int CPLAtomicAdd(volatile int *ptr, int increment)
      25             : {
      26             :     return InterlockedExchangeAdd((volatile LONG *)(ptr), (LONG)(increment)) +
      27             :            increment;
      28             : }
      29             : 
      30             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
      31             : {
      32             :     return (LONG)InterlockedCompareExchange((volatile LONG *)(ptr),
      33             :                                             (LONG)newval,
      34             :                                             (LONG)oldval) == (LONG)oldval;
      35             : }
      36             : 
      37             : #elif defined(__MINGW32__) && defined(__i386__)
      38             : 
      39             : #include <windows.h>
      40             : 
      41             : int CPLAtomicAdd(volatile int *ptr, int increment)
      42             : {
      43             :     return InterlockedExchangeAdd((LONG *)(ptr), (LONG)(increment)) + increment;
      44             : }
      45             : 
      46             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
      47             : {
      48             :     return (LONG)InterlockedCompareExchange((LONG *)(ptr), (LONG)newval,
      49             :                                             (LONG)oldval) == (LONG)oldval;
      50             : }
      51             : 
      52             : #elif defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__))
      53             : 
      54    37075400 : int CPLAtomicAdd(volatile int *ptr, int increment)
      55             : {
      56    37075400 :     int temp = increment;
      57             :     __asm__ __volatile__("lock; xaddl %0,%1"
      58             :                          : "+r"(temp), "+m"(*ptr)
      59             :                          :
      60    37075400 :                          : "memory");
      61    37075700 :     return temp + increment;
      62             : }
      63             : 
      64     3134400 : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
      65             : {
      66             :     unsigned char ret;
      67             : 
      68             :     __asm__ __volatile__(" lock; cmpxchgl %2,%1\n"
      69             :                          " sete %0\n"
      70             :                          : "=q"(ret), "=m"(*ptr)
      71             :                          : "r"(newval), "m"(*ptr), "a"(oldval)
      72     3134400 :                          : "memory");
      73             : 
      74     3134400 :     return static_cast<int>(ret);
      75             : }
      76             : 
      77             : #elif defined(HAVE_GCC_ATOMIC_BUILTINS)
      78             : // Starting with GCC 4.1.0, built-in functions for atomic memory access are
      79             : // provided.  See:
      80             : //   http://gcc.gnu.org/onlinedocs/gcc-4.1.0/gcc/Atomic-Builtins.html
      81             : // We use a ./configure test to determine whether this builtins are available.
      82             : // as it appears that the GCC 4.1 version used on debian etch is broken when
      83             : // linking such instructions.
      84             : int CPLAtomicAdd(volatile int *ptr, int increment)
      85             : {
      86             :     if (increment > 0)
      87             :         return __sync_add_and_fetch(ptr, increment);
      88             : 
      89             :     return __sync_sub_and_fetch(ptr, -increment);
      90             : }
      91             : 
      92             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
      93             : {
      94             :     return __sync_bool_compare_and_swap(ptr, oldval, newval);
      95             : }
      96             : 
      97             : #elif defined(__MACH__) && defined(__APPLE__)
      98             : 
      99             : #include <libkern/OSAtomic.h>
     100             : 
     101             : int CPLAtomicAdd(volatile int *ptr, int increment)
     102             : {
     103             :     return OSAtomicAdd32(increment, (int *)(ptr));
     104             : }
     105             : 
     106             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
     107             : {
     108             :     return OSAtomicCompareAndSwap32(oldval, newval, (int *)(ptr));
     109             : }
     110             : 
     111             : #elif !defined(CPL_MULTIPROC_PTHREAD)
     112             : #warning "Needs real lock API to implement properly atomic increment"
     113             : 
     114             : // Dummy implementation.
     115             : int CPLAtomicAdd(volatile int *ptr, int increment)
     116             : {
     117             :     (*ptr) += increment;
     118             :     return *ptr;
     119             : }
     120             : 
     121             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
     122             : {
     123             :     if (*ptr == oldval)
     124             :     {
     125             :         *ptr = newval;
     126             :         return TRUE;
     127             :     }
     128             :     return FALSE;
     129             : }
     130             : 
     131             : #else
     132             : 
     133             : #include "cpl_multiproc.h"
     134             : 
     135             : static CPLLock *hAtomicOpLock = nullptr;
     136             : 
     137             : // Slow, but safe, implementation using a mutex.
     138             : int CPLAtomicAdd(volatile int *ptr, int increment)
     139             : {
     140             :     CPLLockHolderD(&hAtomicOpLock, LOCK_SPIN);
     141             :     (*ptr) += increment;
     142             :     return *ptr;
     143             : }
     144             : 
     145             : int CPLAtomicCompareAndExchange(volatile int *ptr, int oldval, int newval)
     146             : {
     147             :     CPLLockHolderD(&hAtomicOpLock, LOCK_SPIN);
     148             :     if (*ptr == oldval)
     149             :     {
     150             :         *ptr = newval;
     151             :         return TRUE;
     152             :     }
     153             :     return FALSE;
     154             : }
     155             : 
     156             : #endif

Generated by: LCOV version 1.14