Home | History | Annotate | Line # | Download | only in atomic
atomic_init_testset.c revision 1.10
      1 /*	$NetBSD: atomic_init_testset.c,v 1.10 2014/01/27 18:03:44 matt Exp $	*/
      2 
      3 /*-
      4  * Copyright (c) 2008 The NetBSD Foundation, Inc.
      5  * All rights reserved.
      6  *
      7  * Redistribution and use in source and binary forms, with or without
      8  * modification, are permitted provided that the following conditions
      9  * are met:
     10  * 1. Redistributions of source code must retain the above copyright
     11  *    notice, this list of conditions and the following disclaimer.
     12  * 2. Redistributions in binary form must reproduce the above copyright
     13  *    notice, this list of conditions and the following disclaimer in the
     14  *    documentation and/or other materials provided with the distribution.
     15  *
     16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     26  * POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 /*
     30  * libc glue for atomic operations where the hardware does not provide
     31  * compare-and-swap.  It's assumed that this will only be used on 32-bit
     32  * platforms.
     33  *
     34  * This should be compiled with '-fno-reorder-blocks -fomit-frame-pointer'
     35  * if using gcc.
     36  */
     37 
     38 #include <sys/cdefs.h>
     39 __RCSID("$NetBSD: atomic_init_testset.c,v 1.10 2014/01/27 18:03:44 matt Exp $");
     40 
     41 #include "atomic_op_namespace.h"
     42 
     43 #include <sys/types.h>
     44 #include <sys/atomic.h>
     45 #include <sys/lock.h>
     46 #include <sys/ras.h>
     47 #include <sys/sysctl.h>
     48 
     49 #include <string.h>
     50 
     51 #define	I2	__SIMPLELOCK_UNLOCKED, __SIMPLELOCK_UNLOCKED,
     52 #define	I16	I2 I2 I2 I2 I2 I2 I2 I2
     53 #define	I128	I16 I16 I16 I16 I16 I16 I16 I16
     54 
     55 static __cpu_simple_lock_t atomic_locks[128] = { I128 };
     56 
     57 #ifdef	__HAVE_ASM_ATOMIC_CAS_UP
     58 extern uint32_t _atomic_cas_up(volatile uint32_t *, uint32_t, uint32_t);
     59 #else
     60 static uint32_t _atomic_cas_up(volatile uint32_t *, uint32_t, uint32_t);
     61 #endif
     62 static uint32_t (*_atomic_cas_fn)(volatile uint32_t *, uint32_t, uint32_t) =
     63     _atomic_cas_up;
     64 RAS_DECL(_atomic_cas);
     65 
     66 #ifdef	__HAVE_ASM_ATOMIC_CAS_16_UP
     67 extern uint16_t _atomic_cas_16_up(volatile uint16_t *, uint16_t, uint16_t);
     68 #else
     69 static uint16_t _atomic_cas_16_up(volatile uint16_t *, uint16_t, uint16_t);
     70 #endif
     71 static uint16_t (*_atomic_cas_16_fn)(volatile uint16_t *, uint16_t, uint16_t) =
     72     _atomic_cas_16_up;
     73 RAS_DECL(_atomic_cas_16);
     74 
     75 #ifdef	__HAVE_ASM_ATOMIC_CAS_8_UP
     76 extern uint8_t _atomic_cas_8_up(volatile uint8_t *, uint8_t, uint8_t);
     77 #else
     78 static uint8_t _atomic_cas_8_up(volatile uint8_t *, uint8_t, uint8_t);
     79 #endif
     80 static uint8_t (*_atomic_cas_8_fn)(volatile uint8_t *, uint8_t, uint8_t) =
     81     _atomic_cas_8_up;
     82 RAS_DECL(_atomic_cas_8);
     83 
     84 void	__libc_atomic_init(void) __attribute__ ((visibility("hidden")));
     85 
     86 #ifndef	__HAVE_ASM_ATOMIC_CAS_UP
     87 static uint32_t
     88 _atomic_cas_up(volatile uint32_t *ptr, uint32_t old, uint32_t new)
     89 {
     90 	uint32_t ret;
     91 
     92 	RAS_START(_atomic_cas);
     93 	ret = *ptr;
     94 	if (__predict_false(ret != old)) {
     95 		return ret;
     96 	}
     97 	*ptr = new;
     98 	RAS_END(_atomic_cas);
     99 
    100 	return ret;
    101 }
    102 #endif
    103 
    104 #ifndef	__HAVE_ASM_ATOMIC_CAS_16_UP
    105 static uint16_t
    106 _atomic_cas_up_16(volatile uint16_t *ptr, uint16_t old, uint16_t new)
    107 {
    108 	uint16_t ret;
    109 
    110 	RAS_START(_atomic_cas_16);
    111 	ret = *ptr;
    112 	if (__predict_false(ret != old)) {
    113 		return ret;
    114 	}
    115 	*ptr = new;
    116 	RAS_END(_atomic_cas_16);
    117 
    118 	return ret;
    119 }
    120 #endif
    121 
    122 #ifndef	__HAVE_ASM_ATOMIC_CAS_UP
    123 static uint8_t
    124 _atomic_cas_up(volatile uint8_t *ptr, uint8_t old, uint8_t new)
    125 {
    126 	uint8_t ret;
    127 
    128 	RAS_START(_atomic_cas_8);
    129 	ret = *ptr;
    130 	if (__predict_false(ret != old)) {
    131 		return ret;
    132 	}
    133 	*ptr = new;
    134 	RAS_END(_atomic_cas_16);
    135 
    136 	return ret;
    137 }
    138 #endif
    139 
    140 static uint32_t
    141 _atomic_cas_mp(volatile uint32_t *ptr, uint32_t old, uint32_t new)
    142 {
    143 	__cpu_simple_lock_t *lock;
    144 	uint32_t ret;
    145 
    146 	lock = &atomic_locks[((uintptr_t)ptr >> 3) & 127];
    147 	__cpu_simple_lock(lock);
    148 	ret = *ptr;
    149 	if (__predict_true(ret == old)) {
    150 		*ptr = new;
    151 	}
    152 	__cpu_simple_unlock(lock);
    153 
    154 	return ret;
    155 }
    156 
    157 uint32_t
    158 _atomic_cas_32(volatile uint32_t *ptr, uint32_t old, uint32_t new)
    159 {
    160 
    161 	return (*_atomic_cas_fn)(ptr, old, new);
    162 }
    163 
    164 uint16_t _atomic_cas_16(volatile uint16_t *, uint16_t, uint16_t);
    165 
    166 uint16_t
    167 _atomic_cas_16(volatile uint16_t *ptr, uint16_t old, uint16_t new)
    168 {
    169 
    170 	return (*_atomic_cas_16_fn)(ptr, old, new);
    171 }
    172 
    173 uint8_t _atomic_cas_8(volatile uint8_t *, uint8_t, uint8_t);
    174 
    175 uint8_t
    176 _atomic_cas_8(volatile uint8_t *ptr, uint8_t old, uint8_t new)
    177 {
    178 
    179 	return (*_atomic_cas_8_fn)(ptr, old, new);
    180 }
    181 
    182 void __section(".text.startup")
    183 __libc_atomic_init(void)
    184 {
    185 	int ncpu, mib[2];
    186 	size_t len;
    187 
    188 	_atomic_cas_fn = _atomic_cas_mp;
    189 
    190 	mib[0] = CTL_HW;
    191 	mib[1] = HW_NCPU;
    192 	len = sizeof(ncpu);
    193 	if (sysctl(mib, 2, &ncpu, &len, NULL, 0) == -1)
    194 		return;
    195 	if (ncpu > 1)
    196 		return;
    197 	if (rasctl(RAS_ADDR(_atomic_cas), RAS_SIZE(_atomic_cas),
    198 	    RAS_INSTALL) == 0) {
    199 		_atomic_cas_fn = _atomic_cas_up;
    200 		return;
    201 	}
    202 
    203 	if (rasctl(RAS_ADDR(_atomic_cas_16), RAS_SIZE(_atomic_cas_16),
    204 	    RAS_INSTALL) == 0) {
    205 		_atomic_cas_16_fn = _atomic_cas_16_up;
    206 		return;
    207 	}
    208 
    209 	if (rasctl(RAS_ADDR(_atomic_cas_8), RAS_SIZE(_atomic_cas_8),
    210 	    RAS_INSTALL) == 0) {
    211 		_atomic_cas_8_fn = _atomic_cas_8_up;
    212 		return;
    213 	}
    214 }
    215 
    216 #undef atomic_cas_32
    217 #undef atomic_cas_uint
    218 #undef atomic_cas_ulong
    219 #undef atomic_cas_ptr
    220 #undef atomic_cas_32_ni
    221 #undef atomic_cas_uint_ni
    222 #undef atomic_cas_ulong_ni
    223 #undef atomic_cas_ptr_ni
    224 
    225 atomic_op_alias(atomic_cas_32,_atomic_cas_32)
    226 atomic_op_alias(atomic_cas_uint,_atomic_cas_32)
    227 __strong_alias(_atomic_cas_uint,_atomic_cas_32)
    228 atomic_op_alias(atomic_cas_ulong,_atomic_cas_32)
    229 __strong_alias(_atomic_cas_ulong,_atomic_cas_32)
    230 atomic_op_alias(atomic_cas_ptr,_atomic_cas_32)
    231 __strong_alias(_atomic_cas_ptr,_atomic_cas_32)
    232 
    233 atomic_op_alias(atomic_cas_32_ni,_atomic_cas_32)
    234 __strong_alias(_atomic_cas_32_ni,_atomic_cas_32)
    235 atomic_op_alias(atomic_cas_uint_ni,_atomic_cas_32)
    236 __strong_alias(_atomic_cas_uint_ni,_atomic_cas_32)
    237 atomic_op_alias(atomic_cas_ulong_ni,_atomic_cas_32)
    238 __strong_alias(_atomic_cas_ulong_ni,_atomic_cas_32)
    239 atomic_op_alias(atomic_cas_ptr_ni,_atomic_cas_32)
    240 __strong_alias(_atomic_cas_ptr_ni,_atomic_cas_32)
    241 
    242 __strong_alias(__sync_val_compare_and_swap_4,_atomic_cas_32)
    243 __strong_alias(__sync_val_compare_and_swap_2,_atomic_cas_16)
    244 __strong_alias(__sync_val_compare_and_swap_1,_atomic_cas_8)
    245