Add default-monitor-time-sec
[platform/upstream/pulseaudio.git] / src / pulsecore / atomic.h
1 #ifndef foopulseatomichfoo
2 #define foopulseatomichfoo
3
4 /***
5   This file is part of PulseAudio.
6
7   Copyright 2006-2008 Lennart Poettering
8   Copyright 2008 Nokia Corporation
9
10   PulseAudio is free software; you can redistribute it and/or modify
11   it under the terms of the GNU Lesser General Public License as
12   published by the Free Software Foundation; either version 2.1 of the
13   License, or (at your option) any later version.
14
15   PulseAudio is distributed in the hope that it will be useful, but
16   WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18   General Public License for more details.
19
20   You should have received a copy of the GNU Lesser General Public
21   License along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
22 ***/
23
24 #include <pulsecore/macro.h>
25
26 /*
27  * atomic_ops guarantees us that sizeof(AO_t) == sizeof(void*).  It is
28  * not guaranteed however, that sizeof(AO_t) == sizeof(size_t).
29  * however very likely.
30  *
31  * For now we do only full memory barriers. Eventually we might want
32  * to support more elaborate memory barriers, in which case we will add
33  * suffixes to the function names.
34  *
35  * On gcc >= 4.1 we use the builtin atomic functions. otherwise we use
36  * libatomic_ops
37  */
38
39 #ifndef PACKAGE
40 #error "Please include config.h before including this file!"
41 #endif
42
43 #ifdef HAVE_ATOMIC_BUILTINS
44
45 /* __sync based implementation */
46
47 typedef struct pa_atomic {
48     volatile int value;
49 } pa_atomic_t;
50
51 #define PA_ATOMIC_INIT(v) { .value = (v) }
52
53 #ifdef HAVE_ATOMIC_BUILTINS_MEMORY_MODEL
54
55 /* __atomic based implementation */
56
57 static inline int pa_atomic_load(const pa_atomic_t *a) {
58     return __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
59 }
60
61 static inline void pa_atomic_store(pa_atomic_t *a, int i) {
62     __atomic_store_n(&a->value, i, __ATOMIC_SEQ_CST);
63 }
64
65 #else
66
67 static inline int pa_atomic_load(const pa_atomic_t *a) {
68     __sync_synchronize();
69     return a->value;
70 }
71
72 static inline void pa_atomic_store(pa_atomic_t *a, int i) {
73     a->value = i;
74     __sync_synchronize();
75 }
76
77 #endif
78
79
80 /* Returns the previously set value */
81 static inline int pa_atomic_add(pa_atomic_t *a, int i) {
82     return __sync_fetch_and_add(&a->value, i);
83 }
84
85 /* Returns the previously set value */
86 static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
87     return __sync_fetch_and_sub(&a->value, i);
88 }
89
90 /* Returns the previously set value */
91 static inline int pa_atomic_inc(pa_atomic_t *a) {
92     return pa_atomic_add(a, 1);
93 }
94
95 /* Returns the previously set value */
96 static inline int pa_atomic_dec(pa_atomic_t *a) {
97     return pa_atomic_sub(a, 1);
98 }
99
100 /* Returns true when the operation was successful. */
101 static inline bool pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
102     return __sync_bool_compare_and_swap(&a->value, old_i, new_i);
103 }
104
105 typedef struct pa_atomic_ptr {
106     volatile unsigned long value;
107 } pa_atomic_ptr_t;
108
109 #define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) }
110
111 #ifdef HAVE_ATOMIC_BUILTINS_MEMORY_MODEL
112
113 /* __atomic based implementation */
114
115 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
116     return (void*) __atomic_load_n(&a->value, __ATOMIC_SEQ_CST);
117 }
118
119 static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void* p) {
120     __atomic_store_n(&a->value, (unsigned long) p, __ATOMIC_SEQ_CST);
121 }
122
123 #else
124
125 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
126     __sync_synchronize();
127     return (void*) a->value;
128 }
129
130 static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
131     a->value = (unsigned long) p;
132     __sync_synchronize();
133 }
134
135 #endif
136
137 static inline bool pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
138     return __sync_bool_compare_and_swap(&a->value, (long) old_p, (long) new_p);
139 }
140
141 #elif defined(__NetBSD__) && defined(HAVE_SYS_ATOMIC_H)
142
143 /* NetBSD 5.0+ atomic_ops(3) implementation */
144
145 #include <sys/atomic.h>
146
147 typedef struct pa_atomic {
148     volatile unsigned int value;
149 } pa_atomic_t;
150
151 #define PA_ATOMIC_INIT(v) { .value = (unsigned int) (v) }
152
153 static inline int pa_atomic_load(const pa_atomic_t *a) {
154     membar_sync();
155     return (int) a->value;
156 }
157
158 static inline void pa_atomic_store(pa_atomic_t *a, int i) {
159     a->value = (unsigned int) i;
160     membar_sync();
161 }
162
163 /* Returns the previously set value */
164 static inline int pa_atomic_add(pa_atomic_t *a, int i) {
165     int nv = (int) atomic_add_int_nv(&a->value, i);
166     return nv - i;
167 }
168
169 /* Returns the previously set value */
170 static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
171     int nv = (int) atomic_add_int_nv(&a->value, -i);
172     return nv + i;
173 }
174
175 /* Returns the previously set value */
176 static inline int pa_atomic_inc(pa_atomic_t *a) {
177     int nv = (int) atomic_inc_uint_nv(&a->value);
178     return nv - 1;
179 }
180
181 /* Returns the previously set value */
182 static inline int pa_atomic_dec(pa_atomic_t *a) {
183     int nv = (int) atomic_dec_uint_nv(&a->value);
184     return nv + 1;
185 }
186
187 /* Returns true when the operation was successful. */
188 static inline bool pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
189     unsigned int r = atomic_cas_uint(&a->value, (unsigned int) old_i, (unsigned int) new_i);
190     return (int) r == old_i;
191 }
192
193 typedef struct pa_atomic_ptr {
194     volatile void *value;
195 } pa_atomic_ptr_t;
196
197 #define PA_ATOMIC_PTR_INIT(v) { .value = (v) }
198
199 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
200     membar_sync();
201     return (void *) a->value;
202 }
203
204 static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
205     a->value = p;
206     membar_sync();
207 }
208
209 static inline bool pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
210     void *r = atomic_cas_ptr(&a->value, old_p, new_p);
211     return r == old_p;
212 }
213
214 #elif defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
215
216 #include <sys/cdefs.h>
217 #include <sys/types.h>
218 #include <sys/param.h>
219 #include <machine/atomic.h>
220
221 typedef struct pa_atomic {
222     volatile unsigned long value;
223 } pa_atomic_t;
224
225 #define PA_ATOMIC_INIT(v) { .value = (v) }
226
227 static inline int pa_atomic_load(const pa_atomic_t *a) {
228     return (int) atomic_load_acq_int((unsigned int *) &a->value);
229 }
230
231 static inline void pa_atomic_store(pa_atomic_t *a, int i) {
232     atomic_store_rel_int((unsigned int *) &a->value, i);
233 }
234
235 static inline int pa_atomic_add(pa_atomic_t *a, int i) {
236     return atomic_fetchadd_int((unsigned int *) &a->value, i);
237 }
238
239 static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
240     return atomic_fetchadd_int((unsigned int *) &a->value, -(i));
241 }
242
243 static inline int pa_atomic_inc(pa_atomic_t *a) {
244     return atomic_fetchadd_int((unsigned int *) &a->value, 1);
245 }
246
247 static inline int pa_atomic_dec(pa_atomic_t *a) {
248     return atomic_fetchadd_int((unsigned int *) &a->value, -1);
249 }
250
251 static inline int pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
252     return atomic_cmpset_int((unsigned int *) &a->value, old_i, new_i);
253 }
254
255 typedef struct pa_atomic_ptr {
256     volatile unsigned long value;
257 } pa_atomic_ptr_t;
258
259 #define PA_ATOMIC_PTR_INIT(v) { .value = (unsigned long) (v) }
260
261 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
262 #ifdef atomic_load_acq_64
263     return (void*) atomic_load_acq_ptr((unsigned long *) &a->value);
264 #else
265     return (void*) atomic_load_acq_ptr((unsigned int *) &a->value);
266 #endif
267 }
268
269 static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
270 #ifdef atomic_load_acq_64
271     atomic_store_rel_ptr(&a->value, (unsigned long) p);
272 #else
273     atomic_store_rel_ptr((unsigned int *) &a->value, (unsigned int) p);
274 #endif
275 }
276
277 static inline int pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
278 #ifdef atomic_load_acq_64
279     return atomic_cmpset_ptr(&a->value, (unsigned long) old_p, (unsigned long) new_p);
280 #else
281     return atomic_cmpset_ptr((unsigned int *) &a->value, (unsigned int) old_p, (unsigned int) new_p);
282 #endif
283 }
284
285 #elif defined(__GNUC__) && (defined(__amd64__) || defined(__x86_64__))
286
287 #warn "The native atomic operations implementation for AMD64 has not been tested thoroughly. libatomic_ops is known to not work properly on AMD64 and your gcc version is too old for the gcc-builtin atomic ops support. You have three options now: test the native atomic operations implementation for AMD64, fix libatomic_ops, or upgrade your GCC."
288
289 /* Adapted from glibc */
290
291 typedef struct pa_atomic {
292     volatile int value;
293 } pa_atomic_t;
294
295 #define PA_ATOMIC_INIT(v) { .value = (v) }
296
297 static inline int pa_atomic_load(const pa_atomic_t *a) {
298     return a->value;
299 }
300
301 static inline void pa_atomic_store(pa_atomic_t *a, int i) {
302     a->value = i;
303 }
304
305 static inline int pa_atomic_add(pa_atomic_t *a, int i) {
306     int result;
307
308     __asm __volatile ("lock; xaddl %0, %1"
309                       : "=r" (result), "=m" (a->value)
310                       : "0" (i), "m" (a->value));
311
312     return result;
313 }
314
315 static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
316     return pa_atomic_add(a, -i);
317 }
318
319 static inline int pa_atomic_inc(pa_atomic_t *a) {
320     return pa_atomic_add(a, 1);
321 }
322
323 static inline int pa_atomic_dec(pa_atomic_t *a) {
324     return pa_atomic_sub(a, 1);
325 }
326
327 static inline bool pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
328     int result;
329
330     __asm__ __volatile__ ("lock; cmpxchgl %2, %1"
331                           : "=a" (result), "=m" (a->value)
332                           : "r" (new_i), "m" (a->value), "0" (old_i));
333
334     return result == old_i;
335 }
336
337 typedef struct pa_atomic_ptr {
338     volatile unsigned long value;
339 } pa_atomic_ptr_t;
340
341 #define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) }
342
343 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
344     return (void*) a->value;
345 }
346
347 static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
348     a->value = (unsigned long) p;
349 }
350
351 static inline bool pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
352     void *result;
353
354     __asm__ __volatile__ ("lock; cmpxchgq %q2, %1"
355                           : "=a" (result), "=m" (a->value)
356                           : "r" (new_p), "m" (a->value), "0" (old_p));
357
358     return result == old_p;
359 }
360
361 #elif defined(ATOMIC_ARM_INLINE_ASM)
362
363 /*
364    These should only be enabled if we have ARMv6 or better.
365 */
366
367 typedef struct pa_atomic {
368     volatile int value;
369 } pa_atomic_t;
370
371 #define PA_ATOMIC_INIT(v) { .value = (v) }
372
373 static inline void pa_memory_barrier(void) {
374 #ifdef ATOMIC_ARM_MEMORY_BARRIER_ENABLED
375     asm volatile ("mcr  p15, 0, r0, c7, c10, 5  @ dmb");
376 #endif
377 }
378
379 static inline int pa_atomic_load(const pa_atomic_t *a) {
380     pa_memory_barrier();
381     return a->value;
382 }
383
384 static inline void pa_atomic_store(pa_atomic_t *a, int i) {
385     a->value = i;
386     pa_memory_barrier();
387 }
388
389 /* Returns the previously set value */
390 static inline int pa_atomic_add(pa_atomic_t *a, int i) {
391     unsigned long not_exclusive;
392     int new_val, old_val;
393
394     pa_memory_barrier();
395     do {
396         asm volatile ("ldrex    %0, [%3]\n"
397                       "add      %2, %0, %4\n"
398                       "strex    %1, %2, [%3]\n"
399                       : "=&r" (old_val), "=&r" (not_exclusive), "=&r" (new_val)
400                       : "r" (&a->value), "Ir" (i)
401                       : "cc");
402     } while(not_exclusive);
403     pa_memory_barrier();
404
405     return old_val;
406 }
407
408 /* Returns the previously set value */
409 static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
410     unsigned long not_exclusive;
411     int new_val, old_val;
412
413     pa_memory_barrier();
414     do {
415         asm volatile ("ldrex    %0, [%3]\n"
416                       "sub      %2, %0, %4\n"
417                       "strex    %1, %2, [%3]\n"
418                       : "=&r" (old_val), "=&r" (not_exclusive), "=&r" (new_val)
419                       : "r" (&a->value), "Ir" (i)
420                       : "cc");
421     } while(not_exclusive);
422     pa_memory_barrier();
423
424     return old_val;
425 }
426
427 static inline int pa_atomic_inc(pa_atomic_t *a) {
428     return pa_atomic_add(a, 1);
429 }
430
431 static inline int pa_atomic_dec(pa_atomic_t *a) {
432     return pa_atomic_sub(a, 1);
433 }
434
435 static inline bool pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
436     unsigned long not_equal, not_exclusive;
437
438     pa_memory_barrier();
439     do {
440         asm volatile ("ldrex    %0, [%2]\n"
441                       "subs     %0, %0, %3\n"
442                       "mov      %1, %0\n"
443                       "strexeq %0, %4, [%2]\n"
444                       : "=&r" (not_exclusive), "=&r" (not_equal)
445                       : "r" (&a->value), "Ir" (old_i), "r" (new_i)
446                       : "cc");
447     } while(not_exclusive && !not_equal);
448     pa_memory_barrier();
449
450     return !not_equal;
451 }
452
453 typedef struct pa_atomic_ptr {
454     volatile unsigned long value;
455 } pa_atomic_ptr_t;
456
457 #define PA_ATOMIC_PTR_INIT(v) { .value = (long) (v) }
458
459 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
460     pa_memory_barrier();
461     return (void*) a->value;
462 }
463
464 static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
465     a->value = (unsigned long) p;
466     pa_memory_barrier();
467 }
468
469 static inline bool pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
470     unsigned long not_equal, not_exclusive;
471
472     pa_memory_barrier();
473     do {
474         asm volatile ("ldrex    %0, [%2]\n"
475                       "subs     %0, %0, %3\n"
476                       "mov      %1, %0\n"
477                       "strexeq %0, %4, [%2]\n"
478                       : "=&r" (not_exclusive), "=&r" (not_equal)
479                       : "r" (&a->value), "Ir" (old_p), "r" (new_p)
480                       : "cc");
481     } while(not_exclusive && !not_equal);
482     pa_memory_barrier();
483
484     return !not_equal;
485 }
486
487 #elif defined(ATOMIC_ARM_LINUX_HELPERS)
488
489 /* See file arch/arm/kernel/entry-armv.S in your kernel sources for more
490    information about these functions. The arm kernel helper functions first
491    appeared in 2.6.16.
492    Apply --disable-atomic-arm-linux-helpers flag to configure if you prefer
493    inline asm implementation or you have an obsolete Linux kernel.
494 */
495 /* Memory barrier */
496 typedef void (__kernel_dmb_t)(void);
497 #define __kernel_dmb (*(__kernel_dmb_t *)0xffff0fa0)
498
499 static inline void pa_memory_barrier(void) {
500 #ifndef ATOMIC_ARM_MEMORY_BARRIER_ENABLED
501     __kernel_dmb();
502 #endif
503 }
504
505 /* Atomic exchange (__kernel_cmpxchg_t contains memory barriers if needed) */
506 typedef int (__kernel_cmpxchg_t)(int oldval, int newval, volatile int *ptr);
507 #define __kernel_cmpxchg (*(__kernel_cmpxchg_t *)0xffff0fc0)
508
509 /* This is just to get rid of all warnings */
510 typedef int (__kernel_cmpxchg_u_t)(unsigned long oldval, unsigned long newval, volatile unsigned long *ptr);
511 #define __kernel_cmpxchg_u (*(__kernel_cmpxchg_u_t *)0xffff0fc0)
512
513 typedef struct pa_atomic {
514     volatile int value;
515 } pa_atomic_t;
516
517 #define PA_ATOMIC_INIT(v) { .value = (v) }
518
519 static inline int pa_atomic_load(const pa_atomic_t *a) {
520     pa_memory_barrier();
521     return a->value;
522 }
523
524 static inline void pa_atomic_store(pa_atomic_t *a, int i) {
525     a->value = i;
526     pa_memory_barrier();
527 }
528
529 /* Returns the previously set value */
530 static inline int pa_atomic_add(pa_atomic_t *a, int i) {
531     int old_val;
532     do {
533         old_val = a->value;
534     } while(__kernel_cmpxchg(old_val, old_val + i, &a->value));
535     return old_val;
536 }
537
538 /* Returns the previously set value */
539 static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
540     int old_val;
541     do {
542         old_val = a->value;
543     } while(__kernel_cmpxchg(old_val, old_val - i, &a->value));
544     return old_val;
545 }
546
547 /* Returns the previously set value */
548 static inline int pa_atomic_inc(pa_atomic_t *a) {
549     return pa_atomic_add(a, 1);
550 }
551
552 /* Returns the previously set value */
553 static inline int pa_atomic_dec(pa_atomic_t *a) {
554     return pa_atomic_sub(a, 1);
555 }
556
557 /* Returns true when the operation was successful. */
558 static inline bool pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
559     bool failed;
560     do {
561       failed = !!__kernel_cmpxchg(old_i, new_i, &a->value);
562     } while(failed && a->value == old_i);
563     return !failed;
564 }
565
566 typedef struct pa_atomic_ptr {
567     volatile unsigned long value;
568 } pa_atomic_ptr_t;
569
570 #define PA_ATOMIC_PTR_INIT(v) { .value = (unsigned long) (v) }
571
572 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
573     pa_memory_barrier();
574     return (void*) a->value;
575 }
576
577 static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
578     a->value = (unsigned long) p;
579     pa_memory_barrier();
580 }
581
582 static inline bool pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
583     bool failed;
584     do {
585         failed = !!__kernel_cmpxchg_u((unsigned long) old_p, (unsigned long) new_p, &a->value);
586     } while(failed && a->value == (unsigned long) old_p);
587     return !failed;
588 }
589
590 #else
591
592 /* libatomic_ops based implementation */
593
594 #include <atomic_ops.h>
595
596 typedef struct pa_atomic {
597     volatile AO_t value;
598 } pa_atomic_t;
599
600 #define PA_ATOMIC_INIT(v) { .value = (AO_t) (v) }
601
602 static inline int pa_atomic_load(const pa_atomic_t *a) {
603     return (int) AO_load_full((AO_t*) &a->value);
604 }
605
606 static inline void pa_atomic_store(pa_atomic_t *a, int i) {
607     AO_store_full(&a->value, (AO_t) i);
608 }
609
610 static inline int pa_atomic_add(pa_atomic_t *a, int i) {
611     return (int) AO_fetch_and_add_full(&a->value, (AO_t) i);
612 }
613
614 static inline int pa_atomic_sub(pa_atomic_t *a, int i) {
615     return (int) AO_fetch_and_add_full(&a->value, (AO_t) -i);
616 }
617
618 static inline int pa_atomic_inc(pa_atomic_t *a) {
619     return (int) AO_fetch_and_add1_full(&a->value);
620 }
621
622 static inline int pa_atomic_dec(pa_atomic_t *a) {
623     return (int) AO_fetch_and_sub1_full(&a->value);
624 }
625
626 static inline bool pa_atomic_cmpxchg(pa_atomic_t *a, int old_i, int new_i) {
627     return AO_compare_and_swap_full(&a->value, (unsigned long) old_i, (unsigned long) new_i);
628 }
629
630 typedef struct pa_atomic_ptr {
631     volatile AO_t value;
632 } pa_atomic_ptr_t;
633
634 #define PA_ATOMIC_PTR_INIT(v) { .value = (AO_t) (v) }
635
636 static inline void* pa_atomic_ptr_load(const pa_atomic_ptr_t *a) {
637     return (void*) AO_load_full((AO_t*) &a->value);
638 }
639
640 static inline void pa_atomic_ptr_store(pa_atomic_ptr_t *a, void *p) {
641     AO_store_full(&a->value, (AO_t) p);
642 }
643
644 static inline bool pa_atomic_ptr_cmpxchg(pa_atomic_ptr_t *a, void *old_p, void* new_p) {
645     return AO_compare_and_swap_full(&a->value, (AO_t) old_p, (AO_t) new_p);
646 }
647
648 #endif
649
650 #endif