[kernel] Move the logger from kutil into kernel
Part one of a series of code moves. The kutil library is not very useful, as most of its code is kernel-specific. This was originally for testing purposes, but that can be achieved in other ways with the current build system. I find this mostly creates a strange division in the kernel code. Instead, I'm going to move everything kernel-specific to actually be in the kernel, and replace kutil with just 'util' for generic utility code I want to share. This commit: - Moves the logger into the kernel. - Updates the 'printf' library used from mpaland/printf to eyalroz/printf and moved it into the kernel, as it's only used by the logger in kutil. - Removes some other unused kutil headers from some files, to help future code rearrangement. Note that the (now redundant-seeming) log.cpp/h in kernel is currently still there - these files are more about log output than the logging system, and will get replaced once I add user-space log output.
This commit is contained in:
172
src/kernel/logger.cpp
Normal file
172
src/kernel/logger.cpp
Normal file
@@ -0,0 +1,172 @@
|
||||
#include "kutil/assert.h"
|
||||
#include "kutil/constexpr_hash.h"
|
||||
#include "kutil/memory.h"
|
||||
#include "printf/printf.h"
|
||||
|
||||
#include "logger.h"
|
||||
|
||||
namespace logs {
|
||||
#define LOG(name, lvl) \
|
||||
const log::area_t name = #name ## _h; \
|
||||
const char * name ## _name = #name;
|
||||
#include "j6/tables/log_areas.inc"
|
||||
#undef LOG
|
||||
}
|
||||
|
||||
namespace log {
|
||||
|
||||
using kutil::memset;
|
||||
using kutil::memcpy;
|
||||
|
||||
logger *logger::s_log = nullptr;
|
||||
const char *logger::s_level_names[] = {"", "debug", "info", "warn", "error", "fatal"};
|
||||
|
||||
logger::logger(logger::immediate_cb output) :
|
||||
m_buffer(nullptr, 0),
|
||||
m_immediate(output),
|
||||
m_flush(nullptr),
|
||||
m_sequence(0)
|
||||
{
|
||||
memset(&m_levels, 0, sizeof(m_levels));
|
||||
memset(&m_names, 0, sizeof(m_names));
|
||||
s_log = this;
|
||||
}
|
||||
|
||||
logger::logger(uint8_t *buffer, size_t size, logger::immediate_cb output) :
|
||||
m_buffer(buffer, size),
|
||||
m_immediate(output),
|
||||
m_flush(nullptr),
|
||||
m_sequence(0)
|
||||
{
|
||||
memset(&m_levels, 0, sizeof(m_levels));
|
||||
memset(&m_names, 0, sizeof(m_names));
|
||||
s_log = this;
|
||||
|
||||
#define LOG(name, lvl) \
|
||||
register_area(logs::name, logs::name ## _name, log::level::lvl);
|
||||
#include "j6/tables/log_areas.inc"
|
||||
#undef LOG
|
||||
}
|
||||
|
||||
void
|
||||
logger::set_level(area_t area, level l)
|
||||
{
|
||||
unsigned uarea = static_cast<unsigned>(area);
|
||||
uint8_t ulevel = static_cast<uint8_t>(l) & 0x0f;
|
||||
uint8_t &flags = m_levels[uarea / 2];
|
||||
if (uarea & 1)
|
||||
flags = (flags & 0x0f) | (ulevel << 4);
|
||||
else
|
||||
flags = (flags & 0xf0) | ulevel;
|
||||
}
|
||||
|
||||
level
|
||||
logger::get_level(area_t area)
|
||||
{
|
||||
unsigned uarea = static_cast<unsigned>(area);
|
||||
uint8_t &flags = m_levels[uarea / 2];
|
||||
if (uarea & 1)
|
||||
return static_cast<level>((flags & 0xf0) >> 4);
|
||||
else
|
||||
return static_cast<level>(flags & 0x0f);
|
||||
}
|
||||
|
||||
void
|
||||
logger::register_area(area_t area, const char *name, level verbosity)
|
||||
{
|
||||
m_names[area] = name;
|
||||
set_level(area, verbosity);
|
||||
}
|
||||
|
||||
void
|
||||
logger::output(level severity, area_t area, const char *fmt, va_list args)
|
||||
{
|
||||
uint8_t buffer[256];
|
||||
entry *header = reinterpret_cast<entry *>(buffer);
|
||||
header->bytes = sizeof(entry);
|
||||
header->area = area;
|
||||
header->severity = severity;
|
||||
header->sequence = m_sequence++;
|
||||
|
||||
header->bytes +=
|
||||
vsnprintf(header->message, sizeof(buffer) - sizeof(entry), fmt, args);
|
||||
|
||||
kutil::scoped_lock lock {m_lock};
|
||||
|
||||
if (m_immediate) {
|
||||
buffer[header->bytes] = 0;
|
||||
m_immediate(area, severity, header->message);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8_t *out;
|
||||
size_t n = m_buffer.reserve(header->bytes, reinterpret_cast<void**>(&out));
|
||||
if (n < sizeof(entry)) {
|
||||
m_buffer.commit(0); // Cannot even write the header, abort
|
||||
return;
|
||||
}
|
||||
|
||||
if (n < header->bytes)
|
||||
header->bytes = n;
|
||||
|
||||
memcpy(out, buffer, n);
|
||||
m_buffer.commit(n);
|
||||
|
||||
if (m_flush)
|
||||
m_flush();
|
||||
}
|
||||
|
||||
size_t
|
||||
logger::get_entry(void *buffer, size_t size)
|
||||
{
|
||||
kutil::scoped_lock lock {m_lock};
|
||||
|
||||
void *out;
|
||||
size_t out_size = m_buffer.get_block(&out);
|
||||
if (out_size == 0 || out == 0)
|
||||
return 0;
|
||||
|
||||
kassert(out_size >= sizeof(entry), "Couldn't read a full entry");
|
||||
if (out_size < sizeof(entry))
|
||||
return 0;
|
||||
|
||||
entry *ent = reinterpret_cast<entry *>(out);
|
||||
if (size >= ent->bytes) {
|
||||
memcpy(buffer, out, ent->bytes);
|
||||
m_buffer.consume(ent->bytes);
|
||||
}
|
||||
|
||||
return ent->bytes;
|
||||
}
|
||||
|
||||
#define LOG_LEVEL_FUNCTION(name) \
|
||||
void name (area_t area, const char *fmt, ...) { \
|
||||
logger *l = logger::s_log; \
|
||||
if (!l) return; \
|
||||
level limit = l->get_level(area); \
|
||||
if (limit == level::none || level::name < limit) return; \
|
||||
va_list args; \
|
||||
va_start(args, fmt); \
|
||||
l->output(level::name, area, fmt, args); \
|
||||
va_end(args); \
|
||||
}
|
||||
|
||||
LOG_LEVEL_FUNCTION(debug);
|
||||
LOG_LEVEL_FUNCTION(info);
|
||||
LOG_LEVEL_FUNCTION(warn);
|
||||
LOG_LEVEL_FUNCTION(error);
|
||||
|
||||
void fatal(area_t area, const char *fmt, ...)
|
||||
{
|
||||
logger *l = logger::s_log;
|
||||
if (!l) return;
|
||||
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
l->output(level::fatal, area, fmt, args);
|
||||
va_end(args);
|
||||
|
||||
kassert(false, "log::fatal");
|
||||
}
|
||||
|
||||
} // namespace log
|
||||
Reference in New Issue
Block a user