00001 /* 00002 * Copyright (C) 2005, 2007, 2009 Internet Systems Consortium, Inc. ("ISC") 00003 * 00004 * Permission to use, copy, modify, and/or distribute this software for any 00005 * purpose with or without fee is hereby granted, provided that the above 00006 * copyright notice and this permission notice appear in all copies. 00007 * 00008 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH 00009 * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY 00010 * AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT, 00011 * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM 00012 * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE 00013 * OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 00014 * PERFORMANCE OF THIS SOFTWARE. 00015 */ 00016 00017 /* $Id: atomic.h,v 1.7 2009/04/08 06:48:23 tbox Exp $ */ 00018 00019 /* 00020 * This code was written based on FreeBSD's kernel source whose copyright 00021 * follows: 00022 */ 00023 00024 /*- 00025 * Copyright (c) 1998 Doug Rabson 00026 * All rights reserved. 00027 * 00028 * Redistribution and use in source and binary forms, with or without 00029 * modification, are permitted provided that the following conditions 00030 * are met: 00031 * 1. Redistributions of source code must retain the above copyright 00032 * notice, this list of conditions and the following disclaimer. 00033 * 2. Redistributions in binary form must reproduce the above copyright 00034 * notice, this list of conditions and the following disclaimer in the 00035 * documentation and/or other materials provided with the distribution. 00036 * 00037 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 00038 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 00039 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 00040 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 00041 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 00042 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 00043 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00044 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 00045 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 00046 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 00047 * SUCH DAMAGE. 00048 * 00049 * $FreeBSD: src/sys/alpha/include/atomic.h,v 1.18.6.1 2004/09/13 21:52:04 wilko Exp $ 00050 */ 00051 00052 #ifndef ISC_ATOMIC_H 00053 #define ISC_ATOMIC_H 1 00054 00055 #include <isc/platform.h> 00056 #include <isc/types.h> 00057 00058 #ifdef ISC_PLATFORM_USEOSFASM 00059 #include <c_asm.h> 00060 00061 #pragma intrinsic(asm) 00062 00063 /* 00064 * This routine atomically increments the value stored in 'p' by 'val', and 00065 * returns the previous value. Memory access ordering around this function 00066 * can be critical, so we add explicit memory block instructions at the 00067 * beginning and the end of it (same for other functions). 00068 */ 00069 static inline isc_int32_t 00070 isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { 00071 return (asm("mb;" 00072 "1:" 00073 "ldl_l %t0, 0(%a0);" /* load old value */ 00074 "mov %t0, %v0;" /* copy the old value */ 00075 "addl %t0, %a1, %t0;" /* calculate new value */ 00076 "stl_c %t0, 0(%a0);" /* attempt to store */ 00077 "beq %t0, 1b;" /* spin if failed */ 00078 "mb;", 00079 p, val)); 00080 } 00081 00082 /* 00083 * This routine atomically stores the value 'val' in 'p'. 00084 */ 00085 static inline void 00086 isc_atomic_store(isc_int32_t *p, isc_int32_t val) { 00087 (void)asm("mb;" 00088 "1:" 00089 "ldl_l %t0, 0(%a0);" /* load old value */ 00090 "mov %a1, %t0;" /* value to store */ 00091 "stl_c %t0, 0(%a0);" /* attempt to store */ 00092 "beq %t0, 1b;" /* spin if failed */ 00093 "mb;", 00094 p, val); 00095 } 00096 00097 /* 00098 * This routine atomically replaces the value in 'p' with 'val', if the 00099 * original value is equal to 'cmpval'. The original value is returned in any 00100 * case. 00101 */ 00102 static inline isc_int32_t 00103 isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { 00104 00105 return(asm("mb;" 00106 "1:" 00107 "ldl_l %t0, 0(%a0);" /* load old value */ 00108 "mov %t0, %v0;" /* copy the old value */ 00109 "cmpeq %t0, %a1, %t0;" /* compare */ 00110 "beq %t0, 2f;" /* exit if not equal */ 00111 "mov %a2, %t0;" /* value to store */ 00112 "stl_c %t0, 0(%a0);" /* attempt to store */ 00113 "beq %t0, 1b;" /* if it failed, spin */ 00114 "2:" 00115 "mb;", 00116 p, cmpval, val)); 00117 } 00118 #elif defined (ISC_PLATFORM_USEGCCASM) 00119 static inline isc_int32_t 00120 isc_atomic_xadd(isc_int32_t *p, isc_int32_t val) { 00121 isc_int32_t temp, prev; 00122 00123 __asm__ volatile( 00124 "mb;" 00125 "1:" 00126 "ldl_l %0, %1;" /* load old value */ 00127 "mov %0, %2;" /* copy the old value */ 00128 "addl %0, %3, %0;" /* calculate new value */ 00129 "stl_c %0, %1;" /* attempt to store */ 00130 "beq %0, 1b;" /* spin if failed */ 00131 "mb;" 00132 : "=&r"(temp), "+m"(*p), "=&r"(prev) 00133 : "r"(val) 00134 : "memory"); 00135 00136 return (prev); 00137 } 00138 00139 static inline void 00140 isc_atomic_store(isc_int32_t *p, isc_int32_t val) { 00141 isc_int32_t temp; 00142 00143 __asm__ volatile( 00144 "mb;" 00145 "1:" 00146 "ldl_l %0, %1;" /* load old value */ 00147 "mov %2, %0;" /* value to store */ 00148 "stl_c %0, %1;" /* attempt to store */ 00149 "beq %0, 1b;" /* if it failed, spin */ 00150 "mb;" 00151 : "=&r"(temp), "+m"(*p) 00152 : "r"(val) 00153 : "memory"); 00154 } 00155 00156 static inline isc_int32_t 00157 isc_atomic_cmpxchg(isc_int32_t *p, isc_int32_t cmpval, isc_int32_t val) { 00158 isc_int32_t temp, prev; 00159 00160 __asm__ volatile( 00161 "mb;" 00162 "1:" 00163 "ldl_l %0, %1;" /* load old value */ 00164 "mov %0, %2;" /* copy the old value */ 00165 "cmpeq %0, %3, %0;" /* compare */ 00166 "beq %0, 2f;" /* exit if not equal */ 00167 "mov %4, %0;" /* value to store */ 00168 "stl_c %0, %1;" /* attempt to store */ 00169 "beq %0, 1b;" /* if it failed, spin */ 00170 "2:" 00171 "mb;" 00172 : "=&r"(temp), "+m"(*p), "=&r"(prev) 00173 : "r"(cmpval), "r"(val) 00174 : "memory"); 00175 00176 return (prev); 00177 } 00178 #else 00179 00180 #error "unsupported compiler. disable atomic ops by --disable-atomic" 00181 00182 #endif 00183 00184 #endif /* ISC_ATOMIC_H */