/*
 * Copyright (C) Huawei Technologies Co., Ltd. 2023-2024. All rights reserved.
 * SPDX-License-Identifier: MIT
 */

#ifndef VATOMIC_CORE_H
#define VATOMIC_CORE_H
/*******************************************************************************
 * @file core.h
 * @brief Atomic types, core atomic operations and fences.
 *
 * This file is the main entry point of VSync atomics. You can include it with:
 *
 * ```c
 * #include <vsync/atomic/core.h>
 * ```
 *
 * The declaration and documentation of most atomic operations is split into
 * files based on the atomic type operated by the function as follows:
 *
 * | File            | Type                       |
 * | --------------- | -------------------------- |
 * | @ref core_u8.h  | vatomic8_t and vuint8_t    |
 * | @ref core_u16.h | vatomic16_t and vuint16_t  |
 * | @ref core_u32.h | vatomic32_t and vuint32_t  |
 * | @ref core_u64.h | vatomic64_t and vuint64_t  |
 * | @ref core_sz.h  | vatomicsz_t and vsize_t    |
 * | @ref core_ptr.h | vatomicptr_t and void *    |
 *
 * Major configuration options are described in @ref config.h.
 *
 ******************************************************************************/
/* !!!Warning: File generated by tmplr; DO NOT EDIT.!!! */
#include <vsync/atomic/config.h>

/* *****************************************************************************
 * Basic atomic types
 * ****************************************************************************/
#include <vsync/atomic/internal/types.h>

/*******************************************************************************
 * @def VATOMIC_INIT(v)
 * @brief Initializes an atomic variable with value v.
 ******************************************************************************/
#define VATOMIC_INIT(v)                                                        \
    {                                                                          \
        ._v = v                                                                \
    }

/*******************************************************************************
 * @def vatomicptr(T)
 * @brief Declares an atomic pointer type.
 *
 * When declaring an atomic pointer it may be useful to annotate it with the
 * original type. Use vatomicptr(T) macro for that.
 *
 * @example
 * ```c
 * typedef struct mcs_node_s {
 *    vatomicptr(struct mcs_node_s*) next;
 * } mcs_node_t;
 * ```
 ******************************************************************************/
#define vatomicptr(T) vatomicptr_t

/*******************************************************************************
 * @def vatomic_cpu_pause()
 * @brief Calls CPU pause instruction if available, e.g., `PAUSE` in x86.
 *
 * Tight spinloops often overuse the memory subsytem. This macro calls an
 * architecture-dependent instruction to slowdown spinloops (`PAUSE` in x86
 * and `YIELD` in aarch64). Define `VSYNC_DISABLE_POLITE_AWAIT` to disable the
 * effect of this macro.
 *
 * @example
 * ```c
 * while (!vatomic_read(&flag)) vatomic_cpu_pause();
 * ```
 ******************************************************************************/
#ifdef DOC
    #define vatomic_cpu_pause()
#endif

/* *****************************************************************************
 * vatomic_fence
 * ****************************************************************************/
/**
 * Executes an atomic fence with seq_cst memory order.
 */
static inline void vatomic_fence(void);
/**
 * Executes an atomic fence with acquire memory order.
 */
static inline void vatomic_fence_acq(void);
/**
 * Executes an atomic fence with release memory order.
 */
static inline void vatomic_fence_rel(void);
/**
 * Executes an atomic fence with relaxed memory order.
 * @note Technically, there no fence_rlx, it compiles to a NOP.
 */
static inline void vatomic_fence_rlx(void);

/* *****************************************************************************
 * Core functions
 * ****************************************************************************/

#include <vsync/atomic/core_u8.h>
#include <vsync/atomic/core_u16.h>
#include <vsync/atomic/core_u32.h>
#include <vsync/atomic/core_u64.h>
#include <vsync/atomic/core_sz.h>
#include <vsync/atomic/core_ptr.h>

/* *****************************************************************************
 * config
 * ****************************************************************************/
#if defined(VATOMIC_ENABLE_ATOMIC_SC)
    #include <vsync/atomic/internal/config/fnc_sc.h>
    #include <vsync/atomic/internal/config/u8_sc.h>
    #include <vsync/atomic/internal/config/u16_sc.h>
    #include <vsync/atomic/internal/config/u32_sc.h>
    #include <vsync/atomic/internal/config/u64_sc.h>
    #include <vsync/atomic/internal/config/sz_sc.h>
    #include <vsync/atomic/internal/config/ptr_sc.h>
#elif defined(VATOMIC_ENABLE_ATOMIC_RLX)
    #include <vsync/atomic/internal/config/fnc_rlx.h>
    #include <vsync/atomic/internal/config/u8_rlx.h>
    #include <vsync/atomic/internal/config/u16_rlx.h>
    #include <vsync/atomic/internal/config/u32_rlx.h>
    #include <vsync/atomic/internal/config/u64_rlx.h>
    #include <vsync/atomic/internal/config/sz_rlx.h>
    #include <vsync/atomic/internal/config/ptr_rlx.h>
#endif
/* *****************************************************************************
 * Select vatomic implementation and include definitions
 * ****************************************************************************/

#if !defined(VATOMIC_BUILTINS) && defined(__arm__)
    #if defined(__ARM_ARCH) && __ARM_ARCH == 8
        #define VATOMIC_ARM32_V8
        #include <vsync/atomic/internal/arm32_v8.h>
    #else
        /* we don't support ARM archs that are older than v7 */
        #define VATOMIC_ARM32_V7
        #include <vsync/atomic/internal/arm32_v7.h>
    #endif
#elif !defined(VATOMIC_BUILTINS) && defined(__aarch64__)
    #include <vsync/atomic/internal/arm64.h>
#elif !defined(VATOMIC_BUILTINS) && defined(__x86_64__)
    #include <vsync/atomic/internal/x86.h>
#endif

/* *****************************************************************************
 * fallback functions
 *
 * If the vatomic implementantion selected above does not implement some
 * function, the fallback header file may be able to construct the missing
 * function using other existing functions, for example, vatomic32_add_get can
 * get created with vatomic32_get_add.
 * ****************************************************************************/

#include <vsync/atomic/internal/builtins.h>
#include <vsync/atomic/internal/fallback.h>

/*******************************************************************************
 * @def VATOMIC_DISABLE_MACRO_UNDEF
 * @brief Disables undefines of non-exported macros.
 *
 * By default, all non-exported macros are undefined at the end of atomic.h.
 * When VATOMIC_DISABLE_MACRO_UNDEF, no macro is undefined. This is useful for
 * testing.
 ******************************************************************************/
#ifdef DOC
    #define VATOMIC_DISABLE_MACRO_UNDEF
#elif !defined(VATOMIC_DISABLE_MACRO_UNDEF)
    #include <vsync/atomic/internal/undef.h>
#endif

#endif /* VATOMIC_CORE_H */
