1170222Sdougb/*
2245163Serwin * Copyright (C) 2006, 2007, 2009, 2012  Internet Systems Consortium, Inc. ("ISC")
3170222Sdougb *
4193149Sdougb * 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: atomic.h,v 1.7 2009/06/24 02:22:50 marka Exp $ */
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#ifdef ISC_PLATFORM_USEGCCASM
26170222Sdougb/*
27170222Sdougb * This routine atomically increments the value stored in 'p' by 'val', and
28170222Sdougb * returns the previous value.
29170222Sdougb *
30170222Sdougb * Open issue: can 'fetchadd' make the code faster for some particular values
31170222Sdougb * (e.g., 1 and -1)?
32170222Sdougb */
33170222Sdougbstatic inline isc_int32_t
34195000Sdougb#ifdef __GNUC__
35195000Sdougb__attribute__ ((unused))
36195000Sdougb#endif
37193149Sdougbisc_atomic_xadd(isc_int32_t *p, isc_int32_t val)
38193149Sdougb{
39170222Sdougb	isc_int32_t prev, swapped;
40170222Sdougb
41170222Sdougb	for (prev = *(volatile isc_int32_t *)p; ; prev = swapped) {
42170222Sdougb		swapped = prev + val;
43170222Sdougb		__asm__ volatile(
44200202Smarcel			"mov ar.ccv=%2;;"
45170222Sdougb			"cmpxchg4.acq %0=%4,%3,ar.ccv"
46170222Sdougb			: "=r" (swapped), "=m" (*p)
47170222Sdougb			: "r" (prev), "r" (swapped), "m" (*p)
48170222Sdougb			: "memory");
49170222Sdougb		if (swapped == prev)
50170222Sdougb			break;
51170222Sdougb	}
52170222Sdougb
53170222Sdougb	return (prev);
54170222Sdougb}
55170222Sdougb
56170222Sdougb/*
57170222Sdougb * This routine atomically stores the value 'val' in 'p'.
58170222Sdougb */
59170222Sdougbstatic inline void
60195000Sdougb#ifdef __GNUC__
61195000Sdougb__attribute__ ((unused))
62195000Sdougb#endif
63193149Sdougbisc_atomic_store(isc_int32_t *p, isc_int32_t val)
64193149Sdougb{
65170222Sdougb	__asm__ volatile(
66170222Sdougb		"st4.rel %0=%1"
67170222Sdougb		: "=m" (*p)
68170222Sdougb		: "r" (val)
69170222Sdougb		: "memory"
70170222Sdougb		);
71170222Sdougb}
72170222Sdougb
73170222Sdougb/*
74170222Sdougb * This routine atomically replaces the value in 'p' with 'val', if the
75170222Sdougb * original value is equal to 'cmpval'.  The original value is returned in any
76170222Sdougb * case.
77170222Sdougb */
78170222Sdougbstatic inline isc_int32_t
79195000Sdougb#ifdef __GNUC__
80195000Sdougb__attribute__ ((unused))
81195000Sdougb#endif
82193149Sdougbisc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val)
83193149Sdougb{
84170222Sdougb	isc_int32_t ret;
85170222Sdougb
86170222Sdougb	__asm__ volatile(
87200202Smarcel		"mov ar.ccv=%2;;"
88170222Sdougb		"cmpxchg4.acq %0=%4,%3,ar.ccv"
89170222Sdougb		: "=r" (ret), "=m" (*p)
90170222Sdougb		: "r" (cmpval), "r" (val), "m" (*p)
91170222Sdougb		: "memory");
92170222Sdougb
93170222Sdougb	return (ret);
94170222Sdougb}
95170222Sdougb#else /* !ISC_PLATFORM_USEGCCASM */
96170222Sdougb
97170222Sdougb#error "unsupported compiler.  disable atomic ops by --disable-atomic"
98170222Sdougb
99170222Sdougb#endif
100170222Sdougb#endif /* ISC_ATOMIC_H */
101