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 (!PIPE_ATOMIC_OS_UNLOCKED && \
28 defined(PIPE_SUBSYSTEM_WINDOWS_USER))
30 #define PIPE_ATOMIC_OS_PROVIDED \
31 (PIPE_ATOMIC_OS_UNLOCKED || \
32 PIPE_ATOMIC_OS_MS_INTERLOCK)
34 /* Where no OS-provided implementation is available, fall back to
35 * either locally coded assembly or ultimately a mutex-based
38 #define PIPE_ATOMIC_ASM_GCC_X86 \
39 (!PIPE_ATOMIC_OS_PROVIDED && \
40 defined(PIPE_CC_GCC) && \
41 defined(PIPE_ARCH_X86))
43 /* KW: this was originally used when x86 asm wasn't available.
44 * Maintain that logic here.
46 #define PIPE_ATOMIC_GCC_INTRINISIC \
47 (!PIPE_ATOMIC_OS_PROVIDED && \
48 !PIPE_ATOMIC_ASM_GCC_X86 && \
51 #define PIPE_ATOMIC_ASM_MSVC_X86 \
52 (!PIPE_ATOMIC_OS_PROVIDED && \
53 defined(PIPE_CC_MSVC) && \
54 defined(PIPE_ARCH_X86))
56 #define PIPE_ATOMIC_ASM \
57 (PIPE_ATOMIC_ASM_GCC_X86 || \
58 PIPE_ATOMIC_ASM_GCC_INTRINSIC || \
59 PIPE_ATOMIC_ASM_MSVC_X86)
62 /* Where no OS-provided or locally-coded assembly implemenation is
63 * available, use pipe_mutex:
65 #define PIPE_ATOMIC_MUTEX \
66 (!PIPE_ATOMIC_OS_PROVIDED && \
71 #if (PIPE_ATOMIC_ASM_GCC_X86)
73 #define PIPE_ATOMIC "GCC x86 assembly"
79 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
80 #define p_atomic_read(_v) ((_v)->count)
84 p_atomic_dec_zero(struct pipe_atomic
*v
)
88 __asm__
__volatile__("lock; decl %0; sete %1":"+m"(v
->count
), "=qm"(c
)
95 p_atomic_inc(struct pipe_atomic
*v
)
97 __asm__
__volatile__("lock; incl %0":"+m"(v
->count
));
101 p_atomic_dec(struct pipe_atomic
*v
)
103 __asm__
__volatile__("lock; decl %0":"+m"(v
->count
));
106 static INLINE
int32_t
107 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
109 return __sync_val_compare_and_swap(&v
->count
, old
, _new
);
115 /* Implementation using GCC-provided synchronization intrinsics
117 #if (PIPE_ATOMIC_ASM_GCC_INTRINSIC)
119 #define PIPE_ATOMIC "GCC Sync Intrinsics"
125 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
126 #define p_atomic_read(_v) ((_v)->count)
129 static INLINE boolean
130 p_atomic_dec_zero(struct pipe_atomic
*v
)
132 return (__sync_sub_and_fetch(&v
->count
, 1) == 0);
136 p_atomic_inc(struct pipe_atomic
*v
)
138 (void) __sync_add_and_fetch(&v
->count
, 1);
142 p_atomic_dec(struct pipe_atomic
*v
)
144 (void) __sync_sub_and_fetch(&v
->count
, 1);
147 static INLINE
int32_t
148 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
150 return __sync_val_compare_and_swap(&v
->count
, old
, _new
);
156 /* Unlocked version for single threaded environments, such as some
157 * windows kernel modules.
159 #if (PIPE_ATOMIC_OS_UNLOCKED)
161 #define PIPE_ATOMIC "Unlocked"
168 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
169 #define p_atomic_read(_v) ((_v)->count)
170 #define p_atomic_dec_zero(_v) ((boolean) --(_v)->count)
171 #define p_atomic_inc(_v) ((void) (_v)->count++)
172 #define p_atomic_dec(_v) ((void) (_v)->count--)
173 #define p_atomic_cmpxchg(_v, old, _new) ((_v)->count == old ? (_v)->count = (_new) : (_v)->count)
178 /* Locally coded assembly for MSVC on x86:
180 #if (PIPE_ATOMIC_ASM_MSVC_X86)
182 #define PIPE_ATOMIC "MSVC x86 assembly"
189 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
190 #define p_atomic_read(_v) ((_v)->count)
192 static INLINE boolean
193 p_atomic_dec_zero(struct pipe_atomic
*v
)
195 int32_t *pcount
= &v
->count
;
200 lock dec dword ptr
[eax
]
208 p_atomic_inc(struct pipe_atomic
*v
)
210 int32_t *pcount
= &v
->count
;
214 lock inc dword ptr
[eax
]
219 p_atomic_dec(struct pipe_atomic
*v
)
221 int32_t *pcount
= &v
->count
;
225 lock dec dword ptr
[eax
]
229 static INLINE
int32_t
230 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
232 int32_t *pcount
= &v
->count
;
239 lock cmpxchg
[ecx
], edx
248 #if (PIPE_ATOMIC_OS_MS_INTERLOCK)
250 #define PIPE_ATOMIC "MS userspace interlocks"
259 #define p_atomic_set(_v, _i) ((_v)->count = (_i))
260 #define p_atomic_read(_v) ((_v)->count)
262 static INLINE boolean
263 p_atomic_dec_zero(struct pipe_atomic
*v
)
265 return InterlockedDecrement(&v
->count
);
269 p_atomic_inc(struct pipe_atomic
*v
)
271 InterlockedIncrement(&v
->count
);
275 p_atomic_dec(struct pipe_atomic
*v
)
277 InterlockedDecrement(&v
->count
);
280 static INLINE
int32_t
281 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
283 return InterlockedCompareExchange(&v
->count
, _new
, old
);
290 #if (PIPE_ATOMIC_MUTEX)
292 #define PIPE_ATOMIC "mutex-based fallback"
294 #include "pipe/p_thread.h"
297 * This implementation should really not be used.
298 * Add an assembly port instead. It may abort and
299 * doesn't destroy used mutexes.
308 p_atomic_set(struct pipe_atomic
*v
, int32_t i
)
310 pipe_mutex_init(v
->mutex
);
311 pipe_mutex_lock(v
->mutex
);
313 pipe_mutex_unlock(v
->mutex
);
316 static INLINE
int32_t
317 p_atomic_read(struct pipe_atomic
*v
)
321 pipe_mutex_lock(v
->mutex
);
323 pipe_mutex_unlock(v
->mutex
);
328 p_atomic_inc(struct pipe_atomic
*v
)
330 pipe_mutex_lock(v
->mutex
);
332 pipe_mutex_unlock(v
->mutex
);
336 p_atomic_dec(struct pipe_atomic
*v
)
338 pipe_mutex_lock(v
->mutex
);
340 pipe_mutex_unlock(v
->mutex
);
343 static INLINE boolean
344 p_atomic_dec_zero(struct pipe_atomic
*v
)
348 pipe_mutex_lock(v
->mutex
);
349 ret
= (--v
->count
== 0);
350 pipe_mutex_unlock(v
->mutex
);
354 static INLINE
int32_t
355 p_atomic_cmpxchg(struct pipe_atomic
*v
, int32_t old
, int32_t _new
)
359 pipe_mutex_lock(v
->mutex
);
363 pipe_mutex_unlock(v
->mutex
);
372 #error "No pipe_atomic implementation selected"
381 #endif /* P_ATOMIC_H */