1290001Sglebius/*
2290001Sglebius * Copyright (C) 2005, 2007, 2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3290001Sglebius *
4290001Sglebius * Permission to use, copy, modify, and/or distribute this software for any
5290001Sglebius * purpose with or without fee is hereby granted, provided that the above
6290001Sglebius * copyright notice and this permission notice appear in all copies.
7290001Sglebius *
8290001Sglebius * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9290001Sglebius * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10290001Sglebius * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11290001Sglebius * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12290001Sglebius * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13290001Sglebius * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14290001Sglebius * PERFORMANCE OF THIS SOFTWARE.
15290001Sglebius */
16290001Sglebius
17290001Sglebius/* $Id$ */
18290001Sglebius
19290001Sglebius#ifndef ISC_ATOMIC_H
20290001Sglebius#define ISC_ATOMIC_H 1
21290001Sglebius
22290001Sglebius#include <isc/platform.h>
23290001Sglebius#include <isc/types.h>
24290001Sglebius
25290001Sglebius/*!\file
26290001Sglebius * static inline isc_int32_t
27290001Sglebius * isc_atomic_xadd(isc_int32_t *p, isc_int32_t val);
28290001Sglebius *
29290001Sglebius * This routine atomically increments the value stored in 'p' by 'val', and
30290001Sglebius * returns the previous value.
31290001Sglebius *
32290001Sglebius * static inline void
33290001Sglebius * isc_atomic_store(void *p, isc_int32_t val);
34290001Sglebius *
35290001Sglebius * This routine atomically stores the value 'val' in 'p'.
36290001Sglebius *
37290001Sglebius * static inline isc_int32_t
38290001Sglebius * isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val);
39290001Sglebius *
40290001Sglebius * This routine atomically replaces the value in 'p' with 'val', if the
41290001Sglebius * original value is equal to 'cmpval'.  The original value is returned in any
42290001Sglebius * case.
43290001Sglebius */
44290001Sglebius
45290001Sglebius#if defined(_AIX)
46290001Sglebius
47290001Sglebius#include <sys/atomic_op.h>
48290001Sglebius
49290001Sglebius#define isc_atomic_store(p, v) _clear_lock(p, v)
50290001Sglebius
51290001Sglebius#ifdef __GNUC__
52290001Sglebiusstatic inline isc_int32_t
53290001Sglebius#else
54290001Sglebiusstatic isc_int32_t
55290001Sglebius#endif
56290001Sglebiusisc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
57290001Sglebius	int ret;
58290001Sglebius
59290001Sglebius#ifdef __GNUC__
60290001Sglebius	asm("ics");
61290001Sglebius#else
62290001Sglebius	 __isync();
63290001Sglebius#endif
64290001Sglebius
65290001Sglebius	ret = fetch_and_add((atomic_p)p, (int)val);
66290001Sglebius
67290001Sglebius#ifdef __GNUC__
68290001Sglebius	asm("ics");
69290001Sglebius#else
70290001Sglebius	 __isync();
71290001Sglebius#endif
72290001Sglebius
73290001Sglebius	 return (ret);
74290001Sglebius}
75290001Sglebius
76290001Sglebius#ifdef __GNUC__
77290001Sglebiusstatic inline int
78290001Sglebius#else
79290001Sglebiusstatic int
80290001Sglebius#endif
81290001Sglebiusisc_atomic_cmpxchg(atomic_p p, int old, int new) {
82290001Sglebius	int orig = old;
83290001Sglebius
84290001Sglebius#ifdef __GNUC__
85290001Sglebius	asm("ics");
86290001Sglebius#else
87290001Sglebius	 __isync();
88290001Sglebius#endif
89290001Sglebius	if (compare_and_swap(p, &orig, new))
90290001Sglebius		orig = old;
91290001Sglebius
92290001Sglebius#ifdef __GNUC__
93290001Sglebius	asm("ics");
94290001Sglebius#else
95290001Sglebius	 __isync();
96290001Sglebius#endif
97290001Sglebius
98290001Sglebius	return (orig);
99290001Sglebius}
100290001Sglebius
101290001Sglebius#elif defined(ISC_PLATFORM_USEGCCASM) || defined(ISC_PLATFORM_USEMACASM)
102290001Sglebiusstatic inline isc_int32_t
103290001Sglebiusisc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
104290001Sglebius	isc_int32_t orig;
105290001Sglebius
106290001Sglebius	__asm__ volatile (
107290001Sglebius#ifdef ISC_PLATFORM_USEMACASM
108290001Sglebius		"1:"
109290001Sglebius		"lwarx r6, 0, %1\n"
110290001Sglebius		"mr %0, r6\n"
111290001Sglebius		"add r6, r6, %2\n"
112290001Sglebius		"stwcx. r6, 0, %1\n"
113290001Sglebius		"bne- 1b\n"
114290001Sglebius		"sync"
115290001Sglebius#else
116290001Sglebius		"1:"
117290001Sglebius		"lwarx 6, 0, %1\n"
118290001Sglebius		"mr %0, 6\n"
119290001Sglebius		"add 6, 6, %2\n"
120290001Sglebius		"stwcx. 6, 0, %1\n"
121290001Sglebius		"bne- 1b\n"
122290001Sglebius		"sync"
123290001Sglebius#endif
124290001Sglebius		: "=&r"(orig)
125290001Sglebius		: "r"(p), "r"(val)
126290001Sglebius		: "r6", "memory"
127290001Sglebius		);
128290001Sglebius
129290001Sglebius	return (orig);
130290001Sglebius}
131290001Sglebius
132290001Sglebiusstatic inline void
133290001Sglebiusisc_atomic_store(void *p, isc_int32_t val) {
134290001Sglebius	__asm__ volatile (
135290001Sglebius#ifdef ISC_PLATFORM_USEMACASM
136290001Sglebius		"1:"
137290001Sglebius		"lwarx r6, 0, %0\n"
138290001Sglebius		"lwz r6, %1\n"
139290001Sglebius		"stwcx. r6, 0, %0\n"
140290001Sglebius		"bne- 1b\n"
141290001Sglebius		"sync"
142290001Sglebius#else
143290001Sglebius		"1:"
144290001Sglebius		"lwarx 6, 0, %0\n"
145290001Sglebius		"lwz 6, %1\n"
146290001Sglebius		"stwcx. 6, 0, %0\n"
147290001Sglebius		"bne- 1b\n"
148290001Sglebius		"sync"
149290001Sglebius#endif
150290001Sglebius		:
151290001Sglebius		: "r"(p), "m"(val)
152290001Sglebius		: "r6", "memory"
153290001Sglebius		);
154290001Sglebius}
155290001Sglebius
156290001Sglebiusstatic inline isc_int32_t
157290001Sglebiusisc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
158290001Sglebius	isc_int32_t orig;
159290001Sglebius
160290001Sglebius	__asm__ volatile (
161290001Sglebius#ifdef ISC_PLATFORM_USEMACASM
162290001Sglebius		"1:"
163290001Sglebius		"lwarx r6, 0, %1\n"
164290001Sglebius		"mr %0,r6\n"
165290001Sglebius		"cmpw r6, %2\n"
166290001Sglebius		"bne 2f\n"
167290001Sglebius		"mr r6, %3\n"
168290001Sglebius		"stwcx. r6, 0, %1\n"
169290001Sglebius		"bne- 1b\n"
170290001Sglebius		"2:\n"
171290001Sglebius		"sync"
172290001Sglebius#else
173290001Sglebius		"1:"
174290001Sglebius		"lwarx 6, 0, %1\n"
175290001Sglebius		"mr %0,6\n"
176290001Sglebius		"cmpw 6, %2\n"
177290001Sglebius		"bne 2f\n"
178290001Sglebius		"mr 6, %3\n"
179290001Sglebius		"stwcx. 6, 0, %1\n"
180290001Sglebius		"bne- 1b\n"
181290001Sglebius		"2:\n"
182290001Sglebius		"sync"
183290001Sglebius#endif
184290001Sglebius		: "=&r" (orig)
185290001Sglebius		: "r"(p), "r"(cmpval), "r"(val)
186290001Sglebius		: "r6", "memory"
187290001Sglebius		);
188290001Sglebius
189290001Sglebius	return (orig);
190290001Sglebius}
191290001Sglebius
192290001Sglebius#else
193290001Sglebius
194290001Sglebius#error "unsupported compiler.  disable atomic ops by --disable-atomic"
195290001Sglebius
196290001Sglebius#endif
197290001Sglebius#endif /* ISC_ATOMIC_H */
198