genode/repos/os/include/trace/trace_buffer.h
2021-12-17 15:04:45 +01:00

101 lines
2.8 KiB
C++

/*
* \brief Wrapper for Trace::Buffer that adds some convenient functionality
* \author Martin Stein
* \date 2018-01-12
*/
/*
* Copyright (C) 2018 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU Affero General Public License version 3.
*/
#ifndef _TRACE__TRACE_BUFFER_H_
#define _TRACE__TRACE_BUFFER_H_
/* Genode includes */
#include <base/trace/buffer.h>
/**
* Wrapper for Trace::Buffer that adds some convenient functionality
*/
class Trace_buffer
{
private:
Genode::Trace::Buffer &_buffer;
Genode::Trace::Buffer::Entry _curr { _buffer.first() };
unsigned _wrapped_count { 0 };
public:
Trace_buffer(Genode::Trace::Buffer &buffer) : _buffer(buffer) { }
/**
* Call functor for each entry that wasn't yet processed
*/
template <typename FUNC>
void for_each_new_entry(FUNC && functor, bool update = true)
{
using namespace Genode;
bool wrapped = _buffer.wrapped() != _wrapped_count;
if (wrapped) {
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);
}
_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).
*
* 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.
*/
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 */
if (wrapped && entry.last()) {
wrapped = false;
entry = _buffer.first();
if (entry.last())
break;
}
if (!functor(entry))
break;
new_curr = entry;
}
/* remember the last processed entry in _curr */
if (update) _curr = new_curr;
}
void * address() const { return &_buffer; }
};
#endif /* _TRACE__TRACE_BUFFER_H_ */