2 * Many similar implementations exist. See for example libwsbm
3 * or the linux kernel include/atomic.h
5 * No copyright claimed on this file.
12 #include "p_compiler.h"
13 #include "p_defines.h"
20 /* Favor OS-provided implementations.
22 #define PIPE_ATOMIC_OS_UNLOCKED \
23 (defined(PIPE_SUBSYSTEM_WINDOWS_DISPLAY) || \
24 defined(PIPE_SUBSYSTEM_WINDOWS_MINIPORT))
26 #define PIPE_ATOMIC_OS_MS_INTERLOCK \
27 (!defined(PIPE_CC_GCC) && \
28 !PIPE_ATOMIC_OS_UNLOCKED && \
29 defined(PIPE_SUBSYSTEM_WINDOWS_USER))
31 #define PIPE_ATOMIC_OS_PROVIDED \
32 (PIPE_ATOMIC_OS_UNLOCKED || \
33 PIPE_ATOMIC_OS_MS_INTERLOCK)
35 /* Where no OS-provided implementation is available, fall back to
36 * either locally coded assembly or ultimately a mutex-based
39 #define PIPE_ATOMIC_ASM_GCC_X86 \
40 (!PIPE_ATOMIC_OS_PROVIDED && \
41 defined(PIPE_CC_GCC) && \
42 defined(PIPE_ARCH_X86))
44 /* KW: this was originally used when x86 asm wasn't available.
45 * Maintain that logic here.
47 #define PIPE_ATOMIC_GCC_INTRINISIC \
48 (!PIPE_ATOMIC_OS_PROVIDED && \
49 !PIPE_ATOMIC_ASM_GCC_X86 && \
52 #define PIPE_ATOMIC_ASM_MSVC_X86 \
53 (!PIPE_ATOMIC_OS_PROVIDED && \
54 defined(PIPE_CC_MSVC) && \
55 defined(PIPE_ARCH_X86))
57 #define PIPE_ATOMIC_ASM \
58 (PIPE_ATOMIC_ASM_GCC_X86 || \
59 PIPE_ATOMIC_ASM_GCC_INTRINSIC || \
60 PIPE_ATOMIC_ASM_MSVC_X86)
63 /* Where no OS-provided or locally-coded assembly implemenation is
64 * available, use pipe_mutex:
66 #define PIPE_ATOMIC_MUTEX \
67 (!PIPE_ATOMIC_OS_PROVIDED && \
72 #if (PIPE_ATOMIC_ASM_GCC_X86)
74 #define PIPE_ATOMIC "GCC x86 assembly"
80 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
81 #define p_atomic_read(_v) ((_v)->count)
85 p_atomic_dec_zero(struct pipe_atomic
*v
)
89 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(v
->count
), "=qm"(c
)
96 p_atomic_inc(struct pipe_atomic
*v
)
98 __asm__
__volatile__("lock; incl %0":"+m"(v
->count
));
102 p_atomic_dec(struct pipe_atomic
*v
)
104 __asm__
__volatile__("lock; decl %0":"+m"(v
->count
));
107 static INLINE
int32_t
108 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
110 return __sync_val_compare_and_swap(&v
->count
, old
, _new
);
116 /* Implementation using GCC-provided synchronization intrinsics
118 #if (PIPE_ATOMIC_ASM_GCC_INTRINSIC)
120 #define PIPE_ATOMIC "GCC Sync Intrinsics"
126 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
127 #define p_atomic_read(_v) ((_v)->count)
130 static INLINE boolean
131 p_atomic_dec_zero(struct pipe_atomic
*v
)
133 return (__sync_sub_and_fetch(&v
->count
, 1) == 0);
137 p_atomic_inc(struct pipe_atomic
*v
)
139 (void) __sync_add_and_fetch(&v
->count
, 1);
143 p_atomic_dec(struct pipe_atomic
*v
)
145 (void) __sync_sub_and_fetch(&v
->count
, 1);
148 static INLINE
int32_t
149 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
151 return __sync_val_compare_and_swap(&v
->count
, old
, _new
);
157 /* Unlocked version for single threaded environments, such as some
158 * windows kernel modules.
160 #if (PIPE_ATOMIC_OS_UNLOCKED)
162 #define PIPE_ATOMIC "Unlocked"
169 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
170 #define p_atomic_read(_v) ((_v)->count)
171 #define p_atomic_dec_zero(_v) ((boolean) --(_v)->count)
172 #define p_atomic_inc(_v) ((void) (_v)->count++)
173 #define p_atomic_dec(_v) ((void) (_v)->count--)
174 #define p_atomic_cmpxchg(_v, old, _new) ((_v)->count == old ? (_v)->count = (_new) : (_v)->count)
179 /* Locally coded assembly for MSVC on x86:
181 #if (PIPE_ATOMIC_ASM_MSVC_X86)
183 #define PIPE_ATOMIC "MSVC x86 assembly"
190 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
191 #define p_atomic_read(_v) ((_v)->count)
193 static INLINE boolean
194 p_atomic_dec_zero(struct pipe_atomic
*v
)
196 int32_t *pcount
= &v
->count
;
201 lock dec dword ptr
[eax
]
209 p_atomic_inc(struct pipe_atomic
*v
)
211 int32_t *pcount
= &v
->count
;
215 lock inc dword ptr
[eax
]
220 p_atomic_dec(struct pipe_atomic
*v
)
222 int32_t *pcount
= &v
->count
;
226 lock dec dword ptr
[eax
]
230 static INLINE
int32_t
231 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
233 int32_t *pcount
= &v
->count
;
240 lock cmpxchg
[ecx
], edx
249 #if (PIPE_ATOMIC_OS_MS_INTERLOCK)
251 #define PIPE_ATOMIC "MS userspace interlocks"
260 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
261 #define p_atomic_read(_v) ((_v)->count)
263 static INLINE boolean
264 p_atomic_dec_zero(struct pipe_atomic
*v
)
266 return InterlockedDecrement(&v
->count
);
270 p_atomic_inc(struct pipe_atomic
*v
)
272 InterlockedIncrement(&v
->count
);
276 p_atomic_dec(struct pipe_atomic
*v
)
278 InterlockedDecrement(&v
->count
);
281 static INLINE
int32_t
282 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
284 return InterlockedCompareExchange(&v
->count
, _new
, old
);
291 #if (PIPE_ATOMIC_MUTEX)
293 #define PIPE_ATOMIC "mutex-based fallback"
295 #include "pipe/p_thread.h"
298 * This implementation should really not be used.
299 * Add an assembly port instead. It may abort and
300 * doesn't destroy used mutexes.
309 p_atomic_set(struct pipe_atomic
*v
, int32_t i
)
311 pipe_mutex_init(v
->mutex
);
312 pipe_mutex_lock(v
->mutex
);
314 pipe_mutex_unlock(v
->mutex
);
317 static INLINE
int32_t
318 p_atomic_read(struct pipe_atomic
*v
)
322 pipe_mutex_lock(v
->mutex
);
324 pipe_mutex_unlock(v
->mutex
);
329 p_atomic_inc(struct pipe_atomic
*v
)
331 pipe_mutex_lock(v
->mutex
);
333 pipe_mutex_unlock(v
->mutex
);
337 p_atomic_dec(struct pipe_atomic
*v
)
339 pipe_mutex_lock(v
->mutex
);
341 pipe_mutex_unlock(v
->mutex
);
344 static INLINE boolean
345 p_atomic_dec_zero(struct pipe_atomic
*v
)
349 pipe_mutex_lock(v
->mutex
);
350 ret
= (--v
->count
== 0);
351 pipe_mutex_unlock(v
->mutex
);
355 static INLINE
int32_t
356 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
360 pipe_mutex_lock(v
->mutex
);
364 pipe_mutex_unlock(v
->mutex
);
373 #error "No pipe_atomic implementation selected"
382 #endif /* P_ATOMIC_H */