/*
* Copyright (c) 2018 Agustina Arzille.
* Copyright (c) 2018 Richard Braun.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
*
* CPU-local atomic operations.
*
* The latomic module provides operations that are "atomic on the local
* processor", i.e. interrupt-safe. Its interface is similar in spirit
* and purpose to that of the atomic module, and it can transparently
* replace it on single-processor configurations.
*
* Note that the only operations guaranteed to be truely atomic, i.e.
* to completely execute in a single atomic instruction, are loads and
* stores. All other operations may be implemented with multiple
* instructions, possibly disabling interrupts. The rationale is that
* atomic loads and stores are required for some types of access, such
* as memory-mapped device registers, while other operations only require
* interrupt safety.
*
* Also note that interrupts are considered to strictly match the definition
* of signals as described in the specification of program execution in
* the C language. This defines the forms of communication allowed with
* interrupts handlers.
*
* This header provides a generic implementation. Architectures can
* individually override any of the operations provided by this module.
*/
#ifndef KERN_LATOMIC_H
#define KERN_LATOMIC_H
#include
#include
/*
* Memory orders for local atomic operations.
*
* These work like those in the atomic module, but are implemented
* with simple compiler barriers instead of full memory fences.
*/
#define LATOMIC_RELAXED __ATOMIC_RELAXED
#define LATOMIC_ACQUIRE __ATOMIC_ACQUIRE
#define LATOMIC_RELEASE __ATOMIC_RELEASE
#define LATOMIC_ACQ_REL __ATOMIC_ACQ_REL
#define LATOMIC_SEQ_CST __ATOMIC_SEQ_CST
#include
#define latomic_load(ptr, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
((typeof(*(ptr)))latomic_select(ptr, load)(ptr, memorder)); \
MACRO_END
#define latomic_store(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
latomic_select(ptr, store)(ptr, val, memorder); \
MACRO_END
#define latomic_swap(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
((typeof(*(ptr)))latomic_select(ptr, swap)(ptr, val, memorder)); \
MACRO_END
#define latomic_cas(ptr, oval, nval, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
((typeof(*(ptr)))latomic_select(ptr, cas)(ptr, oval, nval, memorder)); \
MACRO_END
#define latomic_fetch_add(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
((typeof(*(ptr)))latomic_select(ptr, fetch_add)(ptr, val, memorder)); \
MACRO_END
#define latomic_fetch_sub(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
((typeof(*(ptr)))latomic_select(ptr, fetch_sub)(ptr, val, memorder)); \
MACRO_END
#define latomic_fetch_and(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
((typeof(*(ptr)))latomic_select(ptr, fetch_and)(ptr, val, memorder)); \
MACRO_END
#define latomic_fetch_or(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
((typeof(*(ptr)))latomic_select(ptr, fetch_or)(ptr, val, memorder)); \
MACRO_END
#define latomic_fetch_xor(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
((typeof(*(ptr)))latomic_select(ptr, fetch_xor)(ptr, val, memorder)); \
MACRO_END
#define latomic_add(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
latomic_select(ptr, add)(ptr, val, memorder); \
MACRO_END
#define latomic_sub(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
latomic_select(ptr, sub)(ptr, val, memorder); \
MACRO_END
#define latomic_and(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
latomic_select(ptr, and)(ptr, val, memorder); \
MACRO_END
#define latomic_or(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
latomic_select(ptr, or)(ptr, val, memorder); \
MACRO_END
#define latomic_xor(ptr, val, memorder) \
MACRO_BEGIN \
assert(latomic_ptr_aligned(ptr)); \
latomic_select(ptr, xor)(ptr, val, memorder); \
MACRO_END
#define latomic_fence(memorder) __atomic_signal_fence(memorder)
#endif /* KERN_LATOMIC_H */