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#pragma once
23
24#include <stdint.h>
25
26// implement an atomic variable for inter-thread signalling purposes
27// the manner in which we implement depends on the capabilities of the compiler:
28// 1. standard-compliant C++ compiler: use C++11 atomics in <atomic>
29// 2. standard-compliant C compiler: use C11 atomics in <stdatomic.h>
30// 3. GCC 4.8+: use intrinsics
31// 4. otherwise: fall back to using Posix mutex to serialize access
32
33#if defined(__cplusplus) && __cplusplus > 201100
34// Shared structs cross C and C++ translation units. Keep atomic storage layout identical to the C side
35// and use compiler builtins for synchronization, otherwise std::atomic can change ABI-visible layout.
36typedef int dt_atomic_int;
37typedef uint64_t dt_atomic_uint64;
38typedef void *dt_atomic_ptr;
39static inline void dt_atomic_set_int(dt_atomic_int *var, int value) { __atomic_store_n(var, value, __ATOMIC_SEQ_CST); }
40static inline int dt_atomic_get_int(dt_atomic_int *var) { return __atomic_load_n(var, __ATOMIC_SEQ_CST); }
41static inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
42{
43 __atomic_store_n(var, value, __ATOMIC_SEQ_CST);
44}
45static inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
46{
47 return __atomic_load_n(var, __ATOMIC_SEQ_CST);
48}
49static inline void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value) { __atomic_store_n(var, value, __ATOMIC_SEQ_CST); }
50static inline void *dt_atomic_get_ptr(const dt_atomic_ptr *var) { return __atomic_load_n(var, __ATOMIC_SEQ_CST); }
51static inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return __atomic_fetch_add(var, incr, __ATOMIC_SEQ_CST); }
52static inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return __atomic_fetch_sub(var, decr, __ATOMIC_SEQ_CST); }
53static inline int dt_atomic_exch_int(dt_atomic_int *var, int value) { return __atomic_exchange_n(var, value, __ATOMIC_SEQ_CST); }
54static inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
55{
56 return __atomic_compare_exchange_n(var, expected, value, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
57}
58
59static inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { __atomic_fetch_or(var, flags, __ATOMIC_SEQ_CST); }
60static inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { __atomic_fetch_and(var, flags, __ATOMIC_SEQ_CST); }
61
62#elif !defined(__STDC_NO_ATOMICS__)
63
64#include <stdatomic.h>
65
66typedef atomic_int dt_atomic_int;
67typedef _Atomic(uint64_t) dt_atomic_uint64;
68typedef _Atomic(void *) dt_atomic_ptr;
69static inline void dt_atomic_set_int(dt_atomic_int *var, int value) { atomic_store(var,value); }
70static inline int dt_atomic_get_int(dt_atomic_int *var) { return atomic_load(var); }
71static inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value) { atomic_store(var,value); }
72static inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var) { return atomic_load(var); }
73static inline void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value) { atomic_store(var,value); }
74static inline void *dt_atomic_get_ptr(const dt_atomic_ptr *var) { return atomic_load(var); }
75static inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return atomic_fetch_add(var,incr); }
76static inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return atomic_fetch_sub(var,decr); }
77static inline int dt_atomic_exch_int(dt_atomic_int *var, int value) { return atomic_exchange(var,value); }
78static inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
79{ return atomic_compare_exchange_strong(var,expected,value); }
80
81static inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { atomic_fetch_or(var, flags); }
82static inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { atomic_fetch_and(var, flags); }
83
84#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNU_MINOR__ >= 8))
85// we don't have or aren't supposed to use C11 atomics, but the compiler is a recent-enough version of GCC
86// that we can use GNU intrinsics corresponding to the C11 atomics
87
88typedef volatile int dt_atomic_int;
89typedef volatile uint64_t dt_atomic_uint64;
90typedef void *volatile dt_atomic_ptr;
91static inline void dt_atomic_set_int(dt_atomic_int *var, int value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
92static inline int dt_atomic_get_int(dt_atomic_int *var)
93{ int value ; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
94static inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
95static inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
96{ uint64_t value; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
97static inline void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
98static inline void *dt_atomic_get_ptr(const dt_atomic_ptr *var)
99{ void *value; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
100
101static inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return __atomic_fetch_add(var,incr,__ATOMIC_SEQ_CST); }
102static inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return __atomic_fetch_sub(var,decr,__ATOMIC_SEQ_CST); }
103static inline int dt_atomic_exch_int(dt_atomic_int *var, int value)
104{ int orig; __atomic_exchange(var,&value,&orig,__ATOMIC_SEQ_CST); return orig; }
105static inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
106{ return __atomic_compare_exchange(var,expected,&value,0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); }
107
108static inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { __atomic_fetch_or(var, flags, __ATOMIC_SEQ_CST); }
109static inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { __atomic_fetch_and(var, flags, __ATOMIC_SEQ_CST); }
110
111#else
112// we don't have or aren't supposed to use C11 atomics, and don't have GNU intrinsics, so
113// fall back to using a mutex for synchronization
114#include <pthread.h>
115
116extern pthread_mutex_t dt_atom_mutex;
117
118typedef int dt_atomic_int;
119typedef uint64_t dt_atomic_uint64;
120typedef void *dt_atomic_ptr;
121static inline void dt_atomic_set_int(dt_atomic_int *var, int value)
122{
123 pthread_mutex_lock(&dt_atom_mutex);
124 *var = value;
125 pthread_mutex_unlock(&dt_atom_mutex);
126}
127
128static inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
129{
130 pthread_mutex_lock(&dt_atom_mutex);
131 *var = value;
132 pthread_mutex_unlock(&dt_atom_mutex);
133}
134
135static inline void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value)
136{
137 pthread_mutex_lock(&dt_atom_mutex);
138 *var = value;
139 pthread_mutex_unlock(&dt_atom_mutex);
140}
141
142static inline int dt_atomic_get_int(const dt_atomic_int *const var)
143{
144 pthread_mutex_lock(&dt_atom_mutex);
145 int value = *var;
146 pthread_mutex_unlock(&dt_atom_mutex);
147 return value;
148}
149
150static inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *const var)
151{
152 pthread_mutex_lock(&dt_atom_mutex);
153 const uint64_t value = *var;
154 pthread_mutex_unlock(&dt_atom_mutex);
155 return value;
156}
157
158static inline void *dt_atomic_get_ptr(const dt_atomic_ptr *const var)
159{
160 pthread_mutex_lock(&dt_atom_mutex);
161 void *value = *var;
162 pthread_mutex_unlock(&dt_atom_mutex);
163 return value;
164}
165
166static inline int dt_atomic_add_int(const dt_atomic_int *const var, int incr)
167{
168 pthread_mutex_lock(&dt_atom_mutex);
169 int value = *var;
170 *var += incr;
171 pthread_mutex_unlock(&dt_atom_mutex);
172 return value;
173}
174
175static inline int dt_atomic_sub_int(const dt_atomic_int *const var, int decr)
176{
177 pthread_mutex_lock(&dt_atom_mutex);
178 int value = *var;
179 *var -= decr;
180 pthread_mutex_unlock(&dt_atom_mutex);
181 return value;
182}
183
184static inline int dt_atomic_exch_int(dt_atomic_int *var, int value)
185{
186 pthread_mutex_lock(&dt_atom_mutex);
187 int origvalue = *var;
188 *var = value;
189 pthread_mutex_unlock(&dt_atom_mutex);
190 return origvalue;
191}
192
193static inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
194{
195 pthread_mutex_lock(&dt_atom_mutex);
196 int origvalue = *var;
197 int success = FALSE;
198 if (origvalue == *expected)
199 {
200 *var = value;
201 success = TRUE;
202 }
203 *expected = origvalue;
204 pthread_mutex_unlock(&dt_atom_mutex);
205 return success;
206}
207
208static inline void dt_atomic_or_int(dt_atomic_int *var, int flags)
209{
210 pthread_mutex_lock(&dt_atom_mutex);
211 *var |= flags;
212 pthread_mutex_unlock(&dt_atom_mutex);
213}
214
215static inline void dt_atomic_and_int(dt_atomic_int *var, int flags)
216{
217 pthread_mutex_lock(&dt_atom_mutex);
218 *var &= flags;
219 pthread_mutex_unlock(&dt_atom_mutex);
220}
221
222#endif // __STDC_NO_ATOMICS__
223
224// clang-format off
225// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
226// vim: shiftwidth=2 expandtab tabstop=2 cindent
227// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
228// 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:69
static void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
Definition atomic.h:71
static int dt_atomic_add_int(dt_atomic_int *var, int incr)
Definition atomic.h:75
static void * dt_atomic_get_ptr(const dt_atomic_ptr *var)
Definition atomic.h:74
typedef _Atomic(uint64_t) dt_atomic_uint64
atomic_int dt_atomic_int
Definition atomic.h:66
static void dt_atomic_or_int(dt_atomic_int *var, int flags)
Definition atomic.h:81
static int dt_atomic_sub_int(dt_atomic_int *var, int decr)
Definition atomic.h:76
static uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
Definition atomic.h:72
static int dt_atomic_exch_int(dt_atomic_int *var, int value)
Definition atomic.h:77
static void dt_atomic_set_ptr(dt_atomic_ptr *var, void *value)
Definition atomic.h:73
static int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
Definition atomic.h:78
static void dt_atomic_and_int(dt_atomic_int *var, int flags)
Definition atomic.h:82
static int dt_atomic_get_int(dt_atomic_int *var)
Definition atomic.h:70
static const dt_aligned_pixel_simd_t value
Definition darktable.h:577
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
unsigned __int64 uint64_t
Definition strptime.c:75