/* * \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 /** * 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 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 = _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_ */