| 113 | = Design of Atomic operations API = |
| 114 | |
| 115 | |
| 116 | The first part is a directory structure chart, atomic.h is API definition file and cpuatomic.h is implementation file. |
| 117 | |
| 118 | |---/cpukit |
| 119 | | |
| 120 | |----score |
| 121 | | |
| 122 | |----include |
| 123 | | | |
| 124 | | ----rtems |
| 125 | | | | |
| 126 | | | ----score |
| 127 | | | | |
| 128 | | | ----atomic.h |
| 129 | |------cpu |
| 130 | | | |
| 131 | | ------architecture |
| 132 | | | | |
| 133 | | | -------rtems |
| 134 | | | | |
| 135 | | | ----score |
| 136 | | | | |
| 137 | | | ----cpuatomic.h |
| 138 | | | | |
| 139 | | | ----cpu.h |
| 140 | |
| 141 | Becuase most of the implementation of atomic operations are assembly instructions, if not they could also be implemented with inlilne C source code. So i place the architecture-independent atomic API definitions to the atomic.h which is visible to other rtems components like score, dirver and etc. The architecture-dependent atomic implementations are placed to the cpuatomic.h which exists in every architecture-related directory as show above. The API is associated with implementations using method like this: |
| 142 | for example, the atomic general load function API: int Atomic_Load_Acq_Int(volatile int *p) |
| 143 | 1. In the implementation file cpuatomic.h it will be implemented like this: |
| 144 | static inline int _Atomic_Load_Acq_Int(volatile int *p) |
| 145 | { |
| 146 | embedded assembly code; |
| 147 | }; |
| 148 | 2. In the API definition file atomic.h it will be defined like this: |
| 149 | #define Atomic_Load_Acq_Int(p) _Atomic_Load_Acq_Int((volatile u_int *)(p)) |
| 150 | 3. The cpuatomic.h should be included in the atomic.h directly or indirectly. If it is included in the atomic directly its file name should be fixed and each architecture has the same file name. If it is included in the atomic.h indirectly its file name can be unfixed and each architecture can have different file name, but it must be included by a architecture-dependent header file(like cpu.h as showed above) which can be included by architecture-independent score header file atomic.h |
| 151 | |
| 152 | Synopsis: |
| 153 | |
| 154 | The follow is atomic operation API definition in "rtems" style: |
| 155 | 1. The atomic_store generic functions |
| 156 | void _Atomic_Store_Rel_<_type_>(volatile _type_ *p, _type_ v); |
| 157 | 2. The atomic_load generic functions |
| 158 | _type_ _Atomic_Load_Acq_<_type_>(volatile _type_ *p); |
| 159 | 3. The atomic_fetch-and-modify generic functions |
| 160 | void _Atomic_Fetch_Add_[Acq_|Rel_]<_type_>(volatile _type_ *p, _type_ v); |
| 161 | void _Atomic_Fetch_Sub_[Acq_|Rel_]<_type_>(volatile _type_ *p, _type_ v); |
| 162 | void _Atomic_Fetch_Or_[Acq_|Rel_]<_type_>(volatile _type_ *p, _type_ v); |
| 163 | void _Atomic_Fetch_And_[Acq_|Rel_]<_type_>(volatile _type_ *p, _type_ v); |
| 164 | 4. The atomic_compare_exchange generic functions |
| 165 | int _Atomic_cmpset_[acq_|rel_]<_type_>(volatile _type_ *dst, _type_ old, _type_ new); |
| 166 | |
| 167 | Description: |
| 168 | |
| 169 | 1. _types_: |
| 170 | |
| 171 | Each atomic operation operates on a specific type. The type to use is indicated in the function name. The available types that can be used are: |
| 172 | int unsigned integer |
| 173 | long unsigned long integer |
| 174 | ptr unsigned integer the size of a pointer |
| 175 | 32 unsigned 32-bit integer |
| 176 | 64 unsigned 64-bit integer |
| 177 | Because rtems is used in lots of soc with 8 or 16 bit bus, so some architectures can consider provide operations for types smaller than ''int''. In the FreeBSD only some architectures provide those types. |
| 178 | char unsigned character |
| 179 | short unsigned short integer |
| 180 | 8 unsigned 8-bit integer |
| 181 | 16 unsigned 16-bit integer |
| 182 | |
| 183 | 2. Acq and Rel: |
| 184 | "Acq" represens a read memory barrier which ensures that the effects of this operation are completed before the effects of any later data accesses |
| 185 | "Rel" represens a write memory barrier which ensures that all effects of all previous data accesses are completed before this operation takes place |