initgraph, whole lot of refactor
This commit is contained in:
+149
-6
@@ -1,22 +1,22 @@
|
||||
#include <zinnia/clock.h>
|
||||
#include <zinnia/console.h>
|
||||
#include <zinnia/panic.h>
|
||||
#include <zinnia/percpu.h>
|
||||
#include <zinnia/print.h>
|
||||
#include <zinnia/sched.h>
|
||||
#include <zinnia/spin.h>
|
||||
#include <zinnia/stdlib.h>
|
||||
#include <zinnia/string.h>
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
typedef void (*log_fn_t)(void* ctx, const char* buf, size_t len);
|
||||
#include <string.h>
|
||||
|
||||
static void print_pad(log_fn_t callback, void* ctx, char c, size_t count) {
|
||||
for (size_t i = 0; i < count; i++)
|
||||
callback(ctx, &c, 1);
|
||||
}
|
||||
|
||||
static void do_print(log_fn_t callback, void* ctx, const char* restrict fmt, va_list args) {
|
||||
void print_fmt(log_fn_t callback, void* ctx, const char* restrict fmt, va_list args) {
|
||||
// Amount of bytes written.
|
||||
int32_t written = 0;
|
||||
|
||||
@@ -320,16 +320,159 @@ void kprintf(const char* message, ...) {
|
||||
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
do_print(printf_console, nullptr, message, args);
|
||||
print_fmt(printf_console, nullptr, message, args);
|
||||
va_end(args);
|
||||
|
||||
spin_unlock(&print_lock);
|
||||
}
|
||||
|
||||
struct snprintf_ctx {
|
||||
char* buf;
|
||||
size_t size;
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static void snprintf_write(void* ctx, const char* str, size_t len) {
|
||||
struct snprintf_ctx* c = ctx;
|
||||
// Always keep room for the terminator.
|
||||
if (c->len < c->size) {
|
||||
size_t room = c->size - c->len - 1;
|
||||
memcpy(c->buf + c->len, str, len < room ? len : room);
|
||||
}
|
||||
c->len += len;
|
||||
}
|
||||
|
||||
size_t kvsnprintf(char* buf, size_t size, const char* format, va_list args) {
|
||||
struct snprintf_ctx ctx = {.buf = buf, .size = size};
|
||||
print_fmt(snprintf_write, &ctx, format, args);
|
||||
if (size > 0)
|
||||
buf[ctx.len < size ? ctx.len : size - 1] = '\0';
|
||||
return ctx.len;
|
||||
}
|
||||
|
||||
size_t ksnprintf(char* buf, size_t size, const char* format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
size_t len = kvsnprintf(buf, size, format, args);
|
||||
va_end(args);
|
||||
return len;
|
||||
}
|
||||
|
||||
void kvprintf(const char* message, va_list args) {
|
||||
spin_lock(&print_lock);
|
||||
|
||||
do_print(printf_console, nullptr, message, args);
|
||||
print_fmt(printf_console, nullptr, message, args);
|
||||
|
||||
spin_unlock(&print_lock);
|
||||
}
|
||||
|
||||
struct log_record {
|
||||
uint64_t time_ns;
|
||||
uint32_t tid;
|
||||
uint16_t len;
|
||||
uint8_t level;
|
||||
};
|
||||
|
||||
#define LOG_BUFFER_SIZE (64 * 1024)
|
||||
#define LOG_MESSAGE_MAX 255
|
||||
|
||||
static uint8_t log_buffer[LOG_BUFFER_SIZE];
|
||||
|
||||
// Protected by print_lock.
|
||||
static size_t log_head = 0;
|
||||
static size_t log_tail = 0;
|
||||
|
||||
static void log_ring_copy_in(const void* src, size_t len) {
|
||||
for (size_t i = 0; i < len; i++)
|
||||
log_buffer[(log_head + i) % LOG_BUFFER_SIZE] = ((const uint8_t*)src)[i];
|
||||
log_head += len;
|
||||
}
|
||||
|
||||
static void log_ring_peek(size_t offset, void* dst, size_t len) {
|
||||
for (size_t i = 0; i < len; i++)
|
||||
((uint8_t*)dst)[i] = log_buffer[(offset + i) % LOG_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
static void log_store(const struct log_record* rec, const char* msg) {
|
||||
const size_t total = sizeof(*rec) + rec->len;
|
||||
|
||||
// Drop the oldest records until the new one fits.
|
||||
while (LOG_BUFFER_SIZE - (log_head - log_tail) < total) {
|
||||
struct log_record old;
|
||||
log_ring_peek(log_tail, &old, sizeof(old));
|
||||
log_tail += sizeof(old) + old.len;
|
||||
}
|
||||
|
||||
log_ring_copy_in(rec, sizeof(*rec));
|
||||
log_ring_copy_in(msg, rec->len);
|
||||
}
|
||||
|
||||
struct log_line {
|
||||
char buf[LOG_MESSAGE_MAX];
|
||||
size_t len;
|
||||
};
|
||||
|
||||
static void log_line_append(void* ctx, const char* str, size_t len) {
|
||||
struct log_line* line = ctx;
|
||||
if (len > sizeof(line->buf) - line->len)
|
||||
len = sizeof(line->buf) - line->len;
|
||||
memcpy(line->buf + line->len, str, len);
|
||||
line->len += len;
|
||||
}
|
||||
|
||||
// ANSI colors for each level.
|
||||
static const char* const log_level_colors[] = {
|
||||
[LOG_DEBUG] = "\e[90m",
|
||||
[LOG_STATUS] = "\e[32m",
|
||||
[LOG_INFO] = "",
|
||||
[LOG_WARN] = "\e[33m",
|
||||
[LOG_ERR] = "\e[31m",
|
||||
[LOG_PANIC] = "\e[1;31m",
|
||||
};
|
||||
|
||||
static void log_console_printf(const char* fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
print_fmt(printf_console, nullptr, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
void log_vwrite(enum log_level level, const char* message, va_list args) {
|
||||
log_vwrite_prefixed(level, "", message, args);
|
||||
}
|
||||
|
||||
void log_vwrite_prefixed(enum log_level level, const char* prefix, const char* message, va_list args) {
|
||||
struct log_line line = {};
|
||||
log_line_append(&line, prefix, strlen(prefix));
|
||||
print_fmt(log_line_append, &line, message, args);
|
||||
if (line.len > 0 && line.buf[line.len - 1] == '\n')
|
||||
line.len--;
|
||||
|
||||
auto cur = percpu_get()->sched.current;
|
||||
const struct log_record rec = {
|
||||
.time_ns = clock_get_elapsed_ns(),
|
||||
.tid = cur ? cur->id : 0,
|
||||
.len = line.len,
|
||||
.level = level,
|
||||
};
|
||||
|
||||
spin_lock(&print_lock);
|
||||
log_store(&rec, line.buf);
|
||||
log_console_printf(
|
||||
"[%5lu.%06lu] [%5lu] %s",
|
||||
rec.time_ns / 1'000'000'000,
|
||||
rec.time_ns / 1'000 % 1'000'000,
|
||||
(uint64_t)rec.tid,
|
||||
log_level_colors[level]
|
||||
);
|
||||
console_write(line.buf, line.len);
|
||||
console_write("\e[0m\n", 5);
|
||||
spin_unlock(&print_lock);
|
||||
}
|
||||
|
||||
void log_write(enum log_level level, const char* message, ...) {
|
||||
va_list args;
|
||||
va_start(args, message);
|
||||
log_vwrite(level, message, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user