Path: blob/main/sys/contrib/openzfs/lib/libspl/include/atomic.h
48406 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 (the "License").6* You may not use this file except in compliance with the License.7*8* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE9* or https://opensource.org/licenses/CDDL-1.0.10* See the License for the specific language governing permissions11* and limitations under the License.12*13* When distributing Covered Code, include this CDDL HEADER in each14* file and include the License file at usr/src/OPENSOLARIS.LICENSE.15* If applicable, add the following below this CDDL HEADER, with the16* fields enclosed by brackets "[]" replaced with your own identifying17* information: Portions Copyright [yyyy] [name of copyright owner]18*19* CDDL HEADER END20*/2122/*23* Copyright 2005 Sun Microsystems, Inc. All rights reserved.24* Use is subject to license terms.25*/2627#ifndef _SYS_ATOMIC_H28#define _SYS_ATOMIC_H2930#include <sys/types.h>31#include <sys/inttypes.h>3233#ifdef __cplusplus34extern "C" {35#endif3637#if defined(__STDC__)38/*39* Increment target.40*/41extern void atomic_inc_8(volatile uint8_t *);42extern void atomic_inc_uchar(volatile uchar_t *);43extern void atomic_inc_16(volatile uint16_t *);44extern void atomic_inc_ushort(volatile ushort_t *);45extern void atomic_inc_32(volatile uint32_t *);46extern void atomic_inc_uint(volatile uint_t *);47extern void atomic_inc_ulong(volatile ulong_t *);48#if defined(_INT64_TYPE)49extern void atomic_inc_64(volatile uint64_t *);50#endif5152/*53* Decrement target54*/55extern void atomic_dec_8(volatile uint8_t *);56extern void atomic_dec_uchar(volatile uchar_t *);57extern void atomic_dec_16(volatile uint16_t *);58extern void atomic_dec_ushort(volatile ushort_t *);59extern void atomic_dec_32(volatile uint32_t *);60extern void atomic_dec_uint(volatile uint_t *);61extern void atomic_dec_ulong(volatile ulong_t *);62#if defined(_INT64_TYPE)63extern void atomic_dec_64(volatile uint64_t *);64#endif6566/*67* Add delta to target68*/69extern void atomic_add_8(volatile uint8_t *, int8_t);70extern void atomic_add_char(volatile uchar_t *, signed char);71extern void atomic_add_16(volatile uint16_t *, int16_t);72extern void atomic_add_short(volatile ushort_t *, short);73extern void atomic_add_32(volatile uint32_t *, int32_t);74extern void atomic_add_int(volatile uint_t *, int);75extern void atomic_add_ptr(volatile void *, ssize_t);76extern void atomic_add_long(volatile ulong_t *, long);77#if defined(_INT64_TYPE)78extern void atomic_add_64(volatile uint64_t *, int64_t);79#endif8081/*82* Subtract delta from target83*/84extern void atomic_sub_8(volatile uint8_t *, int8_t);85extern void atomic_sub_char(volatile uchar_t *, signed char);86extern void atomic_sub_16(volatile uint16_t *, int16_t);87extern void atomic_sub_short(volatile ushort_t *, short);88extern void atomic_sub_32(volatile uint32_t *, int32_t);89extern void atomic_sub_int(volatile uint_t *, int);90extern void atomic_sub_ptr(volatile void *, ssize_t);91extern void atomic_sub_long(volatile ulong_t *, long);92#if defined(_INT64_TYPE)93extern void atomic_sub_64(volatile uint64_t *, int64_t);94#endif9596/*97* logical OR bits with target98*/99extern void atomic_or_8(volatile uint8_t *, uint8_t);100extern void atomic_or_uchar(volatile uchar_t *, uchar_t);101extern void atomic_or_16(volatile uint16_t *, uint16_t);102extern void atomic_or_ushort(volatile ushort_t *, ushort_t);103extern void atomic_or_32(volatile uint32_t *, uint32_t);104extern void atomic_or_uint(volatile uint_t *, uint_t);105extern void atomic_or_ulong(volatile ulong_t *, ulong_t);106#if defined(_INT64_TYPE)107extern void atomic_or_64(volatile uint64_t *, uint64_t);108#endif109110/*111* logical AND bits with target112*/113extern void atomic_and_8(volatile uint8_t *, uint8_t);114extern void atomic_and_uchar(volatile uchar_t *, uchar_t);115extern void atomic_and_16(volatile uint16_t *, uint16_t);116extern void atomic_and_ushort(volatile ushort_t *, ushort_t);117extern void atomic_and_32(volatile uint32_t *, uint32_t);118extern void atomic_and_uint(volatile uint_t *, uint_t);119extern void atomic_and_ulong(volatile ulong_t *, ulong_t);120#if defined(_INT64_TYPE)121extern void atomic_and_64(volatile uint64_t *, uint64_t);122#endif123124/*125* As above, but return the new value. Note that these _nv() variants are126* substantially more expensive on some platforms than the no-return-value127* versions above, so don't use them unless you really need to know the128* new value *atomically* (e.g. when decrementing a reference count and129* checking whether it went to zero).130*/131132/*133* Increment target and return new value.134*/135extern uint8_t atomic_inc_8_nv(volatile uint8_t *);136extern uchar_t atomic_inc_uchar_nv(volatile uchar_t *);137extern uint16_t atomic_inc_16_nv(volatile uint16_t *);138extern ushort_t atomic_inc_ushort_nv(volatile ushort_t *);139extern uint32_t atomic_inc_32_nv(volatile uint32_t *);140extern uint_t atomic_inc_uint_nv(volatile uint_t *);141extern ulong_t atomic_inc_ulong_nv(volatile ulong_t *);142#if defined(_INT64_TYPE)143extern uint64_t atomic_inc_64_nv(volatile uint64_t *);144#endif145146/*147* Decrement target and return new value.148*/149extern uint8_t atomic_dec_8_nv(volatile uint8_t *);150extern uchar_t atomic_dec_uchar_nv(volatile uchar_t *);151extern uint16_t atomic_dec_16_nv(volatile uint16_t *);152extern ushort_t atomic_dec_ushort_nv(volatile ushort_t *);153extern uint32_t atomic_dec_32_nv(volatile uint32_t *);154extern uint_t atomic_dec_uint_nv(volatile uint_t *);155extern ulong_t atomic_dec_ulong_nv(volatile ulong_t *);156#if defined(_INT64_TYPE)157extern uint64_t atomic_dec_64_nv(volatile uint64_t *);158#endif159160/*161* Add delta to target162*/163extern uint8_t atomic_add_8_nv(volatile uint8_t *, int8_t);164extern uchar_t atomic_add_char_nv(volatile uchar_t *, signed char);165extern uint16_t atomic_add_16_nv(volatile uint16_t *, int16_t);166extern ushort_t atomic_add_short_nv(volatile ushort_t *, short);167extern uint32_t atomic_add_32_nv(volatile uint32_t *, int32_t);168extern uint_t atomic_add_int_nv(volatile uint_t *, int);169extern void *atomic_add_ptr_nv(volatile void *, ssize_t);170extern ulong_t atomic_add_long_nv(volatile ulong_t *, long);171#if defined(_INT64_TYPE)172extern uint64_t atomic_add_64_nv(volatile uint64_t *, int64_t);173#endif174175/*176* Subtract delta from target177*/178extern uint8_t atomic_sub_8_nv(volatile uint8_t *, int8_t);179extern uchar_t atomic_sub_char_nv(volatile uchar_t *, signed char);180extern uint16_t atomic_sub_16_nv(volatile uint16_t *, int16_t);181extern ushort_t atomic_sub_short_nv(volatile ushort_t *, short);182extern uint32_t atomic_sub_32_nv(volatile uint32_t *, int32_t);183extern uint_t atomic_sub_int_nv(volatile uint_t *, int);184extern void *atomic_sub_ptr_nv(volatile void *, ssize_t);185extern ulong_t atomic_sub_long_nv(volatile ulong_t *, long);186#if defined(_INT64_TYPE)187extern uint64_t atomic_sub_64_nv(volatile uint64_t *, int64_t);188#endif189190/*191* logical OR bits with target and return new value.192*/193extern uint8_t atomic_or_8_nv(volatile uint8_t *, uint8_t);194extern uchar_t atomic_or_uchar_nv(volatile uchar_t *, uchar_t);195extern uint16_t atomic_or_16_nv(volatile uint16_t *, uint16_t);196extern ushort_t atomic_or_ushort_nv(volatile ushort_t *, ushort_t);197extern uint32_t atomic_or_32_nv(volatile uint32_t *, uint32_t);198extern uint_t atomic_or_uint_nv(volatile uint_t *, uint_t);199extern ulong_t atomic_or_ulong_nv(volatile ulong_t *, ulong_t);200#if defined(_INT64_TYPE)201extern uint64_t atomic_or_64_nv(volatile uint64_t *, uint64_t);202#endif203204/*205* logical AND bits with target and return new value.206*/207extern uint8_t atomic_and_8_nv(volatile uint8_t *, uint8_t);208extern uchar_t atomic_and_uchar_nv(volatile uchar_t *, uchar_t);209extern uint16_t atomic_and_16_nv(volatile uint16_t *, uint16_t);210extern ushort_t atomic_and_ushort_nv(volatile ushort_t *, ushort_t);211extern uint32_t atomic_and_32_nv(volatile uint32_t *, uint32_t);212extern uint_t atomic_and_uint_nv(volatile uint_t *, uint_t);213extern ulong_t atomic_and_ulong_nv(volatile ulong_t *, ulong_t);214#if defined(_INT64_TYPE)215extern uint64_t atomic_and_64_nv(volatile uint64_t *, uint64_t);216#endif217218/*219* If *arg1 == arg2, set *arg1 = arg3; return old value220*/221extern uint8_t atomic_cas_8(volatile uint8_t *, uint8_t, uint8_t);222extern uchar_t atomic_cas_uchar(volatile uchar_t *, uchar_t, uchar_t);223extern uint16_t atomic_cas_16(volatile uint16_t *, uint16_t, uint16_t);224extern ushort_t atomic_cas_ushort(volatile ushort_t *, ushort_t, ushort_t);225extern uint32_t atomic_cas_32(volatile uint32_t *, uint32_t, uint32_t);226extern uint_t atomic_cas_uint(volatile uint_t *, uint_t, uint_t);227extern void *atomic_cas_ptr(volatile void *, void *, void *);228extern ulong_t atomic_cas_ulong(volatile ulong_t *, ulong_t, ulong_t);229#if defined(_INT64_TYPE)230extern uint64_t atomic_cas_64(volatile uint64_t *, uint64_t, uint64_t);231#endif232233/*234* Swap target and return old value235*/236extern uint8_t atomic_swap_8(volatile uint8_t *, uint8_t);237extern uchar_t atomic_swap_uchar(volatile uchar_t *, uchar_t);238extern uint16_t atomic_swap_16(volatile uint16_t *, uint16_t);239extern ushort_t atomic_swap_ushort(volatile ushort_t *, ushort_t);240extern uint32_t atomic_swap_32(volatile uint32_t *, uint32_t);241extern uint_t atomic_swap_uint(volatile uint_t *, uint_t);242extern void *atomic_swap_ptr(volatile void *, void *);243extern ulong_t atomic_swap_ulong(volatile ulong_t *, ulong_t);244#if defined(_INT64_TYPE)245extern uint64_t atomic_swap_64(volatile uint64_t *, uint64_t);246#endif247248/*249* Atomically read variable.250*/251#define atomic_load_char(p) (*(volatile uchar_t *)(p))252#define atomic_load_short(p) (*(volatile ushort_t *)(p))253#define atomic_load_int(p) (*(volatile uint_t *)(p))254#define atomic_load_long(p) (*(volatile ulong_t *)(p))255#define atomic_load_ptr(p) (*(volatile __typeof(*p) *)(p))256#define atomic_load_8(p) (*(volatile uint8_t *)(p))257#define atomic_load_16(p) (*(volatile uint16_t *)(p))258#define atomic_load_32(p) (*(volatile uint32_t *)(p))259#ifdef _LP64260#define atomic_load_64(p) (*(volatile uint64_t *)(p))261#elif defined(_INT64_TYPE)262extern uint64_t atomic_load_64(volatile uint64_t *);263#endif264265/*266* Atomically write variable.267*/268#define atomic_store_char(p, v) \269(*(volatile uchar_t *)(p) = (uchar_t)(v))270#define atomic_store_short(p, v) \271(*(volatile ushort_t *)(p) = (ushort_t)(v))272#define atomic_store_int(p, v) \273(*(volatile uint_t *)(p) = (uint_t)(v))274#define atomic_store_long(p, v) \275(*(volatile ulong_t *)(p) = (ulong_t)(v))276#define atomic_store_ptr(p, v) \277(*(volatile __typeof(*p) *)(p) = (v))278#define atomic_store_8(p, v) \279(*(volatile uint8_t *)(p) = (uint8_t)(v))280#define atomic_store_16(p, v) \281(*(volatile uint16_t *)(p) = (uint16_t)(v))282#define atomic_store_32(p, v) \283(*(volatile uint32_t *)(p) = (uint32_t)(v))284#ifdef _LP64285#define atomic_store_64(p, v) \286(*(volatile uint64_t *)(p) = (uint64_t)(v))287#elif defined(_INT64_TYPE)288extern void atomic_store_64(volatile uint64_t *, uint64_t);289#endif290291/*292* Perform an exclusive atomic bit set/clear on a target.293* Returns 0 if bit was successfully set/cleared, or -1294* if the bit was already set/cleared.295*/296extern int atomic_set_long_excl(volatile ulong_t *, uint_t);297extern int atomic_clear_long_excl(volatile ulong_t *, uint_t);298299/*300* Generic memory barrier used during lock entry, placed after the301* memory operation that acquires the lock to guarantee that the lock302* protects its data. No stores from after the memory barrier will303* reach visibility, and no loads from after the barrier will be304* resolved, before the lock acquisition reaches global visibility.305*/306extern void membar_enter(void);307308/*309* Generic memory barrier used during lock exit, placed before the310* memory operation that releases the lock to guarantee that the lock311* protects its data. All loads and stores issued before the barrier312* will be resolved before the subsequent lock update reaches visibility.313*/314extern void membar_exit(void);315316/*317* Make all stores and loads emitted prior to the the barrier complete before318* crossing it, while also making sure stores and loads emitted after the319* barrier only start being executed after crossing it.320*/321extern void membar_sync(void);322323/*324* Arrange that all stores issued before this point in the code reach325* global visibility before any stores that follow; useful in producer326* modules that update a data item, then set a flag that it is available.327* The memory barrier guarantees that the available flag is not visible328* earlier than the updated data, i.e. it imposes store ordering.329*/330extern void membar_producer(void);331332/*333* Arrange that all loads issued before this point in the code are334* completed before any subsequent loads; useful in consumer modules335* that check to see if data is available and read the data.336* The memory barrier guarantees that the data is not sampled until337* after the available flag has been seen, i.e. it imposes load ordering.338*/339extern void membar_consumer(void);340#endif /* __STDC__ */341342#ifdef __cplusplus343}344#endif345346#endif /* _SYS_ATOMIC_H */347348349