Nexus Embedded Platform 0.1.0
Statically assembled reusable embedded mechanisms
Loading...
Searching...
No Matches
atomic.h
Go to the documentation of this file.
1
24#ifndef NEXUS_ARCH_ATOMIC_H
25#define NEXUS_ARCH_ATOMIC_H
26#include <limits.h>
27#include <stdbool.h>
28#include <stdint.h>
29
30#if !(defined(__GNUC__) || defined(__clang__))
31#error "Nexus inline atomics require the maintained GCC/Clang compiler port"
32#endif
33
34#ifdef __cplusplus
35static_assert(sizeof(uint32_t) == 4 && sizeof(unsigned) == 4 && CHAR_BIT == 8,
36 "Nexus atomics require naturally aligned 32-bit unsigned words");
37#else
38_Static_assert(sizeof(uint32_t) == 4 && sizeof(unsigned) == 4 && CHAR_BIT == 8,
39 "Nexus atomics require naturally aligned 32-bit unsigned words");
40#endif
41
42#if defined(__ARM_ARCH_6M__)
43#include "nexus/arch/arch.h"
44#elif __GCC_ATOMIC_INT_LOCK_FREE != 2
45#error "Nexus RMW requires lock-free words or the reviewed ARMv6-M IRQ port"
46#endif
47
49static inline uint32_t nx_atomic_u32_load_relaxed(const uint32_t* value) {
50 return __atomic_load_n(value, __ATOMIC_RELAXED);
51}
52
54static inline uint32_t nx_atomic_u32_load_acquire(const uint32_t* value) {
55 return __atomic_load_n(value, __ATOMIC_ACQUIRE);
56}
57
59static inline void nx_atomic_u32_store_relaxed(uint32_t* value,
60 uint32_t desired) {
61 __atomic_store_n(value, desired, __ATOMIC_RELAXED);
62}
63
65static inline void nx_atomic_u32_store_release(uint32_t* value,
66 uint32_t desired) {
67 __atomic_store_n(value, desired, __ATOMIC_RELEASE);
68}
69
70#if defined(__ARM_ARCH_6M__)
75static inline uint32_t nx_atomic_u32_add_guarded(uint32_t* value,
76 uint32_t amount) {
78 uint32_t observed = nx_atomic_u32_load_acquire(value);
79 nx_atomic_u32_store_release(value, (uint32_t)(observed + amount));
80 nx_arch_irq_restore(previous);
81 return observed;
82}
83#endif
84
96static inline bool nx_atomic_u32_compare_exchange_acq_rel(uint32_t* value,
97 uint32_t* expected,
98 uint32_t desired) {
99#if defined(__ARM_ARCH_6M__)
101 uint32_t observed = nx_atomic_u32_load_acquire(value);
102 bool matched = observed == *expected;
103 if (matched) {
104 nx_atomic_u32_store_release(value, desired);
105 } else {
106 *expected = observed;
107 }
108 nx_arch_irq_restore(previous);
109 return matched;
110#else
111 return __atomic_compare_exchange_n(value, expected, desired, false,
112 __ATOMIC_ACQ_REL, __ATOMIC_ACQUIRE);
113#endif
114}
115
118static inline uint32_t nx_atomic_u32_fetch_add_acq_rel(uint32_t* value,
119 uint32_t amount) {
120#if defined(__ARM_ARCH_6M__)
121 return nx_atomic_u32_add_guarded(value, amount);
122#else
123 return __atomic_fetch_add(value, amount, __ATOMIC_ACQ_REL);
124#endif
125}
126
131static inline uint32_t nx_atomic_u32_fetch_add_release(uint32_t* value,
132 uint32_t amount) {
133#if defined(__ARM_ARCH_6M__)
134 return nx_atomic_u32_add_guarded(value, amount);
135#else
136 return __atomic_fetch_add(value, amount, __ATOMIC_RELEASE);
137#endif
138}
139
143static inline uint32_t nx_atomic_u32_fetch_sub_acq_rel(uint32_t* value,
144 uint32_t amount) {
145#if defined(__ARM_ARCH_6M__)
146 return nx_atomic_u32_add_guarded(value, (uint32_t)(0u - amount));
147#else
148 return __atomic_fetch_sub(value, amount, __ATOMIC_ACQ_REL);
149#endif
150}
151
156static inline uint32_t nx_atomic_u32_fetch_sub_release(uint32_t* value,
157 uint32_t amount) {
158#if defined(__ARM_ARCH_6M__)
159 return nx_atomic_u32_add_guarded(value, (uint32_t)(0u - amount));
160#else
161 return __atomic_fetch_sub(value, amount, __ATOMIC_RELEASE);
162#endif
163}
164#endif
CPU-local mask, context, ordering and cycle snapshot contract.
void nx_arch_irq_restore(nx_arch_irq_state_t previous)
Restore the incoming mask, preserving nested exclusions.
nx_arch_irq_state_t nx_arch_irq_save(void)
Save incoming local mask and mask configurable exceptions.
Saved incoming PRIMASK or calling-thread Native nesting.
Definition arch.h:22