1170222Sdougb/*
2234010Sdougb * Copyright (C) 2005, 2007, 2009, 2011, 2012  Internet Systems Consortium, Inc. ("ISC")
3170222Sdougb *
4174187Sdougb * Permission to use, copy, modify, and/or distribute this software for any
5170222Sdougb * purpose with or without fee is hereby granted, provided that the above
6170222Sdougb * copyright notice and this permission notice appear in all copies.
7170222Sdougb *
8170222Sdougb * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
9170222Sdougb * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
10170222Sdougb * AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
11170222Sdougb * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
12170222Sdougb * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
13170222Sdougb * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
14170222Sdougb * PERFORMANCE OF THIS SOFTWARE.
15170222Sdougb */
16170222Sdougb
17234010Sdougb/* $Id$ */
18170222Sdougb
19170222Sdougb#ifndef ISC_ATOMIC_H
20170222Sdougb#define ISC_ATOMIC_H 1
21170222Sdougb
22170222Sdougb#include <isc/platform.h>
23170222Sdougb#include <isc/types.h>
24170222Sdougb
25170222Sdougb/*!\file
26170222Sdougb * static inline isc_int32_t
27170222Sdougb * isc_atomic_xadd(isc_int32_t *p, isc_int32_t val);
28170222Sdougb *
29170222Sdougb * This routine atomically increments the value stored in 'p' by 'val', and
30170222Sdougb * returns the previous value.
31170222Sdougb *
32170222Sdougb * static inline void
33170222Sdougb * isc_atomic_store(void *p, isc_int32_t val);
34170222Sdougb *
35170222Sdougb * This routine atomically stores the value 'val' in 'p'.
36170222Sdougb *
37170222Sdougb * static inline isc_int32_t
38170222Sdougb * isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val);
39170222Sdougb *
40170222Sdougb * This routine atomically replaces the value in 'p' with 'val', if the
41170222Sdougb * original value is equal to 'cmpval'.  The original value is returned in any
42170222Sdougb * case.
43170222Sdougb */
44170222Sdougb
45170222Sdougb#if defined(_AIX)
46170222Sdougb
47170222Sdougb#include <sys/atomic_op.h>
48170222Sdougb
49170222Sdougb#define isc_atomic_store(p, v) _clear_lock(p, v)
50170222Sdougb
51170222Sdougb#ifdef __GNUC__
52204619Sdougbstatic inline isc_int32_t
53204619Sdougb#else
54204619Sdougbstatic isc_int32_t
55204619Sdougb#endif
56204619Sdougbisc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
57204619Sdougb	int ret;
58204619Sdougb
59204619Sdougb#ifdef __GNUC__
60204619Sdougb	asm("ics");
61204619Sdougb#else
62204619Sdougb	 __isync();
63204619Sdougb#endif
64204619Sdougb
65204619Sdougb	ret = fetch_and_add((atomic_p)p, (int)val);
66204619Sdougb
67204619Sdougb#ifdef __GNUC__
68204619Sdougb	asm("ics");
69204619Sdougb#else
70204619Sdougb	 __isync();
71204619Sdougb#endif
72204619Sdougb
73204619Sdougb	 return (ret);
74204619Sdougb}
75204619Sdougb
76204619Sdougb#ifdef __GNUC__
77170222Sdougbstatic inline int
78170222Sdougb#else
79170222Sdougbstatic int
80170222Sdougb#endif
81170222Sdougbisc_atomic_cmpxchg(atomic_p p, int old, int new) {
82204619Sdougb	int orig = old;
83170222Sdougb
84170222Sdougb#ifdef __GNUC__
85204619Sdougb	asm("ics");
86170222Sdougb#else
87204619Sdougb	 __isync();
88170222Sdougb#endif
89204619Sdougb	if (compare_and_swap(p, &orig, new))
90204619Sdougb		orig = old;
91204619Sdougb
92204619Sdougb#ifdef __GNUC__
93204619Sdougb	asm("ics");
94204619Sdougb#else
95204619Sdougb	 __isync();
96204619Sdougb#endif
97204619Sdougb
98204619Sdougb	return (orig);
99170222Sdougb}
100170222Sdougb
101170222Sdougb#elif defined(ISC_PLATFORM_USEGCCASM) || defined(ISC_PLATFORM_USEMACASM)
102170222Sdougbstatic inline isc_int32_t
103170222Sdougbisc_atomic_xadd(isc_int32_t *p, isc_int32_t val) {
104170222Sdougb	isc_int32_t orig;
105170222Sdougb
106170222Sdougb	__asm__ volatile (
107170222Sdougb#ifdef ISC_PLATFORM_USEMACASM
108170222Sdougb		"1:"
109170222Sdougb		"lwarx r6, 0, %1\n"
110204619Sdougb		"mr %0, r6\n"
111170222Sdougb		"add r6, r6, %2\n"
112170222Sdougb		"stwcx. r6, 0, %1\n"
113225361Sdougb		"bne- 1b\n"
114225361Sdougb		"sync"
115170222Sdougb#else
116170222Sdougb		"1:"
117170222Sdougb		"lwarx 6, 0, %1\n"
118204619Sdougb		"mr %0, 6\n"
119170222Sdougb		"add 6, 6, %2\n"
120170222Sdougb		"stwcx. 6, 0, %1\n"
121225361Sdougb		"bne- 1b\n"
122225361Sdougb		"sync"
123170222Sdougb#endif
124170222Sdougb		: "=&r"(orig)
125170222Sdougb		: "r"(p), "r"(val)
126170222Sdougb		: "r6", "memory"
127170222Sdougb		);
128170222Sdougb
129170222Sdougb	return (orig);
130170222Sdougb}
131170222Sdougb
132170222Sdougbstatic inline void
133170222Sdougbisc_atomic_store(void *p, isc_int32_t val) {
134170222Sdougb	__asm__ volatile (
135170222Sdougb#ifdef ISC_PLATFORM_USEMACASM
136170222Sdougb		"1:"
137170222Sdougb		"lwarx r6, 0, %0\n"
138170222Sdougb		"lwz r6, %1\n"
139170222Sdougb		"stwcx. r6, 0, %0\n"
140225361Sdougb		"bne- 1b\n"
141225361Sdougb		"sync"
142170222Sdougb#else
143170222Sdougb		"1:"
144170222Sdougb		"lwarx 6, 0, %0\n"
145170222Sdougb		"lwz 6, %1\n"
146170222Sdougb		"stwcx. 6, 0, %0\n"
147225361Sdougb		"bne- 1b\n"
148225361Sdougb		"sync"
149170222Sdougb#endif
150170222Sdougb		:
151170222Sdougb		: "r"(p), "m"(val)
152170222Sdougb		: "r6", "memory"
153170222Sdougb		);
154170222Sdougb}
155170222Sdougb
156170222Sdougbstatic inline isc_int32_t
157170222Sdougbisc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) {
158170222Sdougb	isc_int32_t orig;
159170222Sdougb
160170222Sdougb	__asm__ volatile (
161170222Sdougb#ifdef ISC_PLATFORM_USEMACASM
162170222Sdougb		"1:"
163170222Sdougb		"lwarx r6, 0, %1\n"
164170222Sdougb		"mr %0,r6\n"
165170222Sdougb		"cmpw r6, %2\n"
166170222Sdougb		"bne 2f\n"
167170222Sdougb		"mr r6, %3\n"
168170222Sdougb		"stwcx. r6, 0, %1\n"
169170222Sdougb		"bne- 1b\n"
170225361Sdougb		"2:\n"
171225361Sdougb		"sync"
172170222Sdougb#else
173170222Sdougb		"1:"
174170222Sdougb		"lwarx 6, 0, %1\n"
175170222Sdougb		"mr %0,6\n"
176170222Sdougb		"cmpw 6, %2\n"
177170222Sdougb		"bne 2f\n"
178170222Sdougb		"mr 6, %3\n"
179170222Sdougb		"stwcx. 6, 0, %1\n"
180170222Sdougb		"bne- 1b\n"
181225361Sdougb		"2:\n"
182225361Sdougb		"sync"
183170222Sdougb#endif
184170222Sdougb		: "=&r" (orig)
185170222Sdougb		: "r"(p), "r"(cmpval), "r"(val)
186170222Sdougb		: "r6", "memory"
187170222Sdougb		);
188170222Sdougb
189170222Sdougb	return (orig);
190170222Sdougb}
191170222Sdougb
192170222Sdougb#else
193170222Sdougb
194170222Sdougb#error "unsupported compiler.  disable atomic ops by --disable-atomic"
195170222Sdougb
196170222Sdougb#endif
197170222Sdougb#endif /* ISC_ATOMIC_H */
198