1 /*	$NetBSD: atomic.h,v 1.7 2014/12/10 04:38:00 christos Exp $	*/
2 
3 /*
4  * Copyright (C) 2005, 2007, 2009  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: atomic.h,v 1.7 2009/04/08 06:48:23 tbox Exp  */
20 
21 /*
22  * This code was written based on FreeBSD's kernel source whose copyright
23  * follows:
24  */
25 
26 /*-
27  * Copyright (c) 1998 Doug Rabson
28  * All rights reserved.
29  *
30  * Redistribution and use in source and binary forms, with or without
31  * modification, are permitted provided that the following conditions
32  * are met:
33  * 1. Redistributions of source code must retain the above copyright
34  *    notice, this list of conditions and the following disclaimer.
35  * 2. Redistributions in binary form must reproduce the above copyright
36  *    notice, this list of conditions and the following disclaimer in the
37  *    documentation and/or other materials provided with the distribution.
38  *
39  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
40  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
41  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
42  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
43  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
44  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
45  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
46  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
47  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
48  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
49  * SUCH DAMAGE.
50  *
51  * $FreeBSD: src/sys/alpha/include/atomic.h,v 1.18.6.1 2004/09/13 21:52:04 wilko Exp $
52  */
53 
54 #ifndef ISC_ATOMIC_H
55 #define ISC_ATOMIC_H 1
56 
57 #include <isc/platform.h>
58 #include <isc/types.h>
59 
60 #ifdef ISC_PLATFORM_USEOSFASM
61 #include <c_asm.h>
62 
63 #pragma intrinsic(asm)
64 
65 /*
66  * This routine atomically increments the value stored in 'p' by 'val', and
67  * returns the previous value.  Memory access ordering around this function
68  * can be critical, so we add explicit memory block instructions at the
69  * beginning and the end of it (same for other functions).
70  */
71 static __inline isc_int32_t
72 isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
73 	return (asm("mb;"
74 		    "1:"
75 		    "ldl_l %t0, 0(%a0);"	/* load old value */
76 		    "mov %t0, %v0;"		/* copy the old value */
77 		    "addl %t0, %a1, %t0;"	/* calculate new value */
78 		    "stl_c %t0, 0(%a0);"	/* attempt to store */
79 		    "beq %t0, 1b;"		/* spin if failed */
80 		    "mb;",
81 		    p, val));
82 }
83 
84 /*
85  * This routine atomically stores the value 'val' in 'p'.
86  */
87 static __inline void
88 isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
89 	(void)asm("mb;"
90 		  "1:"
91 		  "ldl_l %t0, 0(%a0);"		/* load old value */
92 		  "mov %a1, %t0;"		/* value to store */
93 		  "stl_c %t0, 0(%a0);"		/* attempt to store */
94 		  "beq %t0, 1b;"		/* spin if failed */
95 		  "mb;",
96 		  p, val);
97 }
98 
99 /*
100  * This routine atomically replaces the value in 'p' with 'val', if the
101  * original value is equal to 'cmpval'.  The original value is returned in any
102  * case.
103  */
104 static __inline isc_int32_t
105 isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
106 
107 	return(asm("mb;"
108 		   "1:"
109 		   "ldl_l %t0, 0(%a0);"		/* load old value */
110 		   "mov %t0, %v0;"		/* copy the old value */
111 		   "cmpeq %t0, %a1, %t0;"	/* compare */
112 		   "beq %t0, 2f;"		/* exit if not equal */
113 		   "mov %a2, %t0;"		/* value to store */
114 		   "stl_c %t0, 0(%a0);"		/* attempt to store */
115 		   "beq %t0, 1b;"		/* if it failed, spin */
116 		   "2:"
117 		   "mb;",
118 		   p, cmpval, val));
119 }
120 #elif defined (ISC_PLATFORM_USEGCCASM)
121 static __inline isc_int32_t
122 isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
123 	isc_int32_t temp, prev;
124 
125 	__asm__ volatile(
126 		"mb;"
127 		"1:"
128 		"ldl_l %0, %1;"			/* load old value */
129 		"mov %0, %2;"			/* copy the old value */
130 		"addl %0, %3, %0;"		/* calculate new value */
131 		"stl_c %0, %1;"			/* attempt to store */
132 		"beq %0, 1b;"			/* spin if failed */
133 		"mb;"
134 		: "=&r"(temp), "+m"(*p), "=&r"(prev)
135 		: "r"(val)
136 		: "memory");
137 
138 	return (prev);
139 }
140 
141 static __inline void
142 isc_atomic_store(isc_int32_t *p, isc_int32_t val) {
143 	isc_int32_t temp;
144 
145 	__asm__ volatile(
146 		"mb;"
147 		"1:"
148 		"ldl_l %0, %1;"			/* load old value */
149 		"mov %2, %0;"			/* value to store */
150 		"stl_c %0, %1;"			/* attempt to store */
151 		"beq %0, 1b;"			/* if it failed, spin */
152 		"mb;"
153 		: "=&r"(temp), "+m"(*p)
154 		: "r"(val)
155 		: "memory");
156 }
157 
158 static __inline isc_int32_t
159 isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
160 	isc_int32_t temp, prev;
161 
162 	__asm__ volatile(
163 		"mb;"
164 		"1:"
165 		"ldl_l %0, %1;"			/* load old value */
166 		"mov %0, %2;"			/* copy the old value */
167 		"cmpeq %0, %3, %0;"		/* compare */
168 		"beq %0, 2f;"			/* exit if not equal */
169 		"mov %4, %0;"			/* value to store */
170 		"stl_c %0, %1;"			/* attempt to store */
171 		"beq %0, 1b;"			/* if it failed, spin */
172 		"2:"
173 		"mb;"
174 		: "=&r"(temp), "+m"(*p), "=&r"(prev)
175 		: "r"(cmpval), "r"(val)
176 		: "memory");
177 
178 	return (prev);
179 }
180 #else
181 
182 #error "unsupported compiler.  disable atomic ops by --disable-atomic"
183 
184 #endif
185 
186 #endif /* ISC_ATOMIC_H */
187