1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#ifndef BASE_STARTUP_PARAM_ATOMIC_H
17#define BASE_STARTUP_PARAM_ATOMIC_H
18#include <stdint.h>
19#include <string.h>
20#include <unistd.h>
21#include <stdio.h>
22#include <sys/types.h>
23
24#if (defined(PARAM_SUPPORT_STDATOMIC) || defined(__LITEOS_A__))
25#include <pthread.h>
26#include <stdatomic.h>
27#endif
28#if defined FUTEX_WAIT || defined FUTEX_WAKE
29#include <linux/futex.h>
30#endif
31
32#ifdef __cplusplus
33#if __cplusplus
34extern "C" {
35#endif
36#endif
37
38#ifdef __LITEOS_M__
39#define ATOMIC_UINT32 uint32_t
40#define ATOMIC_LLONG  long long
41#define ATOMIC_INIT(commitId, value) *(commitId) = (value)
42#define ATOMIC_LOAD_EXPLICIT(commitId, order) *(commitId)
43#define ATOMIC_STORE_EXPLICIT(commitId, value, order) *(commitId) = (value)
44#define ATOMIC_UINT64_INIT(commitId, value) *(commitId) = (value)
45#define ATOMIC_UINT64_LOAD_EXPLICIT(commitId, order) *(commitId)
46#define ATOMIC_UINT64_STORE_EXPLICIT(commitId, value, order) *(commitId) = (value)
47#define ATOMIC_SYNC_OR_AND_FETCH(commitId, value, order) *(commitId) |= (value)
48#define ATOMIC_SYNC_ADD_AND_FETCH(commitId, value, order) *(commitId) += (value)
49
50#define futex_wake(ftx, count) (void)(ftx)
51#define futex_wait(ftx, value) (void)(ftx)
52#define futex_wake_private(ftx, count) (void)(ftx)
53#define futex_wait_private(ftx, value) (void)(ftx)
54#else
55
56// support futex
57#ifndef __NR_futex
58#define PARAM_NR_FUTEX 202 /* syscall number */
59#else
60#define PARAM_NR_FUTEX __NR_futex
61#endif
62
63#if !(defined FUTEX_WAIT || defined FUTEX_WAKE)
64#define FUTEX_WAIT 0
65#define FUTEX_WAKE 1
66#define FUTEX_PRIVATE_FLAG 128
67#define FUTEX_WAIT_PRIVATE (FUTEX_WAIT | FUTEX_PRIVATE_FLAG)
68#define FUTEX_WAKE_PRIVATE (FUTEX_WAKE | FUTEX_PRIVATE_FLAG)
69
70#define PARAM_FUTEX(ftx, op, value, timeout, bitset)                       \
71    do {                                                                   \
72        struct timespec d_timeout = { 0, 1000 * 1000 * (timeout) };        \
73        syscall(PARAM_NR_FUTEX, ftx, op, value, &d_timeout, NULL, bitset); \
74    } while (0)
75
76#define futex_wake(ftx, count) PARAM_FUTEX(ftx, FUTEX_WAKE, count, 0, 0)
77#define futex_wait(ftx, value) PARAM_FUTEX(ftx, FUTEX_WAIT, value, 100, 0)
78#define futex_wake_private(ftx, count) PARAM_FUTEX(ftx, FUTEX_WAKE_PRIVATE, count, 0, 0)
79#define futex_wait_private(ftx, value) PARAM_FUTEX(ftx, FUTEX_WAIT_PRIVATE, value, 100, 0)
80#endif
81
82#if (defined(PARAM_SUPPORT_STDATOMIC) || defined(__LITEOS_A__))
83#define MEMORY_ORDER_RELAXED memory_order_relaxed
84#define MEMORY_ORDER_CONSUME memory_order_consume
85#define MEMORY_ORDER_ACQUIRE memory_order_acquire
86#define MEMORY_ORDER_RELEASE memory_order_release
87
88#define ATOMIC_UINT32 atomic_uint
89#define ATOMIC_LLONG atomic_llong
90#define ATOMIC_INIT(commitId, value) atomic_init((commitId), (value))
91#define ATOMIC_UINT64_INIT(commitId, value) atomic_init((commitId), (value))
92#define ATOMIC_LOAD_EXPLICIT(commitId, order) atomic_load_explicit((commitId), (order))
93#define ATOMIC_UINT64_LOAD_EXPLICIT(commitId, order) atomic_load_explicit((commitId), order)
94#define ATOMIC_STORE_EXPLICIT(commitId, value, order) atomic_store_explicit((commitId), (value), (order))
95#define ATOMIC_UINT64_STORE_EXPLICIT(commitId, value, order) atomic_store_explicit((commitId), (value), (order))
96#define ATOMIC_SYNC_OR_AND_FETCH(commitId, value, order) atomic_fetch_or_explicit((commitId), (value), (order))
97#define ATOMIC_SYNC_ADD_AND_FETCH(commitId, value, order) atomic_fetch_add_explicit((commitId), (value), (order))
98
99#else
100
101#define MEMORY_ORDER_RELAXED 0
102#define MEMORY_ORDER_CONSUME 1
103#define MEMORY_ORDER_ACQUIRE 2
104#define MEMORY_ORDER_RELEASE 3
105
106#define ATOMIC_UINT32 uint32_t
107#define ATOMIC_LLONG int64_t
108
109static inline void param_atomic_store(ATOMIC_UINT32 *ptr, uint32_t value, int order)
110{
111    __sync_lock_test_and_set(ptr, value);
112    if (order == MEMORY_ORDER_RELEASE) {
113        __sync_synchronize();
114    }
115}
116
117static inline void param_atomic_uint64_store(ATOMIC_LLONG *ptr, int64_t value, int order)
118{
119    __sync_lock_test_and_set(ptr, value);
120    if (order == MEMORY_ORDER_RELEASE) {
121        __sync_synchronize();
122    }
123}
124
125static inline void param_atomic_init(ATOMIC_UINT32 *ptr, uint32_t value)
126{
127    *ptr = 0;
128    __sync_fetch_and_add(ptr, value, 0);
129}
130
131static inline void param_atomic_uint64_init(ATOMIC_LLONG *ptr, int64_t value)
132{
133    *ptr = 0;
134    __sync_fetch_and_add(ptr, value, 0);
135}
136
137static inline ATOMIC_UINT32 param_atomic_load(ATOMIC_UINT32 *ptr, int order)
138{
139    return *((volatile ATOMIC_UINT32 *)ptr);
140}
141
142static inline ATOMIC_LLONG param_atomic_uint64_load(ATOMIC_LLONG *ptr, int order)
143{
144    return *((volatile ATOMIC_LLONG *)ptr);
145}
146
147#define ATOMIC_INIT(commitId, value) param_atomic_init((commitId), (value))
148#define ATOMIC_UINT64_INIT(commitId, value) param_atomic_uint64_init((commitId), (value))
149#define ATOMIC_LOAD_EXPLICIT(commitId, order) param_atomic_load((commitId), order)
150#define ATOMIC_UINT64_LOAD_EXPLICIT(commitId, order) param_atomic_uint64_load((commitId), order)
151#define ATOMIC_STORE_EXPLICIT(commitId, value, order) param_atomic_store((commitId), (value), (order))
152#define ATOMIC_UINT64_STORE_EXPLICIT(commitId, value, order) param_atomic_uint64_store((commitId), (value), (order))
153#define ATOMIC_SYNC_OR_AND_FETCH(commitId, value, order) __sync_or_and_fetch((commitId), (value))
154#define ATOMIC_SYNC_ADD_AND_FETCH(commitId, value, order) __sync_add_and_fetch((commitId), (value))
155#endif
156#endif // __LITEOS_M__
157#ifdef __cplusplus
158#if __cplusplus
159}
160#endif
161#endif
162
163#endif // BASE_STARTUP_PARAM_ATOMIC_H