"Fossies" - the Fresh Open Source Software Archive

Member "darktable-3.6.1/src/common/atomic.h" (10 Sep 2021, 5547 Bytes) of package /linux/misc/darktable-3.6.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "atomic.h" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 3.4.1.1_vs_3.6.0.

    1 /*
    2     This file is part of darktable,
    3     Copyright (C) 2020 darktable developers.
    4 
    5     darktable is free software: you can redistribute it and/or modify
    6     it under the terms of the GNU General Public License as published by
    7     the Free Software Foundation, either version 3 of the License, or
    8     (at your option) any later version.
    9 
   10     darktable is distributed in the hope that it will be useful,
   11     but WITHOUT ANY WARRANTY; without even the implied warranty of
   12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   13     GNU General Public License for more details.
   14 
   15     You should have received a copy of the GNU General Public License
   16     along with darktable.  If not, see <http://www.gnu.org/licenses/>.
   17 */
   18 
   19 #pragma once
   20 
   21 // implement an atomic variable for inter-thread signalling purposes
   22 // the manner in which we implement depends on the capabilities of the compiler:
   23 //   1. standard-compliant C++ compiler: use C++11 atomics in <atomic>
   24 //   2. standard-compliant C compiler: use C11 atomics in <stdatomic.h>
   25 //   3. GCC 4.8+: use intrinsics
   26 //   4. otherwise: fall back to using Posix mutex to serialize access
   27 
   28 #if defined(__cplusplus) && __cplusplus > 201100
   29 // G++ throws an error on trying to use C++ atomics with C linkage
   30 // all of the C++ files which (indirectly) include this header do so inside an extern "C" {}, so we need to
   31 //   exit out of the extern statement, make our definitions, and then restart another extern block.
   32 } // end of extern "C" block
   33 #include <atomic>
   34 
   35 typedef std::atomic<int> dt_atomic_int;
   36 inline void dt_atomic_set_int(dt_atomic_int *var, int value) { std::atomic_store(var,value); }
   37 inline int dt_atomic_get_int(dt_atomic_int *var) { return std::atomic_load(var); }
   38 inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return std::atomic_fetch_add(var,incr); }
   39 inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return std::atomic_fetch_sub(var,decr); }
   40 inline int dt_atomic_exch_int(dt_atomic_int *var, int value) { return std::atomic_exchange(var,value); }
   41 inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
   42 { return std::atomic_compare_exchange_strong(var,expected,value); }
   43 
   44 extern "C" { // restart C linkage block
   45 
   46 #elif !defined(__STDC_NO_ATOMICS__)
   47 
   48 #include <stdatomic.h>
   49 
   50 typedef atomic_int dt_atomic_int;
   51 inline void dt_atomic_set_int(dt_atomic_int *var, int value) { atomic_store(var,value); }
   52 inline int dt_atomic_get_int(dt_atomic_int *var) { return atomic_load(var); }
   53 inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return atomic_fetch_add(var,incr); }
   54 inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return atomic_fetch_sub(var,decr); }
   55 inline int dt_atomic_exch_int(dt_atomic_int *var, int value) { return atomic_exchange(var,value); }
   56 inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
   57 { return atomic_compare_exchange_strong(var,expected,value); }
   58 
   59 #elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNU_MINOR__ >= 8))
   60 // we don't have or aren't supposed to use C11 atomics, but the compiler is a recent-enough version of GCC
   61 // that we can use GNU intrinsics corresponding to the C11 atomics
   62 
   63 typedef volatile int dt_atomic_int;
   64 inline void dt_atomic_set_int(dt_atomic_int *var, int value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
   65 inline int dt_atomic_get_int(dt_atomic_int *var)
   66 { int value ; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
   67 
   68 inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return __atomic_fetch_add(var,incr,__ATOMIC_SEQ_CST); }
   69 inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return __atomic_fetch_sub(var,decr,__ATOMIC_SEQ_CST); }
   70 inline int dt_atomic_exch_int(dt_atomic_int *var, int value)
   71 { int orig;  __atomic_exchange(var,&value,&orig,__ATOMIC_SEQ_CST); return orig; }
   72 inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
   73 { return __atomic_compare_exchange(var,expected,&value,0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); }
   74 
   75 #else
   76 // we don't have or aren't supposed to use C11 atomics, and don't have GNU intrinsics, so
   77 // fall back to using a mutex for synchronization
   78 #include <pthread.h>
   79 
   80 extern pthread_mutex_t dt_atom_mutex;
   81 
   82 typedef int dt_atomic_int;
   83 inline void dt_atomic_set_int(dt_atomic_int *var, int value)
   84 {
   85   pthread_mutex_lock(&dt_atom_mutex);
   86   *var = value;
   87   pthread_mutex_unlock(&dt_atom_mutex);
   88 }
   89 
   90 inline int dt_atomic_get_int(const dt_atomic_int *const var)
   91 {
   92   pthread_mutex_lock(&dt_atom_mutex);
   93   int value = *var;
   94   pthread_mutex_unlock(&dt_atom_mutex);
   95   return value;
   96 }
   97 
   98 inline int dt_atomic_add_int(const dt_atomic_int *const var, int incr)
   99 {
  100   pthread_mutex_lock(&dt_atom_mutex);
  101   int value = *var;
  102   *var += incr;
  103   pthread_mutex_unlock(&dt_atom_mutex);
  104   return value;
  105 }
  106 
  107 inline int dt_atomic_sub_int(const dt_atomic_int *const var, int decr)
  108 {
  109   pthread_mutex_lock(&dt_atom_mutex);
  110   int value = *var;
  111   *var -= decr;
  112   pthread_mutex_unlock(&dt_atom_mutex);
  113   return value;
  114 }
  115 
  116 inline int dt_atomic_exch_int(dt_atomic_int *var, int value)
  117 {
  118   pthread_mutex_lock(&dt_atom_mutex);
  119   int origvalue = *var;
  120   *var = value;
  121   pthread_mutex_unlock(&dt_atom_mutex);
  122   return origvalue;
  123 }
  124 
  125 inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
  126 {
  127   pthread_mutex_lock(&dt_atom_mutex);
  128   int origvalue = *var;
  129   int success = FALSE;
  130   if (origvalue == *expected)
  131   {
  132     *var = value;
  133     success = TRUE;
  134   }
  135   *expected = origvalue;
  136   pthread_mutex_unlock(&dt_atom_mutex);
  137   return success;
  138 }
  139 
  140 #endif // __STDC_NO_ATOMICS__