• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * This file is part of the openHiTLS project.
3  *
4  * openHiTLS is licensed under the Mulan PSL v2.
5  * You can use this software according to the terms and conditions of the Mulan PSL v2.
6  * You may obtain a copy of Mulan PSL v2 at:
7  *
8  *     http://license.coscl.org.cn/MulanPSL2
9  *
10  * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
11  * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
12  * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
13  * See the Mulan PSL v2 for more details.
14  */
15 
16 #ifndef SAL_ATOMIC_H
17 #define SAL_ATOMIC_H
18 
19 #include <stdlib.h>
20 #include "bsl_sal.h"
21 #include "bsl_errno.h"
22 
23 /* The value of __STDC_VERSION__ is determined by the compilation option -std.
24    The atomic API is provided only when -std=gnu11 is used. */
25 #if __STDC_VERSION__ >= 201112L && !defined(__STDC_NO_ATOMICS__)
26 #include <stdatomic.h>
27 #define SAL_HAVE_C11_ATOMICS
28 #endif
29 
30 #ifdef __cplusplus
31 extern "C" {
32 #endif // __cplusplus
33 
34 int BSL_SAL_AtomicAdd(int *val, int amount, int *ref, BSL_SAL_ThreadLockHandle lock);
35 
36 /* Atom operation mode 1, which uses the function provided by C11. Only the int type is considered.
37  * ATOMIC_INT_LOCK_FREE: If the value is 1, the operation MAY BE lock-free operation.
38  * ATOMIC_INT_LOCK_FREE: If the value is 2, it's the lock-free operation.
39  * memory_order_relaxed only ensures the atomicity of the current operation
40  * and does not consider the synchronization between threads.
41  */
42 #if defined(SAL_HAVE_C11_ATOMICS) && defined(ATOMIC_INT_LOCK_FREE) && ATOMIC_INT_LOCK_FREE > 0 && !defined(HITLS_ATOMIC_THREAD_LOCK)
43 #define SAL_USE_ATOMICS_LIB_FUNC
44 typedef struct {
45     atomic_int count;
46 } BSL_SAL_RefCount;
47 
BSL_SAL_AtomicUpReferences(BSL_SAL_RefCount * references,int * ret)48 static inline int BSL_SAL_AtomicUpReferences(BSL_SAL_RefCount *references, int *ret)
49 {
50     *ret = atomic_fetch_add_explicit(&(references->count), 1, memory_order_relaxed) + 1;
51     return BSL_SUCCESS;
52 }
53 
BSL_SAL_AtomicDownReferences(BSL_SAL_RefCount * references,int * ret)54 static inline int BSL_SAL_AtomicDownReferences(BSL_SAL_RefCount *references, int *ret)
55 {
56     *ret = atomic_fetch_sub_explicit(&(references->count), 1, memory_order_relaxed) - 1;
57     if (*ret == 0) {
58         atomic_thread_fence(memory_order_acquire);
59     }
60     return BSL_SUCCESS;
61 }
62 
63 /* Atom operation mode 2, using the function provided by the GCC. */
64 #elif defined(__GNUC__) && defined(__ATOMIC_RELAXED) && __GCC_ATOMIC_INT_LOCK_FREE > 0 && !defined(HITLS_ATOMIC_THREAD_LOCK)
65 #define SAL_USE_ATOMICS_LIB_FUNC
66 typedef struct {
67     int count;
68 } BSL_SAL_RefCount;
69 
BSL_SAL_AtomicUpReferences(BSL_SAL_RefCount * references,int * ret)70 static inline int BSL_SAL_AtomicUpReferences(BSL_SAL_RefCount *references, int *ret)
71 {
72     *ret = __atomic_fetch_add(&(references->count), 1, __ATOMIC_RELAXED) + 1;
73     return BSL_SUCCESS;
74 }
75 
BSL_SAL_AtomicDownReferences(BSL_SAL_RefCount * references,int * ret)76 static inline int BSL_SAL_AtomicDownReferences(BSL_SAL_RefCount *references, int *ret)
77 {
78     *ret = __atomic_fetch_sub(&(references->count), 1, __ATOMIC_RELAXED) - 1;
79     if (*ret == 0) {
80         const int type = __ATOMIC_ACQUIRE;
81         __atomic_thread_fence(type);
82     }
83     return BSL_SUCCESS;
84 }
85 
86 // Atom operation mode 3, using read/write locks.
87 #else
88 typedef struct {
89     int count;
90     BSL_SAL_ThreadLockHandle lock;
91 } BSL_SAL_RefCount;
92 
BSL_SAL_AtomicUpReferences(BSL_SAL_RefCount * references,int * ret)93 static inline int BSL_SAL_AtomicUpReferences(BSL_SAL_RefCount *references, int *ret)
94 {
95     return BSL_SAL_AtomicAdd(&(references->count), 1, ret, references->lock);
96 }
97 
BSL_SAL_AtomicDownReferences(BSL_SAL_RefCount * references,int * ret)98 static inline int BSL_SAL_AtomicDownReferences(BSL_SAL_RefCount *references, int *ret)
99 {
100     return BSL_SAL_AtomicAdd(&(references->count), -1, ret, references->lock);
101 }
102 #endif
103 
104 #ifdef SAL_USE_ATOMICS_LIB_FUNC
BSL_SAL_ReferencesInit(BSL_SAL_RefCount * references)105 static inline int BSL_SAL_ReferencesInit(BSL_SAL_RefCount *references)
106 {
107     references->count = 1;
108     return BSL_SUCCESS;
109 }
110 
BSL_SAL_ReferencesFree(BSL_SAL_RefCount * references)111 static inline void BSL_SAL_ReferencesFree(BSL_SAL_RefCount *references)
112 {
113     (void)references;
114     return;
115 }
116 #else
BSL_SAL_ReferencesInit(BSL_SAL_RefCount * references)117 static inline int BSL_SAL_ReferencesInit(BSL_SAL_RefCount *references)
118 {
119     references->count = 1;
120     return BSL_SAL_ThreadLockNew(&(references->lock));
121 }
122 
BSL_SAL_ReferencesFree(BSL_SAL_RefCount * references)123 static inline void BSL_SAL_ReferencesFree(BSL_SAL_RefCount *references)
124 {
125     BSL_SAL_ThreadLockFree(references->lock);
126     references->lock = NULL;
127     return;
128 }
129 #endif
130 
131 #ifdef __cplusplus
132 }
133 #endif // __cplusplus
134 
135 #endif // SAL_ATOMIC_H
136