1290001Sglebius/*
2290001Sglebius * Copyright (C) 2006, 2007, 2009  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: atomic.h,v 1.7 2009/06/24 02:22:50 marka Exp $ */
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#ifdef ISC_PLATFORM_USEGCCASM
26290001Sglebius/*
27290001Sglebius * This routine atomically increments the value stored in 'p' by 'val', and
28290001Sglebius * returns the previous value.
29290001Sglebius *
30290001Sglebius * Open issue: can 'fetchadd' make the code faster for some particular values
31290001Sglebius * (e.g., 1 and -1)?
32290001Sglebius */
33290001Sglebiusstatic inline isc_int32_t
34290001Sglebius#ifdef __GNUC__
35290001Sglebius__attribute__ ((unused))
36290001Sglebius#endif
37290001Sglebiusisc_atomic_xadd(isc_int32_t *p, isc_int32_t val)
38290001Sglebius{
39290001Sglebius	isc_int32_t prev, swapped;
40290001Sglebius
41290001Sglebius	for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) {
42290001Sglebius		swapped = prev + val;
43290001Sglebius		__asm__ volatile(
44290001Sglebius			"mov ar.ccv=%2;"
45290001Sglebius			"cmpxchg4.acq %0=%4,%3,ar.ccv"
46290001Sglebius			: "=r" (swapped), "=m" (*p)
47290001Sglebius			: "r" (prev), "r" (swapped), "m" (*p)
48290001Sglebius			: "memory");
49290001Sglebius		if (swapped == prev)
50290001Sglebius			break;
51290001Sglebius	}
52290001Sglebius
53290001Sglebius	return (prev);
54290001Sglebius}
55290001Sglebius
56290001Sglebius/*
57290001Sglebius * This routine atomically stores the value 'val' in 'p'.
58290001Sglebius */
59290001Sglebiusstatic inline void
60290001Sglebius#ifdef __GNUC__
61290001Sglebius__attribute__ ((unused))
62290001Sglebius#endif
63290001Sglebiusisc_atomic_store(isc_int32_t *p, isc_int32_t val)
64290001Sglebius{
65290001Sglebius	__asm__ volatile(
66290001Sglebius		"st4.rel %0=%1"
67290001Sglebius		: "=m" (*p)
68290001Sglebius		: "r" (val)
69290001Sglebius		: "memory"
70290001Sglebius		);
71290001Sglebius}
72290001Sglebius
73290001Sglebius/*
74290001Sglebius * This routine atomically replaces the value in 'p' with 'val', if the
75290001Sglebius * original value is equal to 'cmpval'.  The original value is returned in any
76290001Sglebius * case.
77290001Sglebius */
78290001Sglebiusstatic inline isc_int32_t
79290001Sglebius#ifdef __GNUC__
80290001Sglebius__attribute__ ((unused))
81290001Sglebius#endif
82290001Sglebiusisc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val)
83290001Sglebius{
84290001Sglebius	isc_int32_t ret;
85290001Sglebius
86290001Sglebius	__asm__ volatile(
87290001Sglebius		"mov ar.ccv=%2;"
88290001Sglebius		"cmpxchg4.acq %0=%4,%3,ar.ccv"
89290001Sglebius		: "=r" (ret), "=m" (*p)
90290001Sglebius		: "r" (cmpval), "r" (val), "m" (*p)
91290001Sglebius		: "memory");
92290001Sglebius
93290001Sglebius	return (ret);
94290001Sglebius}
95290001Sglebius#else /* !ISC_PLATFORM_USEGCCASM */
96290001Sglebius
97290001Sglebius#error "unsupported compiler.  disable atomic ops by --disable-atomic"
98290001Sglebius
99290001Sglebius#endif
100290001Sglebius#endif /* ISC_ATOMIC_H */
101