new stacktrace function in libpbd3; variable size GUI request thread queues
[ardour.git] / libs / pbd3 / pbd / atomic.h
1 /*
2     Copyright (C) 2001 Paul Davis and others (see below)
3     Code derived from various headers from the Linux kernel.
4        Copyright attributions maintained where present.
5     
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19
20     $Id$
21 */
22
23 #ifndef __libpbd_atomic_h__
24 #define __libpbd_atomic_h__
25
26 #ifdef HAVE_SMP      /* a macro we control, to manage ... */
27 #define CONFIG_SMP   /* ... the macro the kernel headers use */
28 #endif
29
30 #if defined(__powerpc__) || defined(__ppc__)
31
32 /*
33  * BK Id: SCCS/s.atomic.h 1.15 10/28/01 10:37:22 trini
34  */
35 /*
36  * PowerPC atomic operations
37  */
38
39 #ifndef _ASM_PPC_ATOMIC_H_ 
40 #define _ASM_PPC_ATOMIC_H_
41
42 typedef struct { volatile int counter; } atomic_t;
43
44
45 #define ATOMIC_INIT(i)  { (i) }
46
47 #define atomic_read(v)          ((v)->counter)
48 #define atomic_set(v,i)         (((v)->counter) = (i))
49
50 extern void atomic_clear_mask(unsigned long mask, unsigned long *addr);
51 extern void atomic_set_mask(unsigned long mask, unsigned long *addr);
52
53 #ifdef CONFIG_SMP
54 #define SMP_ISYNC       "\n\tisync"
55 #else
56 #define SMP_ISYNC
57 #endif
58
59 static __inline__ void atomic_add(int a, atomic_t *v)
60 {
61         int t;
62
63         __asm__ __volatile__(
64 "1:     lwarx   %0,0,%3\n\
65         add     %0,%2,%0\n\
66         stwcx.  %0,0,%3\n\
67         bne-    1b"
68         : "=&r" (t), "=m" (v->counter)
69         : "r" (a), "r" (&v->counter), "m" (v->counter)
70         : "cc");
71 }
72
73 static __inline__ int atomic_add_return(int a, atomic_t *v)
74 {
75         int t;
76
77         __asm__ __volatile__(
78 "1:     lwarx   %0,0,%2\n\
79         add     %0,%1,%0\n\
80         stwcx.  %0,0,%2\n\
81         bne-    1b"
82         SMP_ISYNC
83         : "=&r" (t)
84         : "r" (a), "r" (&v->counter)
85         : "cc", "memory");
86
87         return t;
88 }
89
90 static __inline__ void atomic_sub(int a, atomic_t *v)
91 {
92         int t;
93
94         __asm__ __volatile__(
95 "1:     lwarx   %0,0,%3\n\
96         subf    %0,%2,%0\n\
97         stwcx.  %0,0,%3\n\
98         bne-    1b"
99         : "=&r" (t), "=m" (v->counter)
100         : "r" (a), "r" (&v->counter), "m" (v->counter)
101         : "cc");
102 }
103
104 static __inline__ int atomic_sub_return(int a, atomic_t *v)
105 {
106         int t;
107
108         __asm__ __volatile__(
109 "1:     lwarx   %0,0,%2\n\
110         subf    %0,%1,%0\n\
111         stwcx.  %0,0,%2\n\
112         bne-    1b"
113         SMP_ISYNC
114         : "=&r" (t)
115         : "r" (a), "r" (&v->counter)
116         : "cc", "memory");
117
118         return t;
119 }
120
121 static __inline__ void atomic_inc(atomic_t *v)
122 {
123         int t;
124
125         __asm__ __volatile__(
126 "1:     lwarx   %0,0,%2\n\
127         addic   %0,%0,1\n\
128         stwcx.  %0,0,%2\n\
129         bne-    1b"
130         : "=&r" (t), "=m" (v->counter)
131         : "r" (&v->counter), "m" (v->counter)
132         : "cc");
133 }
134
135 static __inline__ int atomic_inc_return(atomic_t *v)
136 {
137         int t;
138
139         __asm__ __volatile__(
140 "1:     lwarx   %0,0,%1\n\
141         addic   %0,%0,1\n\
142         stwcx.  %0,0,%1\n\
143         bne-    1b"
144         SMP_ISYNC
145         : "=&r" (t)
146         : "r" (&v->counter)
147         : "cc", "memory");
148
149         return t;
150 }
151
152 static __inline__ void atomic_dec(atomic_t *v)
153 {
154         int t;
155
156         __asm__ __volatile__(
157 "1:     lwarx   %0,0,%2\n\
158         addic   %0,%0,-1\n\
159         stwcx.  %0,0,%2\n\
160         bne-    1b"
161         : "=&r" (t), "=m" (v->counter)
162         : "r" (&v->counter), "m" (v->counter)
163         : "cc");
164 }
165
166 static __inline__ int atomic_dec_return(atomic_t *v)
167 {
168         int t;
169
170         __asm__ __volatile__(
171 "1:     lwarx   %0,0,%1\n\
172         addic   %0,%0,-1\n\
173         stwcx.  %0,0,%1\n\
174         bne-    1b"
175         SMP_ISYNC
176         : "=&r" (t)
177         : "r" (&v->counter)
178         : "cc", "memory");
179
180         return t;
181 }
182
183 #define atomic_sub_and_test(a, v)       (atomic_sub_return((a), (v)) == 0)
184 #define atomic_dec_and_test(v)          (atomic_dec_return((v)) == 0)
185
186 /*
187  * Atomically test *v and decrement if it is greater than 0.
188  * The function returns the old value of *v minus 1.
189  */
190 static __inline__ int atomic_dec_if_positive(atomic_t *v)
191 {
192         int t;
193
194         __asm__ __volatile__(
195 "1:     lwarx   %0,0,%1\n\
196         addic.  %0,%0,-1\n\
197         blt-    2f\n\
198         stwcx.  %0,0,%1\n\
199         bne-    1b"
200         SMP_ISYNC
201         "\n\
202 2:"     : "=&r" (t)
203         : "r" (&v->counter)
204         : "cc", "memory");
205
206         return t;
207 }
208
209 #define smp_mb__before_atomic_dec()     smp_mb()
210 #define smp_mb__after_atomic_dec()      smp_mb()
211 #define smp_mb__before_atomic_inc()     smp_mb()
212 #define smp_mb__after_atomic_inc()      smp_mb()
213
214 #endif /* _ASM_PPC_ATOMIC_H_ */
215
216 /***********************************************************************/
217
218 #  else  /* !PPC */
219
220 #if defined(__i386__) || defined(__x86_64__)
221
222 #ifndef __ARCH_I386_ATOMIC__
223 #define __ARCH_I386_ATOMIC__
224
225 /*
226  * Atomic operations that C can't guarantee us.  Useful for
227  * resource counting etc..
228  */
229
230 #ifdef CONFIG_SMP
231 #define SMP_LOCK "lock ; "
232 #else
233 #define SMP_LOCK ""
234 #endif
235
236 /*
237  * Make sure gcc doesn't try to be clever and move things around
238  * on us. We need to use _exactly_ the address the user gave us,
239  * not some alias that contains the same information.
240  */
241 typedef struct { volatile int counter; } atomic_t;
242
243 #define ATOMIC_INIT(i)  { (i) }
244
245 /**
246  * atomic_read - read atomic variable
247  * @v: pointer of type atomic_t
248  * 
249  * Atomically reads the value of @v.  Note that the guaranteed
250  * useful range of an atomic_t is only 24 bits.
251  */ 
252 #define atomic_read(v)          ((v)->counter)
253
254 /**
255  * atomic_set - set atomic variable
256  * @v: pointer of type atomic_t
257  * @i: required value
258  * 
259  * Atomically sets the value of @v to @i.  Note that the guaranteed
260  * useful range of an atomic_t is only 24 bits.
261  */ 
262 #define atomic_set(v,i)         (((v)->counter) = (i))
263
264 /**
265  * atomic_add - add integer to atomic variable
266  * @i: integer value to add
267  * @v: pointer of type atomic_t
268  * 
269  * Atomically adds @i to @v.  Note that the guaranteed useful range
270  * of an atomic_t is only 24 bits.
271  */
272 static __inline__ void atomic_add(int i, atomic_t *v)
273 {
274         __asm__ __volatile__(
275                 SMP_LOCK "addl %1,%0"
276                 :"=m" (v->counter)
277                 :"ir" (i), "m" (v->counter));
278 }
279
280 /**
281  * atomic_sub - subtract the atomic variable
282  * @i: integer value to subtract
283  * @v: pointer of type atomic_t
284  * 
285  * Atomically subtracts @i from @v.  Note that the guaranteed
286  * useful range of an atomic_t is only 24 bits.
287  */
288 static __inline__ void atomic_sub(int i, atomic_t *v)
289 {
290         __asm__ __volatile__(
291                 SMP_LOCK "subl %1,%0"
292                 :"=m" (v->counter)
293                 :"ir" (i), "m" (v->counter));
294 }
295
296 /**
297  * atomic_sub_and_test - subtract value from variable and test result
298  * @i: integer value to subtract
299  * @v: pointer of type atomic_t
300  * 
301  * Atomically subtracts @i from @v and returns
302  * true if the result is zero, or false for all
303  * other cases.  Note that the guaranteed
304  * useful range of an atomic_t is only 24 bits.
305  */
306 static __inline__ int atomic_sub_and_test(int i, atomic_t *v)
307 {
308         unsigned char c;
309
310         __asm__ __volatile__(
311                 SMP_LOCK "subl %2,%0; sete %1"
312                 :"=m" (v->counter), "=qm" (c)
313                 :"ir" (i), "m" (v->counter) : "memory");
314         return c;
315 }
316
317 /**
318  * atomic_inc - increment atomic variable
319  * @v: pointer of type atomic_t
320  * 
321  * Atomically increments @v by 1.  Note that the guaranteed
322  * useful range of an atomic_t is only 24 bits.
323  */ 
324 static __inline__ void atomic_inc(atomic_t *v)
325 {
326         __asm__ __volatile__(
327                 SMP_LOCK "incl %0"
328                 :"=m" (v->counter)
329                 :"m" (v->counter));
330 }
331
332 /**
333  * atomic_dec - decrement atomic variable
334  * @v: pointer of type atomic_t
335  * 
336  * Atomically decrements @v by 1.  Note that the guaranteed
337  * useful range of an atomic_t is only 24 bits.
338  */ 
339 static __inline__ void atomic_dec(atomic_t *v)
340 {
341         __asm__ __volatile__(
342                 SMP_LOCK "decl %0"
343                 :"=m" (v->counter)
344                 :"m" (v->counter));
345 }
346
347 /**
348  * atomic_dec_and_test - decrement and test
349  * @v: pointer of type atomic_t
350  * 
351  * Atomically decrements @v by 1 and
352  * returns true if the result is 0, or false for all other
353  * cases.  Note that the guaranteed
354  * useful range of an atomic_t is only 24 bits.
355  */ 
356 static __inline__ int atomic_dec_and_test(atomic_t *v)
357 {
358         unsigned char c;
359
360         __asm__ __volatile__(
361                 SMP_LOCK "decl %0; sete %1"
362                 :"=m" (v->counter), "=qm" (c)
363                 :"m" (v->counter) : "memory");
364         return c != 0;
365 }
366
367 /**
368  * atomic_inc_and_test - increment and test 
369  * @v: pointer of type atomic_t
370  * 
371  * Atomically increments @v by 1
372  * and returns true if the result is zero, or false for all
373  * other cases.  Note that the guaranteed
374  * useful range of an atomic_t is only 24 bits.
375  */ 
376 static __inline__ int atomic_inc_and_test(atomic_t *v)
377 {
378         unsigned char c;
379
380         __asm__ __volatile__(
381                 SMP_LOCK "incl %0; sete %1"
382                 :"=m" (v->counter), "=qm" (c)
383                 :"m" (v->counter) : "memory");
384         return c != 0;
385 }
386
387 /**
388  * atomic_add_negative - add and test if negative
389  * @v: pointer of type atomic_t
390  * @i: integer value to add
391  * 
392  * Atomically adds @i to @v and returns true
393  * if the result is negative, or false when
394  * result is greater than or equal to zero.  Note that the guaranteed
395  * useful range of an atomic_t is only 24 bits.
396  */ 
397 static __inline__ int atomic_add_negative(int i, atomic_t *v)
398 {
399         unsigned char c;
400
401         __asm__ __volatile__(
402                 SMP_LOCK "addl %2,%0; sets %1"
403                 :"=m" (v->counter), "=qm" (c)
404                 :"ir" (i), "m" (v->counter) : "memory");
405         return c;
406 }
407
408 /* These are x86-specific, used by some header files */
409 #define atomic_clear_mask(mask, addr) \
410 __asm__ __volatile__(SMP_LOCK "andl %0,%1" \
411 : : "r" (~(mask)),"m" (*addr) : "memory")
412
413 #define atomic_set_mask(mask, addr) \
414 __asm__ __volatile__(SMP_LOCK "orl %0,%1" \
415 : : "r" (mask),"m" (*addr) : "memory")
416
417 /* Atomic operations are already serializing on x86 */
418 #define smp_mb__before_atomic_dec()     barrier()
419 #define smp_mb__after_atomic_dec()      barrier()
420 #define smp_mb__before_atomic_inc()     barrier()
421 #define smp_mb__after_atomic_inc()      barrier()
422
423 #endif /* __ARCH_I386_ATOMIC__ */
424
425 /***********************************************************************/
426
427 #else /* !PPC && !i386 */
428
429 #ifdef __sparc__
430
431 /* atomic.h: These still suck, but the I-cache hit rate is higher.
432  *
433  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
434  * Copyright (C) 2000 Anton Blanchard (anton@linuxcare.com.au)
435  */
436
437 #ifndef __ARCH_SPARC_ATOMIC__
438 #define __ARCH_SPARC_ATOMIC__
439
440 typedef struct { volatile int counter; } atomic_t;
441
442 #ifndef CONFIG_SMP
443
444 #define ATOMIC_INIT(i)  { (i) }
445 #define atomic_read(v)          ((v)->counter)
446 #define atomic_set(v, i)        (((v)->counter) = i)
447
448 #else
449 /* We do the bulk of the actual work out of line in two common
450  * routines in assembler, see arch/sparc/lib/atomic.S for the
451  * "fun" details.
452  *
453  * For SMP the trick is you embed the spin lock byte within
454  * the word, use the low byte so signedness is easily retained
455  * via a quick arithmetic shift.  It looks like this:
456  *
457  *      ----------------------------------------
458  *      | signed 24-bit counter value |  lock  |  atomic_t
459  *      ----------------------------------------
460  *       31                          8 7      0
461  */
462
463 #define ATOMIC_INIT(i)  { (i << 8) }
464
465 static __inline__ int atomic_read(atomic_t *v)
466 {
467         int ret = v->counter;
468
469         while(ret & 0xff)
470                 ret = v->counter;
471
472         return ret >> 8;
473 }
474
475 #define atomic_set(v, i)        (((v)->counter) = ((i) << 8))
476 #endif
477
478 static __inline__ int __atomic_add(int i, atomic_t *v)
479 {
480         register volatile int *ptr asm("g1");
481         register int increment asm("g2");
482
483         ptr = &v->counter;
484         increment = i;
485
486         __asm__ __volatile__(
487         "mov    %%o7, %%g4\n\t"
488         "call   ___atomic_add\n\t"
489         " add   %%o7, 8, %%o7\n"
490         : "=&r" (increment)
491         : "0" (increment), "r" (ptr)
492         : "g3", "g4", "g7", "memory", "cc");
493
494         return increment;
495 }
496
497 static __inline__ int __atomic_sub(int i, atomic_t *v)
498 {
499         register volatile int *ptr asm("g1");
500         register int increment asm("g2");
501
502         ptr = &v->counter;
503         increment = i;
504
505         __asm__ __volatile__(
506         "mov    %%o7, %%g4\n\t"
507         "call   ___atomic_sub\n\t"
508         " add   %%o7, 8, %%o7\n"
509         : "=&r" (increment)
510         : "0" (increment), "r" (ptr)
511         : "g3", "g4", "g7", "memory", "cc");
512
513         return increment;
514 }
515
516 #define atomic_add(i, v) ((void)__atomic_add((i), (v)))
517 #define atomic_sub(i, v) ((void)__atomic_sub((i), (v)))
518
519 #define atomic_dec_return(v) __atomic_sub(1, (v))
520 #define atomic_inc_return(v) __atomic_add(1, (v))
521
522 #define atomic_sub_and_test(i, v) (__atomic_sub((i), (v)) == 0)
523 #define atomic_dec_and_test(v) (__atomic_sub(1, (v)) == 0)
524
525 #define atomic_inc(v) ((void)__atomic_add(1, (v)))
526 #define atomic_dec(v) ((void)__atomic_sub(1, (v)))
527
528 #define atomic_add_negative(i, v) (__atomic_add((i), (v)) < 0)
529
530 /* Atomic operations are already serializing */
531 #define smp_mb__before_atomic_dec()     barrier()
532 #define smp_mb__after_atomic_dec()      barrier()
533 #define smp_mb__before_atomic_inc()     barrier()
534 #define smp_mb__after_atomic_inc()      barrier()
535
536
537 #endif /* !(__ARCH_SPARC_ATOMIC__) */
538
539 /***********************************************************************/
540
541 #else
542
543 #ifdef __ia64__
544
545 #ifndef __ARCH_IA64_ATOMIC__
546 #define __ARCH_IA64_ATOMIC__
547
548 typedef volatile int atomic_t;
549
550 inline
551 int
552 atomic_read (const atomic_t * a)
553 {
554         return *a;
555 }
556
557 inline
558 void
559 atomic_set(atomic_t *a, int v)
560 {
561         *a = v;
562 }
563
564 inline
565 void
566 atomic_inc (atomic_t *v)
567 {
568         int old, r;
569
570         do {
571                 old = atomic_read(v);
572                 __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO" (old));
573                 __asm__ __volatile__ ("cmpxchg4.acq %0=[%1],%2,ar.ccv"
574                                       : "=r"(r) : "r"(v), "r"(old + 1)
575                                       : "memory");
576         } while (r != old);
577 }
578
579 inline
580 void
581 atomic_dec (atomic_t *v)
582 {
583         int old, r;
584
585         do {
586                 old = atomic_read(v);
587                 __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO" (old));
588                 __asm__ __volatile__ ("cmpxchg4.acq %0=[%1],%2,ar.ccv"
589                                       : "=r"(r) : "r"(v), "r"(old - 1)
590                                       : "memory");
591         } while (r != old);
592 }
593
594 inline
595 int
596 atomic_dec_and_test (atomic_t *v)
597 {
598         int old, r;
599
600         do {
601                 old = atomic_read(v);
602                 __asm__ __volatile__ ("mov ar.ccv=%0;;" :: "rO" (old));
603                 __asm__ __volatile__ ("cmpxchg4.acq %0=[%1],%2,ar.ccv"
604                                       : "=r"(r) : "r"(v), "r"(old - 1)
605                                       : "memory");
606         } while (r != old);
607         return old != 1;
608 }
609
610 #endif /* !(__ARCH_IA64_ATOMIC__) */
611
612 #else
613
614 #ifdef __alpha__
615
616 #ifndef _ALPHA_ATOMIC_H
617 #define _ALPHA_ATOMIC_H
618
619 /*
620  * Atomic operations that C can't guarantee us.  Useful for
621  * resource counting etc...
622  *
623  * But use these as seldom as possible since they are much slower
624  * than regular operations.
625  */
626
627
628 /*
629  * Counter is volatile to make sure gcc doesn't try to be clever
630  * and move things around on us. We need to use _exactly_ the address
631  * the user gave us, not some alias that contains the same information.
632  */
633 typedef struct { volatile int counter; } atomic_t;
634
635 #define ATOMIC_INIT(i)  ( (atomic_t) { (i) } )
636
637 #define atomic_read(v)          ((v)->counter)
638 #define atomic_set(v,i)         ((v)->counter = (i))
639
640 /*
641  * To get proper branch prediction for the main line, we must branch
642  * forward to code at the end of this object's .text section, then
643  * branch back to restart the operation.
644  */
645
646 static __inline__ void atomic_add(int i, atomic_t * v)
647 {
648         unsigned long temp;
649         __asm__ __volatile__(
650         "1:     ldl_l %0,%1\n"
651         "       addl %0,%2,%0\n"
652         "       stl_c %0,%1\n"
653         "       beq %0,2f\n"
654         ".subsection 2\n"
655         "2:     br 1b\n"
656         ".previous"
657         :"=&r" (temp), "=m" (v->counter)
658         :"Ir" (i), "m" (v->counter));
659 }
660
661 static __inline__ void atomic_sub(int i, atomic_t * v)
662 {
663         unsigned long temp;
664         __asm__ __volatile__(
665         "1:     ldl_l %0,%1\n"
666         "       subl %0,%2,%0\n"
667         "       stl_c %0,%1\n"
668         "       beq %0,2f\n"
669         ".subsection 2\n"
670         "2:     br 1b\n"
671         ".previous"
672         :"=&r" (temp), "=m" (v->counter)
673         :"Ir" (i), "m" (v->counter));
674 }
675
676 /*
677  * Same as above, but return the result value
678  */
679 static __inline__ long atomic_add_return(int i, atomic_t * v)
680 {
681         long temp, result;
682         __asm__ __volatile__(
683         "1:     ldl_l %0,%1\n"
684         "       addl %0,%3,%2\n"
685         "       addl %0,%3,%0\n"
686         "       stl_c %0,%1\n"
687         "       beq %0,2f\n"
688         "       mb\n"
689         ".subsection 2\n"
690         "2:     br 1b\n"
691         ".previous"
692         :"=&r" (temp), "=m" (v->counter), "=&r" (result)
693         :"Ir" (i), "m" (v->counter) : "memory");
694         return result;
695 }
696
697 static __inline__ long atomic_sub_return(int i, atomic_t * v)
698 {
699         long temp, result;
700         __asm__ __volatile__(
701         "1:     ldl_l %0,%1\n"
702         "       subl %0,%3,%2\n"
703         "       subl %0,%3,%0\n"
704         "       stl_c %0,%1\n"
705         "       beq %0,2f\n"
706         "       mb\n"
707         ".subsection 2\n"
708         "2:     br 1b\n"
709         ".previous"
710         :"=&r" (temp), "=m" (v->counter), "=&r" (result)
711         :"Ir" (i), "m" (v->counter) : "memory");
712         return result;
713 }
714
715 #define atomic_dec_return(v) atomic_sub_return(1,(v))
716 #define atomic_inc_return(v) atomic_add_return(1,(v))
717
718 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
719 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
720
721 #define atomic_inc(v) atomic_add(1,(v))
722 #define atomic_dec(v) atomic_sub(1,(v))
723
724 #define smp_mb__before_atomic_dec()     smp_mb()
725 #define smp_mb__after_atomic_dec()      smp_mb()
726 #define smp_mb__before_atomic_inc()     smp_mb()
727 #define smp_mb__after_atomic_inc()      smp_mb()
728
729 #endif /* _ALPHA_ATOMIC_H */
730
731 #else
732
733 #ifdef __s390__
734
735 #ifndef __ARCH_S390_ATOMIC__
736 #define __ARCH_S390_ATOMIC__
737
738 /*
739  *  include/asm-s390/atomic.h
740  *
741  *  S390 version
742  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
743  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
744  *               Denis Joseph Barrow
745  *
746  *  Derived from "include/asm-i386/bitops.h"
747  *    Copyright (C) 1992, Linus Torvalds
748  *
749  */
750
751 /*
752  * Atomic operations that C can't guarantee us.  Useful for
753  * resource counting etc..
754  * S390 uses 'Compare And Swap' for atomicity in SMP enviroment
755  */
756
757 typedef struct { volatile int counter; } __attribute__ ((aligned (4))) atomic_t;
758 #define ATOMIC_INIT(i)  { (i) }
759
760 #define atomic_eieio()          __asm__ __volatile__ ("BCR 15,0")
761
762 #define __CS_LOOP(old_val, new_val, ptr, op_val, op_string)             \
763         __asm__ __volatile__("   l     %0,0(%2)\n"                      \
764                              "0: lr    %1,%0\n"                         \
765                              op_string "  %1,%3\n"                      \
766                              "   cs    %0,%1,0(%2)\n"                   \
767                              "   jl    0b"                              \
768                              : "=&d" (old_val), "=&d" (new_val)         \
769                              : "a" (ptr), "d" (op_val) : "cc" );
770
771 #define atomic_read(v)          ((v)->counter)
772 #define atomic_set(v,i)         (((v)->counter) = (i))
773
774 static __inline__ void atomic_add(int i, atomic_t *v)
775 {
776         int old_val, new_val;
777         __CS_LOOP(old_val, new_val, v, i, "ar");
778 }
779
780 static __inline__ int atomic_add_return (int i, atomic_t *v)
781 {
782         int old_val, new_val;
783         __CS_LOOP(old_val, new_val, v, i, "ar");
784         return new_val;
785 }
786
787 static __inline__ int atomic_add_negative(int i, atomic_t *v)
788 {
789         int old_val, new_val;
790         __CS_LOOP(old_val, new_val, v, i, "ar");
791         return new_val < 0;
792 }
793
794 static __inline__ void atomic_sub(int i, atomic_t *v)
795 {
796         int old_val, new_val;
797         __CS_LOOP(old_val, new_val, v, i, "sr");
798 }
799
800 static __inline__ void atomic_inc(volatile atomic_t *v)
801 {
802         int old_val, new_val;
803         __CS_LOOP(old_val, new_val, v, 1, "ar");
804 }
805
806 static __inline__ int atomic_inc_return(volatile atomic_t *v)
807 {
808         int old_val, new_val;
809         __CS_LOOP(old_val, new_val, v, 1, "ar");
810         return new_val;
811 }
812
813 static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
814 {
815         int old_val, new_val;
816         __CS_LOOP(old_val, new_val, v, 1, "ar");
817         return new_val != 0;
818 }
819
820 static __inline__ void atomic_dec(volatile atomic_t *v)
821 {
822         int old_val, new_val;
823         __CS_LOOP(old_val, new_val, v, 1, "sr");
824 }
825
826 static __inline__ int atomic_dec_return(volatile atomic_t *v)
827 {
828         int old_val, new_val;
829         __CS_LOOP(old_val, new_val, v, 1, "sr");
830         return new_val;
831 }
832
833 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
834 {
835         int old_val, new_val;
836         __CS_LOOP(old_val, new_val, v, 1, "sr");
837         return new_val == 0;
838 }
839
840 static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
841 {
842         int old_val, new_val;
843         __CS_LOOP(old_val, new_val, v, ~mask, "nr");
844 }
845
846 static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
847 {
848         int old_val, new_val;
849         __CS_LOOP(old_val, new_val, v, mask, "or");
850 }
851
852 /*
853   returns 0  if expected_oldval==value in *v ( swap was successful )
854   returns 1  if unsuccessful.
855 */
856 static __inline__ int
857 atomic_compare_and_swap(int expected_oldval,int new_val,atomic_t *v)
858 {
859         int retval;
860
861         __asm__ __volatile__(
862                 "  lr   0,%2\n"
863                 "  cs   0,%3,0(%1)\n"
864                 "  ipm  %0\n"
865                 "  srl  %0,28\n"
866                 "0:"
867                 : "=&d" (retval)
868                 : "a" (v), "d" (expected_oldval) , "d" (new_val)
869                 : "0", "cc");
870         return retval;
871 }
872
873 /*
874   Spin till *v = expected_oldval then swap with newval.
875  */
876 static __inline__ void
877 atomic_compare_and_swap_spin(int expected_oldval,int new_val,atomic_t *v)
878 {
879         __asm__ __volatile__(
880                 "0: lr  0,%1\n"
881                 "   cs  0,%2,0(%0)\n"
882                 "   jl  0b\n"
883                 : : "a" (v), "d" (expected_oldval) , "d" (new_val)
884                 : "cc", "0" );
885 }
886
887 #define smp_mb__before_atomic_dec()     smp_mb()
888 #define smp_mb__after_atomic_dec()      smp_mb()
889 #define smp_mb__before_atomic_inc()     smp_mb()
890 #define smp_mb__after_atomic_inc()      smp_mb()
891
892 #endif                                 /* __ARCH_S390_ATOMIC __            */
893
894 #else
895
896 #ifdef __mips__
897
898 /*
899  * Atomic operations that C can't guarantee us.  Useful for
900  * resource counting etc..
901  *
902  * But use these as seldom as possible since they are much more slower
903  * than regular operations.
904  *
905  * This file is subject to the terms and conditions of the GNU General Public
906  * License.  See the file "COPYING" in the main directory of this archive
907  * for more details.
908  *
909  * Copyright (C) 1996, 1997, 2000 by Ralf Baechle
910  */
911 #ifndef __ASM_ATOMIC_H
912 #define __ASM_ATOMIC_H
913
914 typedef struct { volatile int counter; } atomic_t;
915
916 #define ATOMIC_INIT(i)    { (i) }
917
918 /*
919  * atomic_read - read atomic variable
920  * @v: pointer of type atomic_t
921  *
922  * Atomically reads the value of @v.  Note that the guaranteed
923  * useful range of an atomic_t is only 24 bits.
924  */
925 #define atomic_read(v)  ((v)->counter)
926
927 /*
928  * atomic_set - set atomic variable
929  * @v: pointer of type atomic_t
930  * @i: required value
931  *
932  * Atomically sets the value of @v to @i.  Note that the guaranteed
933  * useful range of an atomic_t is only 24 bits.
934  */
935 #define atomic_set(v,i) ((v)->counter = (i))
936
937 /*
938  * ... while for MIPS II and better we can use ll/sc instruction.  This
939  * implementation is SMP safe ...
940  */
941
942 /*
943  * atomic_add - add integer to atomic variable
944  * @i: integer value to add
945  * @v: pointer of type atomic_t
946  *
947  * Atomically adds @i to @v.  Note that the guaranteed useful range
948  * of an atomic_t is only 24 bits.
949  */
950 extern __inline__ void atomic_add(int i, atomic_t * v)
951 {
952         unsigned long temp;
953
954         __asm__ __volatile__(
955                 ".set push                # atomic_add\n"
956                 ".set mips2                           \n"
957                 "1:   ll      %0, %1                  \n"
958                 "     addu    %0, %2                  \n"
959                 "     sc      %0, %1                  \n"
960                 "     beqz    %0, 1b                  \n"
961                 ".set pop                             \n"
962                 : "=&r" (temp), "=m" (v->counter)
963                 : "Ir" (i), "m" (v->counter));
964 }
965
966 /*
967  * atomic_sub - subtract the atomic variable
968  * @i: integer value to subtract
969  * @v: pointer of type atomic_t
970  *
971  * Atomically subtracts @i from @v.  Note that the guaranteed
972  * useful range of an atomic_t is only 24 bits.
973  */
974 extern __inline__ void atomic_sub(int i, atomic_t * v)
975 {
976         unsigned long temp;
977
978         __asm__ __volatile__(
979                 ".set push                # atomic_sub\n"
980                 ".set mips2                           \n"
981                 "1:   ll      %0, %1                  \n"
982                 "     subu    %0, %2                  \n"
983                 "     sc      %0, %1                  \n"
984                 "     beqz    %0, 1b                  \n"
985                 ".set pop                             \n"
986                 : "=&r" (temp), "=m" (v->counter)
987                 : "Ir" (i), "m" (v->counter));
988 }
989
990 /*
991  * Same as above, but return the result value
992  */
993 extern __inline__ int atomic_add_return(int i, atomic_t * v)
994 {
995         unsigned long temp, result;
996
997         __asm__ __volatile__(
998                 ".set push               # atomic_add_return\n"
999                 ".set mips2                                 \n"
1000                 ".set noreorder                             \n"
1001                 "1:   ll      %1, %2                        \n"
1002                 "     addu    %0, %1, %3                    \n"
1003                 "     sc      %0, %2                        \n"
1004                 "     beqz    %0, 1b                        \n"
1005                 "     addu    %0, %1, %3                    \n"
1006                 "     sync                                  \n"
1007                 ".set pop                                   \n"
1008                 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
1009                 : "Ir" (i), "m" (v->counter)
1010                 : "memory");
1011
1012         return result;
1013 }
1014
1015 extern __inline__ int atomic_sub_return(int i, atomic_t * v)
1016 {
1017         unsigned long temp, result;
1018
1019         __asm__ __volatile__(
1020                 ".set push                # atomic_sub_return\n"
1021                 ".set mips2                                  \n"
1022                 ".set noreorder                              \n"
1023                 "1:   ll    %1, %2                           \n"
1024                 "     subu  %0, %1, %3                       \n"
1025                 "     sc    %0, %2                           \n"
1026                 "     beqz  %0, 1b                           \n"
1027                 "     subu  %0, %1, %3                       \n"
1028                 "     sync                                   \n"
1029                 ".set pop                                    \n"
1030                 : "=&r" (result), "=&r" (temp), "=m" (v->counter)
1031                 : "Ir" (i), "m" (v->counter)
1032                 : "memory");
1033
1034         return result;
1035 }
1036
1037 #define atomic_dec_return(v) atomic_sub_return(1,(v))
1038 #define atomic_inc_return(v) atomic_add_return(1,(v))
1039
1040 /*
1041  * atomic_sub_and_test - subtract value from variable and test result
1042  * @i: integer value to subtract
1043  * @v: pointer of type atomic_t
1044  *
1045  * Atomically subtracts @i from @v and returns
1046  * true if the result is zero, or false for all
1047  * other cases.  Note that the guaranteed
1048  * useful range of an atomic_t is only 24 bits.
1049  */
1050 #define atomic_sub_and_test(i,v) (atomic_sub_return((i), (v)) == 0)
1051
1052 /*
1053  * atomic_inc_and_test - increment and test
1054  * @v: pointer of type atomic_t
1055  *
1056  * Atomically increments @v by 1
1057  * and returns true if the result is zero, or false for all
1058  * other cases.  Note that the guaranteed
1059  * useful range of an atomic_t is only 24 bits.
1060  */
1061 #define atomic_inc_and_test(v) (atomic_inc_return(1, (v)) == 0)
1062
1063 /*
1064  * atomic_dec_and_test - decrement by 1 and test
1065  * @v: pointer of type atomic_t
1066  *
1067  * Atomically decrements @v by 1 and
1068  * returns true if the result is 0, or false for all other
1069  * cases.  Note that the guaranteed
1070  * useful range of an atomic_t is only 24 bits.
1071  */
1072 #define atomic_dec_and_test(v) (atomic_sub_return(1, (v)) == 0)
1073
1074 /*
1075  * atomic_inc - increment atomic variable
1076  * @v: pointer of type atomic_t
1077  *
1078  * Atomically increments @v by 1.  Note that the guaranteed
1079  * useful range of an atomic_t is only 24 bits.
1080  */
1081 #define atomic_inc(v) atomic_add(1,(v))
1082
1083 /*
1084  * atomic_dec - decrement and test
1085  * @v: pointer of type atomic_t
1086  *
1087  * Atomically decrements @v by 1.  Note that the guaranteed
1088  * useful range of an atomic_t is only 24 bits.
1089  */
1090 #define atomic_dec(v) atomic_sub(1,(v))
1091
1092 /*
1093  * atomic_add_negative - add and test if negative
1094  * @v: pointer of type atomic_t
1095  * @i: integer value to add
1096  *
1097  * Atomically adds @i to @v and returns true
1098  * if the result is negative, or false when
1099  * result is greater than or equal to zero.  Note that the guaranteed
1100  * useful range of an atomic_t is only 24 bits.
1101  *
1102  * Currently not implemented for MIPS.
1103  */
1104
1105 /* Atomic operations are already serializing */
1106 #define smp_mb__before_atomic_dec()     smp_mb()
1107 #define smp_mb__after_atomic_dec()      smp_mb()
1108 #define smp_mb__before_atomic_inc()     smp_mb()
1109 #define smp_mb__after_atomic_inc()      smp_mb()
1110
1111 #endif /* __ASM_ATOMIC_H */
1112
1113 #else
1114
1115 #if defined(__m68k__)
1116
1117 #ifndef __ARCH_M68K_ATOMIC__
1118 #define __ARCH_M68K_ATOMIC__
1119
1120 /*
1121  * Atomic operations that C can't guarantee us.  Useful for
1122  * resource counting etc..
1123  */
1124
1125 /*
1126  * We do not have SMP m68k systems, so we don't have to deal with that.
1127  */
1128
1129 typedef struct { int counter; } atomic_t;
1130 #define ATOMIC_INIT(i)  { (i) }
1131
1132 #define atomic_read(v)          ((v)->counter)
1133 #define atomic_set(v, i)        (((v)->counter) = i)
1134
1135 static __inline__ void atomic_add(int i, atomic_t *v)
1136 {
1137         __asm__ __volatile__("addl %1,%0" : "=m" (*v) : "id" (i), "0" (*v));
1138 }
1139
1140 static __inline__ void atomic_sub(int i, atomic_t *v)
1141 {
1142         __asm__ __volatile__("subl %1,%0" : "=m" (*v) : "id" (i), "0" (*v));
1143 }
1144
1145 static __inline__ void atomic_inc(volatile atomic_t *v)
1146 {
1147         __asm__ __volatile__("addql #1,%0" : "=m" (*v): "0" (*v));
1148 }
1149
1150 static __inline__ void atomic_dec(volatile atomic_t *v)
1151 {
1152         __asm__ __volatile__("subql #1,%0" : "=m" (*v): "0" (*v));
1153 }
1154
1155 static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
1156 {
1157         char c;
1158         __asm__ __volatile__("subql #1,%1; seq %0" : "=d" (c), "=m" (*v): "1" (*v));
1159         return c != 0;
1160 }
1161
1162 #define atomic_clear_mask(mask, v) \
1163         __asm__ __volatile__("andl %1,%0" : "=m" (*v) : "id" (~(mask)),"0"(*v))
1164
1165 #define atomic_set_mask(mask, v) \
1166         __asm__ __volatile__("orl %1,%0" : "=m" (*v) : "id" (mask),"0"(*v))
1167
1168 /* Atomic operations are already serializing */
1169 #define smp_mb__before_atomic_dec()     barrier()
1170 #define smp_mb__after_atomic_dec()      barrier()
1171 #define smp_mb__before_atomic_inc()     barrier()
1172 #define smp_mb__after_atomic_inc()      barrier()
1173
1174 #endif /* __ARCH_M68K_ATOMIC __ */
1175
1176 #else
1177
1178 #warning libs/pbd has no implementation of strictly atomic operations for your hardware.
1179
1180 #define __NO_STRICT_ATOMIC
1181 #ifdef __NO_STRICT_ATOMIC
1182         
1183 /* 
1184  * Because the implementations from the kernel (where all these come
1185  * from) use cli and spinlocks for hppa and arm...
1186  */
1187
1188 typedef struct { volatile int counter; } atomic_t;
1189
1190 #define ATOMIC_INIT(i)  ( (atomic_t) { (i) } )
1191
1192 #define atomic_read(v)          ((v)->counter)
1193 #define atomic_set(v,i)         ((v)->counter = (i))
1194
1195 static __inline__ void atomic_inc(atomic_t *v)
1196 {
1197         v->counter++;
1198 }
1199
1200 static __inline__ void atomic_dec(atomic_t *v)
1201 {
1202         v->counter--;
1203 }
1204     
1205 static __inline__ int atomic_dec_and_test(atomic_t *v)
1206 {
1207         int res;
1208         v->counter--;
1209         res = v->counter;
1210         return res == 0;
1211 }
1212     
1213 static __inline__ int atomic_inc_and_test(atomic_t *v)
1214 {
1215         int res;
1216         v->counter++;
1217         res = v->counter;
1218         return res == 0;
1219 }
1220
1221 #  endif /* __NO_STRICT_ATOMIC */
1222 #  endif /* m68k */
1223 #  endif /* mips */
1224 #  endif /* s390 */
1225 #  endif /* alpha */
1226 #  endif /* ia64 */
1227 #  endif /* sparc */
1228 #  endif /* i386 */
1229 #  endif /* ppc */
1230
1231 #endif /* __libpbd_atomic_h__ */
1232