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;
38inline void dt_atomic_set_int(dt_atomic_int *var, int value) { __atomic_store_n(var, value, __ATOMIC_SEQ_CST); }
39inline int dt_atomic_get_int(dt_atomic_int *var) { return __atomic_load_n(var, __ATOMIC_SEQ_CST); }
40inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
41{
42 __atomic_store_n(var, value, __ATOMIC_SEQ_CST);
43}
44inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
45{
46 return __atomic_load_n(var, __ATOMIC_SEQ_CST);
47}
48inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return __atomic_fetch_add(var, incr, __ATOMIC_SEQ_CST); }
49inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return __atomic_fetch_sub(var, decr, __ATOMIC_SEQ_CST); }
50inline int dt_atomic_exch_int(dt_atomic_int *var, int value) { return __atomic_exchange_n(var, value, __ATOMIC_SEQ_CST); }
51inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
52{
53 return __atomic_compare_exchange_n(var, expected, value, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);
54}
55
56inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { __atomic_fetch_or(var, flags, __ATOMIC_SEQ_CST); }
57inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { __atomic_fetch_and(var, flags, __ATOMIC_SEQ_CST); }
58
59#elif !defined(__STDC_NO_ATOMICS__)
60
61#include <stdatomic.h>
62
63typedef atomic_int dt_atomic_int;
64typedef _Atomic(uint64_t) dt_atomic_uint64;
65inline void dt_atomic_set_int(dt_atomic_int *var, int value) { atomic_store(var,value); }
66inline int dt_atomic_get_int(dt_atomic_int *var) { return atomic_load(var); }
67inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value) { atomic_store(var,value); }
68inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var) { return atomic_load(var); }
69inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return atomic_fetch_add(var,incr); }
70inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return atomic_fetch_sub(var,decr); }
71inline int dt_atomic_exch_int(dt_atomic_int *var, int value) { return atomic_exchange(var,value); }
72inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
73{ return atomic_compare_exchange_strong(var,expected,value); }
74
75inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { atomic_fetch_or(var, flags); }
76inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { atomic_fetch_and(var, flags); }
77
78#elif defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNU_MINOR__ >= 8))
79// we don't have or aren't supposed to use C11 atomics, but the compiler is a recent-enough version of GCC
80// that we can use GNU intrinsics corresponding to the C11 atomics
81
82typedef volatile int dt_atomic_int;
83typedef volatile uint64_t dt_atomic_uint64;
84inline void dt_atomic_set_int(dt_atomic_int *var, int value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
85inline int dt_atomic_get_int(dt_atomic_int *var)
86{ int value ; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
87inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value) { __atomic_store(var,&value,__ATOMIC_SEQ_CST); }
88inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
89{ uint64_t value; __atomic_load(var,&value,__ATOMIC_SEQ_CST); return value; }
90
91inline int dt_atomic_add_int(dt_atomic_int *var, int incr) { return __atomic_fetch_add(var,incr,__ATOMIC_SEQ_CST); }
92inline int dt_atomic_sub_int(dt_atomic_int *var, int decr) { return __atomic_fetch_sub(var,decr,__ATOMIC_SEQ_CST); }
93inline int dt_atomic_exch_int(dt_atomic_int *var, int value)
94{ int orig; __atomic_exchange(var,&value,&orig,__ATOMIC_SEQ_CST); return orig; }
95inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
96{ return __atomic_compare_exchange(var,expected,&value,0,__ATOMIC_SEQ_CST,__ATOMIC_SEQ_CST); }
97
98inline void dt_atomic_or_int(dt_atomic_int *var, int flags) { __atomic_fetch_or(var, flags, __ATOMIC_SEQ_CST); }
99inline void dt_atomic_and_int(dt_atomic_int *var, int flags) { __atomic_fetch_and(var, flags, __ATOMIC_SEQ_CST); }
100
101#else
102// we don't have or aren't supposed to use C11 atomics, and don't have GNU intrinsics, so
103// fall back to using a mutex for synchronization
104#include <pthread.h>
105
106extern pthread_mutex_t dt_atom_mutex;
107
108typedef int dt_atomic_int;
109typedef uint64_t dt_atomic_uint64;
110inline void dt_atomic_set_int(dt_atomic_int *var, int value)
111{
112 pthread_mutex_lock(&dt_atom_mutex);
113 *var = value;
114 pthread_mutex_unlock(&dt_atom_mutex);
115}
116
117inline void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
118{
119 pthread_mutex_lock(&dt_atom_mutex);
120 *var = value;
121 pthread_mutex_unlock(&dt_atom_mutex);
122}
123
124inline int dt_atomic_get_int(const dt_atomic_int *const var)
125{
126 pthread_mutex_lock(&dt_atom_mutex);
127 int value = *var;
128 pthread_mutex_unlock(&dt_atom_mutex);
129 return value;
130}
131
132inline uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *const var)
133{
134 pthread_mutex_lock(&dt_atom_mutex);
135 const uint64_t value = *var;
136 pthread_mutex_unlock(&dt_atom_mutex);
137 return value;
138}
139
140inline int dt_atomic_add_int(const dt_atomic_int *const var, int incr)
141{
142 pthread_mutex_lock(&dt_atom_mutex);
143 int value = *var;
144 *var += incr;
145 pthread_mutex_unlock(&dt_atom_mutex);
146 return value;
147}
148
149inline int dt_atomic_sub_int(const dt_atomic_int *const var, int decr)
150{
151 pthread_mutex_lock(&dt_atom_mutex);
152 int value = *var;
153 *var -= decr;
154 pthread_mutex_unlock(&dt_atom_mutex);
155 return value;
156}
157
158inline int dt_atomic_exch_int(dt_atomic_int *var, int value)
159{
160 pthread_mutex_lock(&dt_atom_mutex);
161 int origvalue = *var;
162 *var = value;
163 pthread_mutex_unlock(&dt_atom_mutex);
164 return origvalue;
165}
166
167inline int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
168{
169 pthread_mutex_lock(&dt_atom_mutex);
170 int origvalue = *var;
171 int success = FALSE;
172 if (origvalue == *expected)
173 {
174 *var = value;
175 success = TRUE;
176 }
177 *expected = origvalue;
178 pthread_mutex_unlock(&dt_atom_mutex);
179 return success;
180}
181
182inline void dt_atomic_or_int(dt_atomic_int *var, int flags)
183{
184 pthread_mutex_lock(&dt_atom_mutex);
185 *var |= flags;
186 pthread_mutex_unlock(&dt_atom_mutex);
187}
188
189inline void dt_atomic_and_int(dt_atomic_int *var, int flags)
190{
191 pthread_mutex_lock(&dt_atom_mutex);
192 *var &= flags;
193 pthread_mutex_unlock(&dt_atom_mutex);
194}
195
196#endif // __STDC_NO_ATOMICS__
197
198// clang-format off
199// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
200// vim: shiftwidth=2 expandtab tabstop=2 cindent
201// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
202// clang-format on
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_atomic_set_int(dt_atomic_int *var, int value)
Definition atomic.h:65
int dt_atomic_get_int(dt_atomic_int *var)
Definition atomic.h:66
uint64_t dt_atomic_get_uint64(const dt_atomic_uint64 *var)
Definition atomic.h:68
typedef _Atomic(uint64_t) dt_atomic_uint64
atomic_int dt_atomic_int
Definition atomic.h:63
int dt_atomic_sub_int(dt_atomic_int *var, int decr)
Definition atomic.h:70
int dt_atomic_add_int(dt_atomic_int *var, int incr)
Definition atomic.h:69
void dt_atomic_set_uint64(dt_atomic_uint64 *var, uint64_t value)
Definition atomic.h:67
void dt_atomic_and_int(dt_atomic_int *var, int flags)
Definition atomic.h:76
int dt_atomic_CAS_int(dt_atomic_int *var, int *expected, int value)
Definition atomic.h:72
int dt_atomic_exch_int(dt_atomic_int *var, int value)
Definition atomic.h:71
void dt_atomic_or_int(dt_atomic_int *var, int flags)
Definition atomic.h:75
static const dt_aligned_pixel_simd_t value
Definition darktable.h:501
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
unsigned __int64 uint64_t
Definition strptime.c:74