trace_buffer: revise trace buffer implementation

This commit simplifies the current implementation by overloading the
length field with a padding indicator in addition to the zero-length
head entry. This simplifies the iteration semantics as it eliminates
the need for determining whether a zero-length entries is the actual
head of the buffer or a padding at the buffer end.

genodelabs/genode#4434
This commit is contained in:
Johannes Schlatow
2022-02-04 16:56:21 +01:00
committed by Norman Feske
parent d24552f5e2
commit edc46d15f8
3 changed files with 149 additions and 93 deletions

View File

@ -46,62 +46,37 @@ class Trace_buffer
if ((_buffer.wrapped() - 1) != _wrapped_count) {
warning("buffer wrapped multiple times; you might want to raise buffer size; curr_count=",
_buffer.wrapped(), " last_count=", _wrapped_count);
_curr = _buffer.first();
}
_wrapped_count = (unsigned)_buffer.wrapped();
}
Trace::Buffer::Entry new_curr { _curr };
Trace::Buffer::Entry entry { _curr };
/**
* If '_curr' is marked 'last' (i.e., the entry pointer it contains
* is invalid), either this method wasn't called before on this
* buffer or the buffer was empty on all previous calls (note that
* '_curr' is only updated with valid entry pointers by this
* method). In this case, we start with the first entry (if any).
* Iterate over all entries that were not processed yet.
*
* If '_curr' is not marked 'last' it points to the last processed
* entry and we proceed with the, so far unprocessed entry next to
* it (if any). Note that in this case, the entry behind '_curr'
* might have got overridden since the last call to this method
* because the buffer wrapped and oustripped the entry consumer.
* This problem is well known and should be avoided by choosing a
* large enough buffer.
* A note on terminology: The head of the buffer marks the write
* position. The first entry is the one that starts at the lowest
* memory address. The next entry returns an invalid entry called
* if the 'last' end of the buffer (highest address) was reached.
*/
if (entry.last())
entry = _buffer.first();
else
entry = _buffer.next(entry);
/* iterate over all entries that were not processed yet */
for (; wrapped || !entry.last(); entry = _buffer.next(entry)) {
/* if buffer wrapped, we pass the last entry once and continue at first entry */
bool applied_wrap = false;
if (wrapped && entry.last()) {
wrapped = false;
applied_wrap = true;
for (; !entry.head(); entry = _buffer.next(entry)) {
/* continue at first entry if we hit the end of the buffer */
if (entry.last())
entry = _buffer.first();
if (entry.last()) {
new_curr = entry;
break;
}
}
if (!entry.length()) {
/* skip empty entries */
if (entry.empty())
continue;
}
if (!functor(entry)) {
if (applied_wrap)
new_curr = Trace::Buffer::Entry();
/* functor may return false to continue processing later on */
if (!functor(entry))
break;
}
new_curr = entry;
}
/* remember the last processed entry in _curr */
if (update) _curr = new_curr;
/* remember the next to be processed entry in _curr */
if (update) _curr = entry;
}
void * address() const { return &_buffer; }