1
0
mirror of https://github.com/esphome/esphome.git synced 2026-02-08 00:31:58 +00:00
Files
esphome/esphome/components/logger/task_log_buffer_esp32.h
J. Nick Koston 30f9bfaf83 [logger] Resolve thread name once and pass through logging chain
Eliminate redundant xTaskGetCurrentTaskHandle() and pcTaskGetName()
calls on the hot path by resolving the thread name once in log_vprintf_
and passing it through as const char* to all downstream functions.

- Main task fast path passes nullptr (no task handle lookup needed)
- Non-main thread path resolves name once, passes to both ring buffer
  and emergency console fallback
- Unify log_vprintf_non_main_thread_ to single signature across platforms
- Change send_message_thread_safe() on all platforms from TaskHandle_t
  to const char* thread_name
- Add TaskHandle_t overload for get_thread_name_ as primary on
  ESP32/LibreTiny, with no-arg convenience wrapper
- Use std::span<char> for Host/Zephyr get_thread_name_ buffer parameter
- Document Zephyr single-task path thread safety limitation
2026-02-07 07:47:00 +01:00

87 lines
3.4 KiB
C++

#pragma once
#ifdef USE_ESP32
#include "esphome/core/defines.h"
#include "esphome/core/helpers.h"
#ifdef USE_ESPHOME_TASK_LOG_BUFFER
#include <cstddef>
#include <cstring>
#include <memory>
#include <atomic>
#include <freertos/FreeRTOS.h>
#include <freertos/ringbuf.h>
namespace esphome::logger {
/**
* @brief Task log buffer for ESP32 platform using FreeRTOS ring buffer.
*
* Threading Model: Multi-Producer Single-Consumer (MPSC)
* - Multiple FreeRTOS tasks can safely call send_message_thread_safe() concurrently
* - Only the main loop task calls borrow_message_main_loop() and release_message_main_loop()
*
* This uses the FreeRTOS ring buffer (RINGBUF_TYPE_NOSPLIT) which provides
* built-in thread-safety for the MPSC pattern. The ring buffer ensures
* message integrity - each message is stored contiguously.
*
* Design:
* - Variable-size messages with header + text stored contiguously
* - FreeRTOS ring buffer handles synchronization internally
* - Atomic counter for fast has_messages() check without ring buffer lock
*/
class TaskLogBuffer {
public:
// Structure for a log message header (text data follows immediately after)
struct LogMessage {
const char *tag; // We store the pointer, assuming tags are static
char thread_name[16]; // Store thread name directly (only used for non-main threads)
uint16_t text_length; // Length of the message text (up to ~64KB)
uint16_t line; // Source code line number
uint8_t level; // Log level (0-7)
// Methods for accessing message contents
inline char *text_data() { return reinterpret_cast<char *>(this) + sizeof(LogMessage); }
inline const char *text_data() const { return reinterpret_cast<const char *>(this) + sizeof(LogMessage); }
};
// Constructor that takes a total buffer size
explicit TaskLogBuffer(size_t total_buffer_size);
~TaskLogBuffer();
// NOT thread-safe - borrow a message from the ring buffer, only call from main loop
bool borrow_message_main_loop(LogMessage **message, const char **text, void **received_token);
// NOT thread-safe - release a message buffer and update the counter, only call from main loop
void release_message_main_loop(void *token);
// Thread-safe - send a message to the ring buffer from any thread
bool send_message_thread_safe(uint8_t level, const char *tag, uint16_t line, const char *thread_name,
const char *format, va_list args);
// Check if there are messages ready to be processed using an atomic counter for performance
inline bool HOT has_messages() const {
return message_counter_.load(std::memory_order_relaxed) != last_processed_counter_;
}
// Get the total buffer size in bytes
inline size_t size() const { return size_; }
private:
RingbufHandle_t ring_buffer_{nullptr}; // FreeRTOS ring buffer handle
StaticRingbuffer_t structure_; // Static structure for the ring buffer
uint8_t *storage_{nullptr}; // Pointer to allocated memory
size_t size_{0}; // Size of allocated memory
// Atomic counter for message tracking (only differences matter)
std::atomic<uint16_t> message_counter_{0}; // Incremented when messages are committed
mutable uint16_t last_processed_counter_{0}; // Tracks last processed message
};
} // namespace esphome::logger
#endif // USE_ESPHOME_TASK_LOG_BUFFER
#endif // USE_ESP32