1 /*	$NetBSD: atomic.h,v 1.7 2014/12/10 04:38:00 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2005, 2007, 2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
5  *
6  * Permission to use, copy, modify, and/or distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
11  * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
12  * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
13  * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
14  * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
15  * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
16  * PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 /* Id */
20 
21 #ifndef ISC_ATOMIC_H
22 #define ISC_ATOMIC_H 1
23 
24 #include <isc/platform.h>
25 #include <isc/types.h>
26 
27 /*!\file
28  * static inline isc_int32_t
29  * isc_atomic_xadd(isc_int32_t *p, isc_int32_t val);
30  *
31  * This routine atomically increments the value stored in 'p' by 'val', and
32  * returns the previous value.
33  *
34  * static inline void
35  * isc_atomic_store(void *p, isc_int32_t val);
36  *
37  * This routine atomically stores the value 'val' in 'p'.
38  *
39  * static inline isc_int32_t
40  * isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val);
41  *
42  * This routine atomically replaces the value in 'p' with 'val', if the
43  * original value is equal to 'cmpval'.  The original value is returned in any
44  * case.
45  */
46 
47 #if defined(_AIX)
48 
49 #include <sys/atomic_op.h>
50 
51 #define isc_atomic_store(p, v) _clear_lock(p, v)
52 
53 #ifdef __GNUC__
54 static __inline isc_int32_t
55 #else
56 static isc_int32_t
57 #endif
isc_atomic_xadd(isc_int32_t * p,isc_int32_t val)58 isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
59 	int ret;
60 
61 #ifdef __GNUC__
62 	asm("ics");
63 #else
64 	 __isync();
65 #endif
66 
67 	ret = fetch_and_add((atomic_p)p, (int)val);
68 
69 #ifdef __GNUC__
70 	asm("ics");
71 #else
72 	 __isync();
73 #endif
74 
75 	 return (ret);
76 }
77 
78 #ifdef __GNUC__
79 static __inline int
80 #else
81 static int
82 #endif
isc_atomic_cmpxchg(atomic_p p,int old,int new)83 isc_atomic_cmpxchg(atomic_p p, int old, int new) {
84 	int orig = old;
85 
86 #ifdef __GNUC__
87 	asm("ics");
88 #else
89 	 __isync();
90 #endif
91 	if (compare_and_swap(p, &orig, new))
92 		orig = old;
93 
94 #ifdef __GNUC__
95 	asm("ics");
96 #else
97 	 __isync();
98 #endif
99 
100 	return (orig);
101 }
102 
103 #elif defined(ISC_PLATFORM_USEGCCASM) || defined(ISC_PLATFORM_USEMACASM)
104 static __inline isc_int32_t
isc_atomic_xadd(isc_int32_t * p,isc_int32_t val)105 isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
106 	isc_int32_t orig;
107 
108 	__asm__ volatile (
109 #ifdef ISC_PLATFORM_USEMACASM
110 		"1:"
111 		"lwarx r6, 0, %1\n"
112 		"mr %0, r6\n"
113 		"add r6, r6, %2\n"
114 		"stwcx. r6, 0, %1\n"
115 		"bne- 1b\n"
116 		"sync"
117 #else
118 		"1:"
119 		"lwarx 6, 0, %1\n"
120 		"mr %0, 6\n"
121 		"add 6, 6, %2\n"
122 		"stwcx. 6, 0, %1\n"
123 		"bne- 1b\n"
124 		"sync"
125 #endif
126 		: "=&r"(orig)
127 		: "r"(p), "r"(val)
128 		: "r6", "memory"
129 		);
130 
131 	return (orig);
132 }
133 
134 static __inline void
isc_atomic_store(void * p,isc_int32_t val)135 isc_atomic_store(void *p, isc_int32_t val) {
136 	__asm__ volatile (
137 #ifdef ISC_PLATFORM_USEMACASM
138 		"1:"
139 		"lwarx r6, 0, %0\n"
140 		"lwz r6, %1\n"
141 		"stwcx. r6, 0, %0\n"
142 		"bne- 1b\n"
143 		"sync"
144 #else
145 		"1:"
146 		"lwarx 6, 0, %0\n"
147 		"lwz 6, %1\n"
148 		"stwcx. 6, 0, %0\n"
149 		"bne- 1b\n"
150 		"sync"
151 #endif
152 		:
153 		: "r"(p), "m"(val)
154 		: "r6", "memory"
155 		);
156 }
157 
158 static __inline isc_int32_t
isc_atomic_cmpxchg(isc_int32_t * p,isc_int32_t cmpval,isc_int32_t val)159 isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
160 	isc_int32_t orig;
161 
162 	__asm__ volatile (
163 #ifdef ISC_PLATFORM_USEMACASM
164 		"1:"
165 		"lwarx r6, 0, %1\n"
166 		"mr %0,r6\n"
167 		"cmpw r6, %2\n"
168 		"bne 2f\n"
169 		"mr r6, %3\n"
170 		"stwcx. r6, 0, %1\n"
171 		"bne- 1b\n"
172 		"2:\n"
173 		"sync"
174 #else
175 		"1:"
176 		"lwarx 6, 0, %1\n"
177 		"mr %0,6\n"
178 		"cmpw 6, %2\n"
179 		"bne 2f\n"
180 		"mr 6, %3\n"
181 		"stwcx. 6, 0, %1\n"
182 		"bne- 1b\n"
183 		"2:\n"
184 		"sync"
185 #endif
186 		: "=&r" (orig)
187 		: "r"(p), "r"(cmpval), "r"(val)
188 		: "r6", "memory"
189 		);
190 
191 	return (orig);
192 }
193 
194 #else
195 
196 #error "unsupported compiler.  disable atomic ops by --disable-atomic"
197 
198 #endif
199 #endif /* ISC_ATOMIC_H */
200