Path: blob/main/sys/contrib/openzfs/lib/libspl/atomic.c
48378 views
// SPDX-License-Identifier: CDDL-1.01/*2* CDDL HEADER START3*4* The contents of this file are subject to the terms of the5* Common Development and Distribution License, Version 1.0 only6* (the "License"). You may not use this file except in compliance7* with the License.8*9* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE10* or https://opensource.org/licenses/CDDL-1.0.11* See the License for the specific language governing permissions12* and limitations under the License.13*14* When distributing Covered Code, include this CDDL HEADER in each15* file and include the License file at usr/src/OPENSOLARIS.LICENSE.16* If applicable, add the following below this CDDL HEADER, with the17* fields enclosed by brackets "[]" replaced with your own identifying18* information: Portions Copyright [yyyy] [name of copyright owner]19*20* CDDL HEADER END21*/22/*23* Copyright (c) 2009 by Sun Microsystems, Inc. All rights reserved.24* Use is subject to license terms.25*/2627#include <atomic.h>2829/*30* These are the void returning variants31*/32#define ATOMIC_INC(name, type) \33void atomic_inc_##name(volatile type *target) \34{ \35(void) __atomic_add_fetch(target, 1, __ATOMIC_SEQ_CST); \36}3738ATOMIC_INC(8, uint8_t)39ATOMIC_INC(16, uint16_t)40ATOMIC_INC(32, uint32_t)41ATOMIC_INC(64, uint64_t)42ATOMIC_INC(uchar, uchar_t)43ATOMIC_INC(ushort, ushort_t)44ATOMIC_INC(uint, uint_t)45ATOMIC_INC(ulong, ulong_t)464748#define ATOMIC_DEC(name, type) \49void atomic_dec_##name(volatile type *target) \50{ \51(void) __atomic_sub_fetch(target, 1, __ATOMIC_SEQ_CST); \52}5354ATOMIC_DEC(8, uint8_t)55ATOMIC_DEC(16, uint16_t)56ATOMIC_DEC(32, uint32_t)57ATOMIC_DEC(64, uint64_t)58ATOMIC_DEC(uchar, uchar_t)59ATOMIC_DEC(ushort, ushort_t)60ATOMIC_DEC(uint, uint_t)61ATOMIC_DEC(ulong, ulong_t)626364#define ATOMIC_ADD(name, type1, type2) \65void atomic_add_##name(volatile type1 *target, type2 bits) \66{ \67(void) __atomic_add_fetch(target, bits, __ATOMIC_SEQ_CST); \68}6970void71atomic_add_ptr(volatile void *target, ssize_t bits)72{73(void) __atomic_add_fetch((void **)target, bits, __ATOMIC_SEQ_CST);74}7576ATOMIC_ADD(8, uint8_t, int8_t)77ATOMIC_ADD(16, uint16_t, int16_t)78ATOMIC_ADD(32, uint32_t, int32_t)79ATOMIC_ADD(64, uint64_t, int64_t)80ATOMIC_ADD(char, uchar_t, signed char)81ATOMIC_ADD(short, ushort_t, short)82ATOMIC_ADD(int, uint_t, int)83ATOMIC_ADD(long, ulong_t, long)848586#define ATOMIC_SUB(name, type1, type2) \87void atomic_sub_##name(volatile type1 *target, type2 bits) \88{ \89(void) __atomic_sub_fetch(target, bits, __ATOMIC_SEQ_CST); \90}9192void93atomic_sub_ptr(volatile void *target, ssize_t bits)94{95(void) __atomic_sub_fetch((void **)target, bits, __ATOMIC_SEQ_CST);96}9798ATOMIC_SUB(8, uint8_t, int8_t)99ATOMIC_SUB(16, uint16_t, int16_t)100ATOMIC_SUB(32, uint32_t, int32_t)101ATOMIC_SUB(64, uint64_t, int64_t)102ATOMIC_SUB(char, uchar_t, signed char)103ATOMIC_SUB(short, ushort_t, short)104ATOMIC_SUB(int, uint_t, int)105ATOMIC_SUB(long, ulong_t, long)106107108#define ATOMIC_OR(name, type) \109void atomic_or_##name(volatile type *target, type bits) \110{ \111(void) __atomic_or_fetch(target, bits, __ATOMIC_SEQ_CST); \112}113114ATOMIC_OR(8, uint8_t)115ATOMIC_OR(16, uint16_t)116ATOMIC_OR(32, uint32_t)117ATOMIC_OR(64, uint64_t)118ATOMIC_OR(uchar, uchar_t)119ATOMIC_OR(ushort, ushort_t)120ATOMIC_OR(uint, uint_t)121ATOMIC_OR(ulong, ulong_t)122123124#define ATOMIC_AND(name, type) \125void atomic_and_##name(volatile type *target, type bits) \126{ \127(void) __atomic_and_fetch(target, bits, __ATOMIC_SEQ_CST); \128}129130ATOMIC_AND(8, uint8_t)131ATOMIC_AND(16, uint16_t)132ATOMIC_AND(32, uint32_t)133ATOMIC_AND(64, uint64_t)134ATOMIC_AND(uchar, uchar_t)135ATOMIC_AND(ushort, ushort_t)136ATOMIC_AND(uint, uint_t)137ATOMIC_AND(ulong, ulong_t)138139140/*141* New value returning variants142*/143144#define ATOMIC_INC_NV(name, type) \145type atomic_inc_##name##_nv(volatile type *target) \146{ \147return (__atomic_add_fetch(target, 1, __ATOMIC_SEQ_CST)); \148}149150ATOMIC_INC_NV(8, uint8_t)151ATOMIC_INC_NV(16, uint16_t)152ATOMIC_INC_NV(32, uint32_t)153ATOMIC_INC_NV(64, uint64_t)154ATOMIC_INC_NV(uchar, uchar_t)155ATOMIC_INC_NV(ushort, ushort_t)156ATOMIC_INC_NV(uint, uint_t)157ATOMIC_INC_NV(ulong, ulong_t)158159160#define ATOMIC_DEC_NV(name, type) \161type atomic_dec_##name##_nv(volatile type *target) \162{ \163return (__atomic_sub_fetch(target, 1, __ATOMIC_SEQ_CST)); \164}165166ATOMIC_DEC_NV(8, uint8_t)167ATOMIC_DEC_NV(16, uint16_t)168ATOMIC_DEC_NV(32, uint32_t)169ATOMIC_DEC_NV(64, uint64_t)170ATOMIC_DEC_NV(uchar, uchar_t)171ATOMIC_DEC_NV(ushort, ushort_t)172ATOMIC_DEC_NV(uint, uint_t)173ATOMIC_DEC_NV(ulong, ulong_t)174175176#define ATOMIC_ADD_NV(name, type1, type2) \177type1 atomic_add_##name##_nv(volatile type1 *target, type2 bits) \178{ \179return (__atomic_add_fetch(target, bits, __ATOMIC_SEQ_CST)); \180}181182void *183atomic_add_ptr_nv(volatile void *target, ssize_t bits)184{185return (__atomic_add_fetch((void **)target, bits, __ATOMIC_SEQ_CST));186}187188ATOMIC_ADD_NV(8, uint8_t, int8_t)189ATOMIC_ADD_NV(16, uint16_t, int16_t)190ATOMIC_ADD_NV(32, uint32_t, int32_t)191ATOMIC_ADD_NV(64, uint64_t, int64_t)192ATOMIC_ADD_NV(char, uchar_t, signed char)193ATOMIC_ADD_NV(short, ushort_t, short)194ATOMIC_ADD_NV(int, uint_t, int)195ATOMIC_ADD_NV(long, ulong_t, long)196197198#define ATOMIC_SUB_NV(name, type1, type2) \199type1 atomic_sub_##name##_nv(volatile type1 *target, type2 bits) \200{ \201return (__atomic_sub_fetch(target, bits, __ATOMIC_SEQ_CST)); \202}203204void *205atomic_sub_ptr_nv(volatile void *target, ssize_t bits)206{207return (__atomic_sub_fetch((void **)target, bits, __ATOMIC_SEQ_CST));208}209210ATOMIC_SUB_NV(8, uint8_t, int8_t)211ATOMIC_SUB_NV(char, uchar_t, signed char)212ATOMIC_SUB_NV(16, uint16_t, int16_t)213ATOMIC_SUB_NV(short, ushort_t, short)214ATOMIC_SUB_NV(32, uint32_t, int32_t)215ATOMIC_SUB_NV(int, uint_t, int)216ATOMIC_SUB_NV(long, ulong_t, long)217ATOMIC_SUB_NV(64, uint64_t, int64_t)218219220#define ATOMIC_OR_NV(name, type) \221type atomic_or_##name##_nv(volatile type *target, type bits) \222{ \223return (__atomic_or_fetch(target, bits, __ATOMIC_SEQ_CST)); \224}225226ATOMIC_OR_NV(8, uint8_t)227ATOMIC_OR_NV(16, uint16_t)228ATOMIC_OR_NV(32, uint32_t)229ATOMIC_OR_NV(64, uint64_t)230ATOMIC_OR_NV(uchar, uchar_t)231ATOMIC_OR_NV(ushort, ushort_t)232ATOMIC_OR_NV(uint, uint_t)233ATOMIC_OR_NV(ulong, ulong_t)234235236#define ATOMIC_AND_NV(name, type) \237type atomic_and_##name##_nv(volatile type *target, type bits) \238{ \239return (__atomic_and_fetch(target, bits, __ATOMIC_SEQ_CST)); \240}241242ATOMIC_AND_NV(8, uint8_t)243ATOMIC_AND_NV(16, uint16_t)244ATOMIC_AND_NV(32, uint32_t)245ATOMIC_AND_NV(64, uint64_t)246ATOMIC_AND_NV(uchar, uchar_t)247ATOMIC_AND_NV(ushort, ushort_t)248ATOMIC_AND_NV(uint, uint_t)249ATOMIC_AND_NV(ulong, ulong_t)250251252/*253* If *tgt == exp, set *tgt = des; return old value254*255* This may not look right on the first pass (or the sixteenth), but,256* from https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html:257* > If they are not equal, the operation is a read258* > and the current contents of *ptr are written into *expected.259* And, in the converse case, exp is already *target by definition.260*/261262#define ATOMIC_CAS(name, type) \263type atomic_cas_##name(volatile type *target, type exp, type des) \264{ \265__atomic_compare_exchange_n(target, &exp, des, B_FALSE, \266__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST); \267return (exp); \268}269270void *271atomic_cas_ptr(volatile void *target, void *exp, void *des)272{273274__atomic_compare_exchange_n((void **)target, &exp, des, B_FALSE,275__ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST);276return (exp);277}278279ATOMIC_CAS(8, uint8_t)280ATOMIC_CAS(16, uint16_t)281ATOMIC_CAS(32, uint32_t)282ATOMIC_CAS(64, uint64_t)283ATOMIC_CAS(uchar, uchar_t)284ATOMIC_CAS(ushort, ushort_t)285ATOMIC_CAS(uint, uint_t)286ATOMIC_CAS(ulong, ulong_t)287288289/*290* Swap target and return old value291*/292293#define ATOMIC_SWAP(name, type) \294type atomic_swap_##name(volatile type *target, type bits) \295{ \296return (__atomic_exchange_n(target, bits, __ATOMIC_SEQ_CST)); \297}298299ATOMIC_SWAP(8, uint8_t)300ATOMIC_SWAP(16, uint16_t)301ATOMIC_SWAP(32, uint32_t)302ATOMIC_SWAP(64, uint64_t)303ATOMIC_SWAP(uchar, uchar_t)304ATOMIC_SWAP(ushort, ushort_t)305ATOMIC_SWAP(uint, uint_t)306ATOMIC_SWAP(ulong, ulong_t)307308void *309atomic_swap_ptr(volatile void *target, void *bits)310{311return (__atomic_exchange_n((void **)target, bits, __ATOMIC_SEQ_CST));312}313314#ifndef _LP64315uint64_t316atomic_load_64(volatile uint64_t *target)317{318return (__atomic_load_n(target, __ATOMIC_RELAXED));319}320321void322atomic_store_64(volatile uint64_t *target, uint64_t bits)323{324return (__atomic_store_n(target, bits, __ATOMIC_RELAXED));325}326#endif327328int329atomic_set_long_excl(volatile ulong_t *target, uint_t value)330{331ulong_t bit = 1UL << value;332ulong_t old = __atomic_fetch_or(target, bit, __ATOMIC_SEQ_CST);333return ((old & bit) ? -1 : 0);334}335336int337atomic_clear_long_excl(volatile ulong_t *target, uint_t value)338{339ulong_t bit = 1UL << value;340ulong_t old = __atomic_fetch_and(target, ~bit, __ATOMIC_SEQ_CST);341return ((old & bit) ? 0 : -1);342}343344void345membar_enter(void)346{347__atomic_thread_fence(__ATOMIC_SEQ_CST);348}349350void351membar_exit(void)352{353__atomic_thread_fence(__ATOMIC_SEQ_CST);354}355356void357membar_sync(void)358{359__atomic_thread_fence(__ATOMIC_SEQ_CST);360}361362void363membar_producer(void)364{365__atomic_thread_fence(__ATOMIC_RELEASE);366}367368void369membar_consumer(void)370{371__atomic_thread_fence(__ATOMIC_ACQUIRE);372}373374375