mirror of
https://github.com/justinian/jsix.git
synced 2025-12-09 16:04:32 -08:00
[util] Add util::format replacement for snprintf
The printf library I have been using, while useful, has way more than I need in it, and had comparably huge stack space requirements. This change adds a new util::format() which is a replacement for snprintf, but with only the features used by kernel logging. The logger has been changed to use it, as well as the few instances of snprintf in the interrupt handling code before calling kassert. Also part of this change: the logger's (now vestigial) immediate output handling code is removed, as well as the "sequence" field on log message headers.
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
#include <util/format.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
#include "cpu.h"
|
#include "cpu.h"
|
||||||
@@ -10,7 +10,6 @@
|
|||||||
#include "logger.h"
|
#include "logger.h"
|
||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "objects/process.h"
|
#include "objects/process.h"
|
||||||
#include "printf/printf.h"
|
|
||||||
#include "scheduler.h"
|
#include "scheduler.h"
|
||||||
#include "vm_space.h"
|
#include "vm_space.h"
|
||||||
|
|
||||||
@@ -105,10 +104,10 @@ isr_handler(cpu_state *regs)
|
|||||||
(!ti) ? "GDT" :
|
(!ti) ? "GDT" :
|
||||||
"LDT";
|
"LDT";
|
||||||
|
|
||||||
snprintf(message, sizeof(message), "General Protection Fault, error:0x%lx%s %s[%d]",
|
util::format({message, sizeof(message)}, "General Protection Fault, error:0x%lx%s %s[%d]",
|
||||||
regs->errorcode, regs->errorcode & 1 ? " external" : "", table, index);
|
regs->errorcode, regs->errorcode & 1 ? " external" : "", table, index);
|
||||||
} else {
|
} else {
|
||||||
snprintf(message, sizeof(message), "General Protection Fault, error:%lx%s",
|
util::format({message, sizeof(message)}, "General Protection Fault, error:%lx%s",
|
||||||
regs->errorcode, regs->errorcode & 1 ? " external" : "");
|
regs->errorcode, regs->errorcode & 1 ? " external" : "");
|
||||||
}
|
}
|
||||||
kassert(false, message, regs);
|
kassert(false, message, regs);
|
||||||
@@ -129,7 +128,7 @@ isr_handler(cpu_state *regs)
|
|||||||
if (cr2 && space.handle_fault(cr2, ft))
|
if (cr2 && space.handle_fault(cr2, ft))
|
||||||
break;
|
break;
|
||||||
|
|
||||||
snprintf(message, sizeof(message),
|
util::format({message, sizeof(message)},
|
||||||
"Page fault: %016lx%s%s%s%s%s", cr2,
|
"Page fault: %016lx%s%s%s%s%s", cr2,
|
||||||
(regs->errorcode & 0x01) ? " present" : "",
|
(regs->errorcode & 0x01) ? " present" : "",
|
||||||
(regs->errorcode & 0x02) ? " write" : "",
|
(regs->errorcode & 0x02) ? " write" : "",
|
||||||
@@ -157,7 +156,7 @@ isr_handler(cpu_state *regs)
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
snprintf(message, sizeof(message), "Unknown interrupt 0x%lx", regs->interrupt);
|
util::format({message, sizeof(message)}, "Unknown interrupt 0x%lx", regs->interrupt);
|
||||||
kassert(false, message, regs);
|
kassert(false, message, regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ kernel = module("kernel",
|
|||||||
"page_table.cpp",
|
"page_table.cpp",
|
||||||
"page_tree.cpp",
|
"page_tree.cpp",
|
||||||
"pci.cpp",
|
"pci.cpp",
|
||||||
"printf/printf.c",
|
|
||||||
"scheduler.cpp",
|
"scheduler.cpp",
|
||||||
"smp.cpp",
|
"smp.cpp",
|
||||||
"smp.s",
|
"smp.s",
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
#include <new>
|
#include <new>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <util/format.h>
|
||||||
#include <util/no_construct.h>
|
#include <util/no_construct.h>
|
||||||
|
|
||||||
#include "assert.h"
|
#include "assert.h"
|
||||||
@@ -8,7 +9,6 @@
|
|||||||
#include "memory.h"
|
#include "memory.h"
|
||||||
#include "objects/system.h"
|
#include "objects/system.h"
|
||||||
#include "objects/thread.h"
|
#include "objects/thread.h"
|
||||||
#include "printf/printf.h"
|
|
||||||
|
|
||||||
static uint8_t log_buffer[128 * 1024];
|
static uint8_t log_buffer[128 * 1024];
|
||||||
|
|
||||||
@@ -18,9 +18,6 @@ static uint8_t log_buffer[128 * 1024];
|
|||||||
static util::no_construct<log::logger> __g_logger_storage;
|
static util::no_construct<log::logger> __g_logger_storage;
|
||||||
log::logger &g_logger = __g_logger_storage.value;
|
log::logger &g_logger = __g_logger_storage.value;
|
||||||
|
|
||||||
// For printf.c
|
|
||||||
extern "C" void putchar_(char c) {}
|
|
||||||
|
|
||||||
|
|
||||||
namespace log {
|
namespace log {
|
||||||
|
|
||||||
@@ -33,19 +30,15 @@ const char *logger::s_area_names[] = {
|
|||||||
nullptr
|
nullptr
|
||||||
};
|
};
|
||||||
|
|
||||||
logger::logger(logger::immediate_cb output) :
|
logger::logger() :
|
||||||
m_buffer(nullptr, 0),
|
m_buffer(nullptr, 0)
|
||||||
m_immediate(output),
|
|
||||||
m_sequence(0)
|
|
||||||
{
|
{
|
||||||
memset(&m_levels, 0, sizeof(m_levels));
|
memset(&m_levels, 0, sizeof(m_levels));
|
||||||
s_log = this;
|
s_log = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
logger::logger(uint8_t *buffer, size_t size, logger::immediate_cb output) :
|
logger::logger(uint8_t *buffer, size_t size) :
|
||||||
m_buffer(buffer, size),
|
m_buffer(buffer, size)
|
||||||
m_immediate(output),
|
|
||||||
m_sequence(0)
|
|
||||||
{
|
{
|
||||||
memset(&m_levels, 0, sizeof(m_levels));
|
memset(&m_levels, 0, sizeof(m_levels));
|
||||||
s_log = this;
|
s_log = this;
|
||||||
@@ -64,20 +57,13 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
|||||||
header->bytes = sizeof(entry);
|
header->bytes = sizeof(entry);
|
||||||
header->area = area;
|
header->area = area;
|
||||||
header->severity = severity;
|
header->severity = severity;
|
||||||
header->sequence = m_sequence++;
|
|
||||||
|
|
||||||
size_t mlen = vsnprintf(header->message, sizeof(buffer) - sizeof(entry) - 1, fmt, args);
|
size_t mlen = util::vformat({header->message, sizeof(buffer) - sizeof(entry) - 1}, fmt, args);
|
||||||
header->message[mlen] = 0;
|
header->message[mlen] = 0;
|
||||||
header->bytes += mlen + 1;
|
header->bytes += mlen + 1;
|
||||||
|
|
||||||
util::scoped_lock lock {m_lock};
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
if (m_immediate) {
|
|
||||||
buffer[header->bytes] = 0;
|
|
||||||
m_immediate(area, severity, header->message);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8_t *out;
|
uint8_t *out;
|
||||||
size_t n = m_buffer.reserve(header->bytes, reinterpret_cast<void**>(&out));
|
size_t n = m_buffer.reserve(header->bytes, reinterpret_cast<void**>(&out));
|
||||||
if (n < header->bytes) {
|
if (n < header->bytes) {
|
||||||
@@ -94,13 +80,14 @@ logger::output(level severity, logs area, const char *fmt, va_list args)
|
|||||||
size_t
|
size_t
|
||||||
logger::get_entry(void *buffer, size_t size)
|
logger::get_entry(void *buffer, size_t size)
|
||||||
{
|
{
|
||||||
|
|
||||||
util::scoped_lock lock {m_lock};
|
util::scoped_lock lock {m_lock};
|
||||||
|
|
||||||
void *out;
|
void *out;
|
||||||
size_t out_size = m_buffer.get_block(&out);
|
size_t out_size = m_buffer.get_block(&out);
|
||||||
if (out_size == 0 || out == 0) {
|
if (out_size == 0 || out == 0) {
|
||||||
|
lock.release();
|
||||||
m_event.wait();
|
m_event.wait();
|
||||||
|
lock.reacquire();
|
||||||
out_size = m_buffer.get_block(&out);
|
out_size = m_buffer.get_block(&out);
|
||||||
|
|
||||||
if (out_size == 0 || out == 0)
|
if (out_size == 0 || out == 0)
|
||||||
@@ -155,5 +142,5 @@ void fatal(logs area, const char *fmt, ...)
|
|||||||
|
|
||||||
void logger_init()
|
void logger_init()
|
||||||
{
|
{
|
||||||
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer), nullptr);
|
new (&g_logger) log::logger(log_buffer, sizeof(log_buffer));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,24 +29,13 @@ constexpr unsigned areas_count =
|
|||||||
class logger
|
class logger
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
/// Callback type for immediate-mode logging
|
|
||||||
typedef void (*immediate_cb)(logs, level, const char *);
|
|
||||||
|
|
||||||
/// Default constructor. Creates a logger without a backing store.
|
/// Default constructor. Creates a logger without a backing store.
|
||||||
/// \arg output Immediate-mode logging output function
|
logger();
|
||||||
logger(immediate_cb output = nullptr);
|
|
||||||
|
|
||||||
/// Constructor. Logs are written to the given buffer.
|
/// Constructor. Logs are written to the given buffer.
|
||||||
/// \arg buffer Buffer to which logs are written
|
/// \arg buffer Buffer to which logs are written
|
||||||
/// \arg size Size of `buffer`, in bytes
|
/// \arg size Size of `buffer`, in bytes
|
||||||
/// \arg output Immediate-mode logging output function
|
logger(uint8_t *buffer, size_t size);
|
||||||
logger(uint8_t *buffer, size_t size, immediate_cb output = nullptr);
|
|
||||||
|
|
||||||
/// Get the current immediate-mode callback
|
|
||||||
inline immediate_cb get_immediate() const { return m_immediate; }
|
|
||||||
|
|
||||||
/// Register an immediate-mode log callback
|
|
||||||
inline void set_immediate(immediate_cb cb) { m_immediate = cb; }
|
|
||||||
|
|
||||||
/// Get the default logger.
|
/// Get the default logger.
|
||||||
inline logger & get() { return *s_log; }
|
inline logger & get() { return *s_log; }
|
||||||
@@ -78,7 +67,6 @@ public:
|
|||||||
uint8_t bytes;
|
uint8_t bytes;
|
||||||
logs area;
|
logs area;
|
||||||
level severity;
|
level severity;
|
||||||
uint8_t sequence;
|
|
||||||
char message[0];
|
char message[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -112,9 +100,6 @@ private:
|
|||||||
obj::event m_event;
|
obj::event m_event;
|
||||||
|
|
||||||
level m_levels[areas_count];
|
level m_levels[areas_count];
|
||||||
immediate_cb m_immediate;
|
|
||||||
|
|
||||||
uint8_t m_sequence;
|
|
||||||
|
|
||||||
util::bip_buffer m_buffer;
|
util::bip_buffer m_buffer;
|
||||||
util::spinlock m_lock;
|
util::spinlock m_lock;
|
||||||
|
|||||||
133
src/libraries/util/format.cpp
Normal file
133
src/libraries/util/format.cpp
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
#include <stdarg.h>
|
||||||
|
#include <util/format.h>
|
||||||
|
|
||||||
|
namespace util {
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
const char digits[] = "0123456789abcdef";
|
||||||
|
|
||||||
|
template <typename I, unsigned N> void
|
||||||
|
append_int(char *&out, size_t &count, size_t max, I value, unsigned min_width, char pad)
|
||||||
|
{
|
||||||
|
static constexpr size_t bufsize = sizeof(I)*3;
|
||||||
|
|
||||||
|
unsigned num_digits = 0;
|
||||||
|
char buffer[bufsize];
|
||||||
|
char *p = buffer + (bufsize - 1);
|
||||||
|
do {
|
||||||
|
if (value) {
|
||||||
|
*p-- = digits[value % N];
|
||||||
|
value /= N;
|
||||||
|
} else {
|
||||||
|
*p-- = num_digits ? pad : '0';
|
||||||
|
}
|
||||||
|
num_digits++;
|
||||||
|
} while (value || num_digits < min_width);
|
||||||
|
|
||||||
|
++p;
|
||||||
|
for (unsigned i = 0; i < num_digits; ++i) {
|
||||||
|
*out++ = p[i];
|
||||||
|
if (++count == max)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
append_string(char *&out, size_t &count, size_t max, char const *value)
|
||||||
|
{
|
||||||
|
while (value && *value && count < max) {
|
||||||
|
count++;
|
||||||
|
*out++ = *value++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
size_t
|
||||||
|
vformat(stringbuf output, char const *format, va_list va)
|
||||||
|
{
|
||||||
|
char * out = output.pointer;
|
||||||
|
const size_t max = output.count - 1;
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
while (format && *format && count < max) {
|
||||||
|
if (*format != '%') {
|
||||||
|
count++;
|
||||||
|
*out++ = *format++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
format++; // chomp the % character
|
||||||
|
char spec = *format++;
|
||||||
|
|
||||||
|
bool long_type = false;
|
||||||
|
if (spec == '%') {
|
||||||
|
count++;
|
||||||
|
*out++ = '%';
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned width = 0;
|
||||||
|
char pad = ' ';
|
||||||
|
|
||||||
|
while (spec) {
|
||||||
|
bool done = false;
|
||||||
|
|
||||||
|
if (spec >= '0' && spec <= '9') {
|
||||||
|
if (spec == '0' && width == 0)
|
||||||
|
pad = '0';
|
||||||
|
else
|
||||||
|
width = width * 10 + (spec - '0');
|
||||||
|
|
||||||
|
spec = *format++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (spec) {
|
||||||
|
case 'l':
|
||||||
|
long_type = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'x':
|
||||||
|
if (long_type)
|
||||||
|
append_int<uint64_t, 16>(out, count, max, va_arg(va, uint64_t), width, pad);
|
||||||
|
else
|
||||||
|
append_int<uint32_t, 16>(out, count, max, va_arg(va, uint32_t), width, pad);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
case 'u':
|
||||||
|
if (long_type)
|
||||||
|
append_int<uint64_t, 10>(out, count, max, va_arg(va, uint64_t), width, pad);
|
||||||
|
else
|
||||||
|
append_int<uint32_t, 10>(out, count, max, va_arg(va, uint32_t), width, pad);
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
append_string(out, count, max, va_arg(va, const char *));
|
||||||
|
done = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (done) break;
|
||||||
|
spec = *format++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t
|
||||||
|
format(stringbuf output, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list va;
|
||||||
|
va_start(va, format);
|
||||||
|
size_t result = vformat(output, format, va);
|
||||||
|
va_end(va);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
} //namespace util
|
||||||
@@ -4,6 +4,7 @@ module("util",
|
|||||||
kind = "lib",
|
kind = "lib",
|
||||||
sources = [
|
sources = [
|
||||||
"bip_buffer.cpp",
|
"bip_buffer.cpp",
|
||||||
|
"format.cpp",
|
||||||
"spinlock.cpp",
|
"spinlock.cpp",
|
||||||
],
|
],
|
||||||
public_headers = [
|
public_headers = [
|
||||||
@@ -13,6 +14,7 @@ module("util",
|
|||||||
"util/counted.h",
|
"util/counted.h",
|
||||||
"util/deque.h",
|
"util/deque.h",
|
||||||
"util/enum_bitfields.h",
|
"util/enum_bitfields.h",
|
||||||
|
"util/format.h",
|
||||||
"util/hash.h",
|
"util/hash.h",
|
||||||
"util/linked_list.h",
|
"util/linked_list.h",
|
||||||
"util/map.h",
|
"util/map.h",
|
||||||
|
|||||||
16
src/libraries/util/util/format.h
Normal file
16
src/libraries/util/util/format.h
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/// \file format.h
|
||||||
|
/// sprintf-like format functions
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <util/counted.h>
|
||||||
|
|
||||||
|
namespace util {
|
||||||
|
|
||||||
|
using stringbuf = counted<char>;
|
||||||
|
|
||||||
|
size_t format(stringbuf output, const char *format, ...);
|
||||||
|
size_t vformat(stringbuf output, const char *format, va_list va);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -25,7 +25,6 @@ struct entry
|
|||||||
uint8_t bytes;
|
uint8_t bytes;
|
||||||
uint8_t area;
|
uint8_t area;
|
||||||
uint8_t severity;
|
uint8_t severity;
|
||||||
uint8_t sequence;
|
|
||||||
char message[0];
|
char message[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user