I'd like to create a std::atomic version of a data record defined by a struct. This is for an ESP32, so I need the atomic load and exchange operations to guarantee atomicity whether they take place in a regular FreeRTOS task or an ISR AND regardless of whether it takes place on Core 0 or Core 1.
First, is std::atomic the correct construct for this application (Task, ISR, Core 0, Core 1), or is the Free RTOS portENTER_CRITICAL(&mutex) structure required?
I tried a simple example with the code below. However, I encountered the shown linker error. It compiles fine if I replace the struct with a POD type.
So, it could be my understanding of std::atomic is incorrect. Or (less likely) that the ESP32 implementation of std::atomic is lacking.
Any ideas?
#include "Arduino.h"
#include <atomic>
struct Record {
int64_t value;
int64_t timeStamp;
};
using AtomicRecord = std::atomic<Record>;
void setup() {
AtomicRecord liveRecord;
Record localRecord{200, -86000};
liveRecord.exchange(localRecord);
}
void loop() {
}
ERROR:
sketch\sketch_apr28a.ino.cpp.o:(.literal._Z5setupv+0x4): undefined reference to `__atomic_exchange'
sketch\sketch_apr28a.ino.cpp.o: In function `std::atomic<Record>::exchange(Record, std::memory_order)':
d:\arduino-1.8.15\portable\packages\esp32\tools\xtensa-esp32-elf-gcc\1.22.0-80-g6c4433a-5.2.0\xtensa-esp32-elf\include\c++\5.2.0/atomic:251: undefined reference to `__atomic_exchange'
collect2.exe: error: ld returned 1 exit status
exit status 1
Error compiling for board Adafruit ESP32 Feather.
Through the Arduino IDE?
I avoid anything STL so I don't know for sure, but I thought anything developed in the Arduino IDE, regardless of board is sans STL. @in0 ?
The ESP32 only supports 32-bit atomic operations in hardware. For larger atomics, you need a lock to ensure atomicity. The routines for these locking operations are usually provided by something like libatomic, but this is not included with the ESP-IDF toolchain. They did add 64-bit atomic routines, but not 128-bit or arbitrary size versions: stdatomic.h 64-bit atomic access support (IDFGH-703) · Issue #3163 · espressif/esp-idf · GitHub
If implemented correctly, atomics should be fine.
You'll see that the ESP-IDF's implementation calls portENTER_CRITICAL under the hood:
If implemented incorrectly, locks shared with interrupt handlers are obviously problematic.
I think 128-bit atomic operations are quite uncommon, many systems don't have hardware instructions for them, so you lose lock-freedom.
For the ESP-IDF implementation, all software atomic routines share the same global spinlock, which ensures sequential consistency, but could also be a bottleneck.
The Arduino IDE does not place any restrictions on the contents of the core library, toolchain, compilation command patterns, etc. of each boards platform.
It may well be that some components provided by one architecture (e.g., ESP32) are not available or not sensible for another (e.g., AVR). This means using them in your code will impair its portability.
There are some libraries that will provide STL for AVR even though the "Arduino AVR Boards" platform does not. I think this is the most popular one: