QElectroTech 0.200.1-dev
Loading...
Searching...
No Matches
LogRing Class Reference

The LogRing class Fixed-capacity, always-on in-memory ring of the most recent log lines, preallocated once at construction – append() never allocates. More...

#include <logring.h>

Collaboration diagram for LogRing:
Collaboration graph

Classes

struct  Entry

Public Member Functions

 LogRing ()
void append (const QByteArray &line) noexcept
QVector< QByteArray > snapshot () const
void dumpToFd (int fd) const noexcept
void clear ()

Static Public Attributes

static constexpr int kCapacityEntries = 4096
static constexpr int kEntryBytes = 512

Private Attributes

std::vector< Entrym_entries
std::atomic< quint64 > m_write_cursor {0}

Detailed Description

The LogRing class Fixed-capacity, always-on in-memory ring of the most recent log lines, preallocated once at construction – append() never allocates.

Lock-free by construction, not just "thread-safe": step 4 (see crashhandler.h) reads this ring from inside a POSIX signal handler, where taking any lock is unsafe – if the crashing thread happens to be the one that already holds it (or any other thread does and never gets scheduled again), the handler hangs forever, and you lose both the ring dump and the core dump. So there is no mutex here at all: append() claims a slot with a single atomic fetch-add, and dumpToFd()/snapshot() read the preallocated entries directly.

Accepted tradeoff: if dumpToFd() runs while another thread is mid-append into the exact slot being read (only possible in the crash-handler case, and only for at most one slot), that one entry may be read torn – part old content, part new. Every other entry is unaffected. This is deliberate: the alternative (a seqlock or similar to detect and retry torn reads) adds real complexity for a window that, per discussion #644, is not worth trading "the handler must never block" against.

Constructor & Destructor Documentation

◆ LogRing()

LogRing::LogRing ( )

Member Function Documentation

◆ append()

void LogRing::append ( const QByteArray & line)
noexcept

Append one already-formatted, already-truncated log line. Bytes beyond kEntryBytes are dropped with a truncation marker. Never allocates, never blocks. Safe to call from any normal (non-signal) thread concurrently.

◆ clear()

void LogRing::clear ( )

◆ dumpToFd()

void LogRing::dumpToFd ( int fd) const
noexcept

Async-signal-safe: writes every entry currently held to fd via write(2) only – no allocation, no Qt, no locks. May write a torn entry under the rare race described above; never blocks.

Here is the call graph for this function:

◆ snapshot()

QVector< QByteArray > LogRing::snapshot ( ) const

Snapshot of the entries currently held, oldest first. Normal (non-signal) context only.

Member Data Documentation

◆ kCapacityEntries

int LogRing::kCapacityEntries = 4096
staticconstexpr

◆ kEntryBytes

int LogRing::kEntryBytes = 512
staticconstexpr

◆ m_entries

std::vector<Entry> LogRing::m_entries
private

◆ m_write_cursor

std::atomic<quint64> LogRing::m_write_cursor {0}
private

The documentation for this class was generated from the following files: