1258945Sroberto/* 2258945Sroberto * Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") 3258945Sroberto * 4258945Sroberto * Permission to use, copy, modify, and/or distribute this software for any 5258945Sroberto * purpose with or without fee is hereby granted, provided that the above 6258945Sroberto * copyright notice and this permission notice appear in all copies. 7258945Sroberto * 8258945Sroberto * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 9258945Sroberto * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 10258945Sroberto * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 11258945Sroberto * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 12258945Sroberto * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 13258945Sroberto * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 14258945Sroberto * PERFORMANCE OF THIS SOFTWARE. 15258945Sroberto */ 16258945Sroberto 17280849Scy/* $Id: atomic.h,v 1.7 2009/04/08 06:48:23 tbox Exp $ */ 18258945Sroberto 19258945Sroberto/* 20258945Sroberto * This code was written based on FreeBSD's kernel source whose copyright 21258945Sroberto * follows: 22258945Sroberto */ 23258945Sroberto 24258945Sroberto/*- 25258945Sroberto * Copyright (c) 1998 Doug Rabson 26258945Sroberto * All rights reserved. 27258945Sroberto * 28258945Sroberto * Redistribution and use in source and binary forms, with or without 29258945Sroberto * modification, are permitted provided that the following conditions 30258945Sroberto * are met: 31258945Sroberto * 1. Redistributions of source code must retain the above copyright 32258945Sroberto * notice, this list of conditions and the following disclaimer. 33258945Sroberto * 2. Redistributions in binary form must reproduce the above copyright 34258945Sroberto * notice, this list of conditions and the following disclaimer in the 35258945Sroberto * documentation and/or other materials provided with the distribution. 36258945Sroberto * 37258945Sroberto * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 38258945Sroberto * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 39258945Sroberto * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 40258945Sroberto * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 41258945Sroberto * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 42258945Sroberto * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 43258945Sroberto * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44258945Sroberto * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 45258945Sroberto * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 46258945Sroberto * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 47258945Sroberto * SUCH DAMAGE. 48258945Sroberto * 49280849Scy * $FreeBSD: 258945 2013-12-04 21:33:17Z roberto $ 50258945Sroberto */ 51258945Sroberto 52258945Sroberto#ifndef ISC_ATOMIC_H 53258945Sroberto#define ISC_ATOMIC_H 1 54258945Sroberto 55258945Sroberto#include <isc/platform.h> 56258945Sroberto#include <isc/types.h> 57258945Sroberto 58258945Sroberto#ifdef ISC_PLATFORM_USEOSFASM 59258945Sroberto#include <c_asm.h> 60258945Sroberto 61258945Sroberto#pragma intrinsic(asm) 62258945Sroberto 63258945Sroberto/* 64258945Sroberto * This routine atomically increments the value stored in 'p' by 'val', and 65258945Sroberto * returns the previous value. Memory access ordering around this function 66258945Sroberto * can be critical, so we add explicit memory block instructions at the 67258945Sroberto * beginning and the end of it (same for other functions). 68258945Sroberto */ 69258945Srobertostatic inline isc_int32_t 70258945Srobertoisc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { 71258945Sroberto return (asm("mb;" 72258945Sroberto "1:" 73258945Sroberto "ldl_l %t0, 0(%a0);" /* load old value */ 74258945Sroberto "mov %t0, %v0;" /* copy the old value */ 75258945Sroberto "addl %t0, %a1, %t0;" /* calculate new value */ 76258945Sroberto "stl_c %t0, 0(%a0);" /* attempt to store */ 77258945Sroberto "beq %t0, 1b;" /* spin if failed */ 78258945Sroberto "mb;", 79258945Sroberto p, val)); 80258945Sroberto} 81258945Sroberto 82258945Sroberto/* 83258945Sroberto * This routine atomically stores the value 'val' in 'p'. 84258945Sroberto */ 85258945Srobertostatic inline void 86258945Srobertoisc_atomic_store(isc_int32_t *p, isc_int32_t val) { 87258945Sroberto (void)asm("mb;" 88258945Sroberto "1:" 89258945Sroberto "ldl_l %t0, 0(%a0);" /* load old value */ 90258945Sroberto "mov %a1, %t0;" /* value to store */ 91258945Sroberto "stl_c %t0, 0(%a0);" /* attempt to store */ 92258945Sroberto "beq %t0, 1b;" /* spin if failed */ 93258945Sroberto "mb;", 94258945Sroberto p, val); 95258945Sroberto} 96258945Sroberto 97258945Sroberto/* 98258945Sroberto * This routine atomically replaces the value in 'p' with 'val', if the 99258945Sroberto * original value is equal to 'cmpval'. The original value is returned in any 100258945Sroberto * case. 101258945Sroberto */ 102258945Srobertostatic inline isc_int32_t 103258945Srobertoisc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { 104258945Sroberto 105258945Sroberto return(asm("mb;" 106258945Sroberto "1:" 107258945Sroberto "ldl_l %t0, 0(%a0);" /* load old value */ 108258945Sroberto "mov %t0, %v0;" /* copy the old value */ 109258945Sroberto "cmpeq %t0, %a1, %t0;" /* compare */ 110258945Sroberto "beq %t0, 2f;" /* exit if not equal */ 111258945Sroberto "mov %a2, %t0;" /* value to store */ 112258945Sroberto "stl_c %t0, 0(%a0);" /* attempt to store */ 113258945Sroberto "beq %t0, 1b;" /* if it failed, spin */ 114258945Sroberto "2:" 115258945Sroberto "mb;", 116258945Sroberto p, cmpval, val)); 117258945Sroberto} 118258945Sroberto#elif defined (ISC_PLATFORM_USEGCCASM) 119258945Srobertostatic inline isc_int32_t 120258945Srobertoisc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { 121258945Sroberto isc_int32_t temp, prev; 122258945Sroberto 123258945Sroberto __asm__ volatile( 124258945Sroberto "mb;" 125258945Sroberto "1:" 126258945Sroberto "ldl_l %0, %1;" /* load old value */ 127258945Sroberto "mov %0, %2;" /* copy the old value */ 128258945Sroberto "addl %0, %3, %0;" /* calculate new value */ 129258945Sroberto "stl_c %0, %1;" /* attempt to store */ 130258945Sroberto "beq %0, 1b;" /* spin if failed */ 131258945Sroberto "mb;" 132258945Sroberto : "=&r"(temp), "+m"(*p), "=&r"(prev) 133258945Sroberto : "r"(val) 134258945Sroberto : "memory"); 135258945Sroberto 136258945Sroberto return (prev); 137258945Sroberto} 138258945Sroberto 139258945Srobertostatic inline void 140258945Srobertoisc_atomic_store(isc_int32_t *p, isc_int32_t val) { 141258945Sroberto isc_int32_t temp; 142258945Sroberto 143258945Sroberto __asm__ volatile( 144258945Sroberto "mb;" 145258945Sroberto "1:" 146258945Sroberto "ldl_l %0, %1;" /* load old value */ 147258945Sroberto "mov %2, %0;" /* value to store */ 148258945Sroberto "stl_c %0, %1;" /* attempt to store */ 149258945Sroberto "beq %0, 1b;" /* if it failed, spin */ 150258945Sroberto "mb;" 151258945Sroberto : "=&r"(temp), "+m"(*p) 152258945Sroberto : "r"(val) 153258945Sroberto : "memory"); 154258945Sroberto} 155258945Sroberto 156258945Srobertostatic inline isc_int32_t 157258945Srobertoisc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { 158258945Sroberto isc_int32_t temp, prev; 159258945Sroberto 160258945Sroberto __asm__ volatile( 161258945Sroberto "mb;" 162258945Sroberto "1:" 163258945Sroberto "ldl_l %0, %1;" /* load old value */ 164258945Sroberto "mov %0, %2;" /* copy the old value */ 165258945Sroberto "cmpeq %0, %3, %0;" /* compare */ 166258945Sroberto "beq %0, 2f;" /* exit if not equal */ 167258945Sroberto "mov %4, %0;" /* value to store */ 168258945Sroberto "stl_c %0, %1;" /* attempt to store */ 169258945Sroberto "beq %0, 1b;" /* if it failed, spin */ 170258945Sroberto "2:" 171258945Sroberto "mb;" 172258945Sroberto : "=&r"(temp), "+m"(*p), "=&r"(prev) 173258945Sroberto : "r"(cmpval), "r"(val) 174258945Sroberto : "memory"); 175258945Sroberto 176258945Sroberto return (prev); 177258945Sroberto} 178258945Sroberto#else 179258945Sroberto 180258945Sroberto#error "unsupported compiler. disable atomic ops by --disable-atomic" 181258945Sroberto 182258945Sroberto#endif 183258945Sroberto 184258945Sroberto#endif /* ISC_ATOMIC_H */ 185