Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
atomic.h
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2020 Ralf Brown.
4 Copyright (C) 2021 luzpaz.
5 Copyright (C) 2022 Martin Baƙinka.
6 Copyright (C) 2025 Alynx Zhou.
7
8 darktable is free software: you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation, either version 3 of the License, or
11 (at your option) any later version.
12
13 darktable is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with darktable. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#ifndef DT_SYSTEM_ATOMIC_H
23#define DT_SYSTEM_ATOMIC_H
24
25#include <stdint.h>
26
27// implement an atomic variable for inter-thread signalling purposes
28// the manner in which we implement depends on the capabilities of the compiler:
29// 1. standard-compliant C++ compiler: use C++11 atomics in <atomic>
30// 2. standard-compliant C compiler: use C11 atomics in <stdatomic.h>
31// 3. GCC 4.8+: use intrinsics
32// 4. otherwise: fall back to using Posix mutex to serialize access
33
34#if defined(__cplusplus) && __cplusplus > 201100
35// Shared structs cross C and C++ translation units. Keep atomic storage layout identical to the C side
36// and use compiler builtins for synchronization, otherwise std::atomic can change ABI-visible layout.
37typedef int dt_atomic_int;
38typedef uint64_t dt_atomic_uint64;
39typedef void *dt_atomic_ptr;
40static inline void dt_atomic_set_int(dt_atomic_int *var, int value) { __atomic_store_n(var, value, __ATOMIC_SEQ_CST); }
41static inline int dt_atomic_get_int(dt_atomic_int *var) { return __atomic_load_n(var, __ATOMIC_SEQ_CST); }
42static inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
43{
44 __atomic_store_n(var, value, __ATOMIC_SEQ_CST);
45}
46static inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
47{
48 return __atomic_load_n(var, __ATOMIC_SEQ_CST);
49}
50static inline void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value) { __atomic_store_n(var, value, __ATOMIC_SEQ_CST); }
51static inline void *dt_atomic_get_ptr(const dt_atomic_ptr *var) { return __atomic_load_n(var, __ATOMIC_SEQ_CST); }
52static inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return __atomic_fetch_add(var, incr, __ATOMIC_SEQ_CST); }
53static inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return __atomic_fetch_sub(var, decr, __ATOMIC_SEQ_CST); }
54static inline int dt_atomic_exch_int(dt_atomic_int *var, int value) { return __atomic_exchange_n(var, value, __ATOMIC_SEQ_CST); }
55static inline void *dt_atomic_exch_ptr(dt_atomic_ptr *var, void *value) { return __atomic_exchange_n(var, value, __ATOMIC_SEQ_CST); }
56static inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
57{
58 return __atomic_compare_exchange_n(var, expected, value, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
59}
60
61static inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { __atomic_fetch_or(var, flags, __ATOMIC_SEQ_CST); }
62static inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { __atomic_fetch_and(var, flags, __ATOMIC_SEQ_CST); }
63
64#elif !defined(__STDC_NO_ATOMICS__)
65
66#include <stdatomic.h>
67
68typedef atomic_int dt_atomic_int;
69typedef _Atomic(uint64_t) dt_atomic_uint64;
70typedef _Atomic(void *) dt_atomic_ptr;
71static inline void dt_atomic_set_int(dt_atomic_int *var, int value) { atomic_store(var,value); }
72static inline int dt_atomic_get_int(dt_atomic_int *var) { return atomic_load(var); }
73static inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value) { atomic_store(var,value); }
74static inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var) { return atomic_load(var); }
75static inline void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value) { atomic_store(var,value); }
76static inline void *dt_atomic_get_ptr(const dt_atomic_ptr *var) { return atomic_load(var); }
77static inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return atomic_fetch_add(var,incr); }
78static inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return atomic_fetch_sub(var,decr); }
79static inline int dt_atomic_exch_int(dt_atomic_int *var, int value) { return atomic_exchange(var,value); }
80static inline void *dt_atomic_exch_ptr(dt_atomic_ptr *var, void *value) { return atomic_exchange(var,value); }
81static inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
82{ return atomic_compare_exchange_strong(var,expected,value); }
83
84static inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { atomic_fetch_or(var, flags); }
85static inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { atomic_fetch_and(var, flags); }
86
87#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNU_MINOR__ >= 8))
88// we don't have or aren't supposed to use C11 atomics, but the compiler is a recent-enough version of GCC
89// that we can use GNU intrinsics corresponding to the C11 atomics
90
91typedef volatile int dt_atomic_int;
92typedef volatile uint64_t dt_atomic_uint64;
93typedef void *volatile dt_atomic_ptr;
94static inline void dt_atomic_set_int(dt_atomic_int *var, int value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
95static inline int dt_atomic_get_int(dt_atomic_int *var)
96{ int value ; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
97static inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
98static inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
99{ uint64_t value; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
100static inline void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
101static inline void *dt_atomic_get_ptr(const dt_atomic_ptr *var)
102{ void *value; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
103
104static inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return __atomic_fetch_add(var,incr,__ATOMIC_SEQ_CST); }
105static inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return __atomic_fetch_sub(var,decr,__ATOMIC_SEQ_CST); }
106static inline int dt_atomic_exch_int(dt_atomic_int *var, int value)
107{ int orig; __atomic_exchange(var,&value,&orig,__ATOMIC_SEQ_CST); return orig; }
108static inline void *dt_atomic_exch_ptr(dt_atomic_ptr *var, void *value)
109{ void *orig; __atomic_exchange(var,&value,&orig,__ATOMIC_SEQ_CST); return orig; }
110static inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
111{ return __atomic_compare_exchange(var,expected,&value,0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); }
112
113static inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { __atomic_fetch_or(var, flags, __ATOMIC_SEQ_CST); }
114static inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { __atomic_fetch_and(var, flags, __ATOMIC_SEQ_CST); }
115
116#else
117// we don't have or aren't supposed to use C11 atomics, and don't have GNU intrinsics, so
118// fall back to using a mutex for synchronization
119#include <pthread.h>
120
121extern pthread_mutex_t dt_atom_mutex;
122
123typedef int dt_atomic_int;
124typedef uint64_t dt_atomic_uint64;
125typedef void *dt_atomic_ptr;
126static inline void dt_atomic_set_int(dt_atomic_int *var, int value)
127{
128 pthread_mutex_lock(&dt_atom_mutex);
129 *var = value;
130 pthread_mutex_unlock(&dt_atom_mutex);
131}
132
133static inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
134{
135 pthread_mutex_lock(&dt_atom_mutex);
136 *var = value;
137 pthread_mutex_unlock(&dt_atom_mutex);
138}
139
140static inline void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value)
141{
142 pthread_mutex_lock(&dt_atom_mutex);
143 *var = value;
144 pthread_mutex_unlock(&dt_atom_mutex);
145}
146
147static inline int dt_atomic_get_int(const dt_atomic_int *const var)
148{
149 pthread_mutex_lock(&dt_atom_mutex);
150 int value = *var;
151 pthread_mutex_unlock(&dt_atom_mutex);
152 return value;
153}
154
155static inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *const var)
156{
157 pthread_mutex_lock(&dt_atom_mutex);
158 const uint64_t value = *var;
159 pthread_mutex_unlock(&dt_atom_mutex);
160 return value;
161}
162
163static inline void *dt_atomic_get_ptr(const dt_atomic_ptr *const var)
164{
165 pthread_mutex_lock(&dt_atom_mutex);
166 void *value = *var;
167 pthread_mutex_unlock(&dt_atom_mutex);
168 return value;
169}
170
171static inline int dt_atomic_add_int(const dt_atomic_int *const var, int incr)
172{
173 pthread_mutex_lock(&dt_atom_mutex);
174 int value = *var;
175 *var += incr;
176 pthread_mutex_unlock(&dt_atom_mutex);
177 return value;
178}
179
180static inline int dt_atomic_sub_int(const dt_atomic_int *const var, int decr)
181{
182 pthread_mutex_lock(&dt_atom_mutex);
183 int value = *var;
184 *var -= decr;
185 pthread_mutex_unlock(&dt_atom_mutex);
186 return value;
187}
188
189static inline int dt_atomic_exch_int(dt_atomic_int *var, int value)
190{
191 pthread_mutex_lock(&dt_atom_mutex);
192 int origvalue = *var;
193 *var = value;
194 pthread_mutex_unlock(&dt_atom_mutex);
195 return origvalue;
196}
197
198static inline void *dt_atomic_exch_ptr(dt_atomic_ptr *var, void *value)
199{
200 pthread_mutex_lock(&dt_atom_mutex);
201 void *origvalue = *var;
202 *var = value;
203 pthread_mutex_unlock(&dt_atom_mutex);
204 return origvalue;
205}
206
207static inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
208{
209 pthread_mutex_lock(&dt_atom_mutex);
210 int origvalue = *var;
211 int success = FALSE;
212 if (origvalue == *expected)
213 {
214 *var = value;
215 success = TRUE;
216 }
217 *expected = origvalue;
218 pthread_mutex_unlock(&dt_atom_mutex);
219 return success;
220}
221
222static inline void dt_atomic_or_int(dt_atomic_int *var, int flags)
223{
224 pthread_mutex_lock(&dt_atom_mutex);
225 *var |= flags;
226 pthread_mutex_unlock(&dt_atom_mutex);
227}
228
229static inline void dt_atomic_and_int(dt_atomic_int *var, int flags)
230{
231 pthread_mutex_lock(&dt_atom_mutex);
232 *var &= flags;
233 pthread_mutex_unlock(&dt_atom_mutex);
234}
235
236#endif // __STDC_NO_ATOMICS__
237
238#endif // DT_SYSTEM_ATOMIC_H
239
240// clang-format off
241// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
242// vim: shiftwidth=2 expandtab tabstop=2 cindent
243// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
244// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
static void dt_atomic_set_int(dt_atomic_int *var, int value)
Definition atomic.h:71
static void * dt_atomic_exch_ptr(dt_atomic_ptr *var, void *value)
Definition atomic.h:80
static void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
Definition atomic.h:73
static int dt_atomic_add_int(dt_atomic_int *var, int incr)
Definition atomic.h:77
static void * dt_atomic_get_ptr(const dt_atomic_ptr *var)
Definition atomic.h:76
typedef _Atomic(uint64_t) dt_atomic_uint64
atomic_int dt_atomic_int
Definition atomic.h:68
static void dt_atomic_or_int(dt_atomic_int *var, int flags)
Definition atomic.h:84
static int dt_atomic_sub_int(dt_atomic_int *var, int decr)
Definition atomic.h:78
static uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
Definition atomic.h:74
static int dt_atomic_exch_int(dt_atomic_int *var, int value)
Definition atomic.h:79
static void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value)
Definition atomic.h:75
static int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
Definition atomic.h:81
static void dt_atomic_and_int(dt_atomic_int *var, int flags)
Definition atomic.h:85
static int dt_atomic_get_int(dt_atomic_int *var)
Definition atomic.h:72
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
unsigned __int64 uint64_t
Definition strptime.c:75