HelenOS sources
This source file includes following definitions.
- log_init
- log_copy_from
- log_copy_to
- log_append
- log_begin
- log_end
- log_update
- log_printf_str_write
- log_printf_wstr_write
- log_vprintf
- log_printf
- log
- sys_klog
#include <sysinfo/sysinfo.h>
#include <synch/spinlock.h>
#include <typedefs.h>
#include <ddi/irq.h>
#include <ddi/ddi.h>
#include <ipc/event.h>
#include <ipc/irq.h>
#include <arch.h>
#include <panic.h>
#include <putchar.h>
#include <atomic.h>
#include <syscall/copy.h>
#include <errno.h>
#include <str.h>
#include <print.h>
#include <printf/printf_core.h>
#include <stdarg.h>
#include <log.h>
#include <console/console.h>
#include <abi/log.h>
#include <stdlib.h>
#define LOG_PAGES 8
#define LOG_LENGTH (LOG_PAGES * PAGE_SIZE)
#define LOG_ENTRY_HEADER_LENGTH (sizeof(size_t) + sizeof(uint32_t))
uint8_t log_buffer[LOG_LENGTH] __attribute__((aligned(PAGE_SIZE)));
static atomic_bool log_inited = false;
size_t log_start = 0;
size_t log_used = 0;
SPINLOCK_STATIC_INITIALIZE_NAME(log_lock, "log_lock");
static uint32_t log_counter = 0;
static size_t log_current_start = 0;
static size_t log_current_len = 0;
static size_t next_for_uspace = 0;
static void log_update(void *);
void log_init(void)
{
event_set_unmask_callback(EVENT_KLOG, log_update);
atomic_store(&log_inited, true);
}
static size_t log_copy_from(uint8_t *data, size_t pos, size_t len)
{
for (size_t i = 0; i < len; i++, pos = (pos + 1) % LOG_LENGTH) {
data[i] = log_buffer[pos];
}
return pos;
}
static size_t log_copy_to(const uint8_t *data, size_t pos, size_t len)
{
for (size_t i = 0; i < len; i++, pos = (pos + 1) % LOG_LENGTH) {
log_buffer[pos] = data[i];
}
return pos;
}
static void log_append(const uint8_t *data, size_t len)
{
if (len > LOG_LENGTH - log_current_len) {
len = LOG_LENGTH - log_current_len;
}
if (len == 0)
return;
size_t log_free = LOG_LENGTH - log_used - log_current_len;
while (len > log_free) {
size_t entry_len;
log_copy_from((uint8_t *) &entry_len, log_start, sizeof(size_t));
log_start = (log_start + entry_len) % LOG_LENGTH;
log_used -= entry_len;
log_free += entry_len;
next_for_uspace -= entry_len;
}
size_t pos = (log_current_start + log_current_len) % LOG_LENGTH;
log_copy_to(data, pos, len);
log_current_len += len;
}
void log_begin(log_facility_t fac, log_level_t level)
{
spinlock_lock(&log_lock);
spinlock_lock(&kio_lock);
log_current_start = (log_start + log_used) % LOG_LENGTH;
log_current_len = 0;
log_append((uint8_t *) &log_current_len, sizeof(size_t));
log_append((uint8_t *) &log_counter, sizeof(uint32_t));
uint32_t fac32 = fac;
uint32_t lvl32 = level;
log_append((uint8_t *) &fac32, sizeof(uint32_t));
log_append((uint8_t *) &lvl32, sizeof(uint32_t));
log_counter++;
}
void log_end(void)
{
log_copy_to((uint8_t *) &log_current_len, log_current_start, sizeof(size_t));
log_used += log_current_len;
kio_push_char('\n');
spinlock_unlock(&kio_lock);
spinlock_unlock(&log_lock);
kio_flush();
kio_update(NULL);
log_update(NULL);
}
static void log_update(void *event)
{
if (!atomic_load(&log_inited))
return;
spinlock_lock(&log_lock);
if (next_for_uspace < log_used)
event_notify_0(EVENT_KLOG, true);
spinlock_unlock(&log_lock);
}
static int log_printf_str_write(const char *str, size_t size, void *data)
{
size_t offset = 0;
size_t chars = 0;
while (offset < size) {
kio_push_char(str_decode(str, &offset, size));
chars++;
}
log_append((const uint8_t *)str, size);
return chars;
}
static int log_printf_wstr_write(const char32_t *wstr, size_t size, void *data)
{
char buffer[16];
size_t offset = 0;
size_t chars = 0;
for (offset = 0; offset < size; offset += sizeof(char32_t), chars++) {
kio_push_char(wstr[chars]);
size_t buffer_offset = 0;
errno_t rc = chr_encode(wstr[chars], buffer, &buffer_offset, 16);
if (rc != EOK) {
return EOF;
}
log_append((const uint8_t *)buffer, buffer_offset);
}
return chars;
}
int log_vprintf(const char *fmt, va_list args)
{
int ret;
printf_spec_t ps = {
log_printf_str_write,
log_printf_wstr_write,
NULL
};
ret = printf_core(fmt, &ps, args);
return ret;
}
int log_printf(const char *fmt, ...)
{
int ret;
va_list args;
va_start(args, fmt);
ret = log_vprintf(fmt, args);
va_end(args);
return ret;
}
int log(log_facility_t fac, log_level_t level, const char *fmt, ...)
{
int ret;
va_list args;
log_begin(fac, level);
va_start(args, fmt);
ret = log_vprintf(fmt, args);
va_end(args);
log_end();
return ret;
}
sys_errno_t sys_klog(sysarg_t operation, uspace_addr_t buf, size_t size,
sysarg_t level, uspace_ptr_size_t uspace_nread)
{
char *data;
errno_t rc;
if (size > PAGE_SIZE)
return (sys_errno_t) ELIMIT;
switch (operation) {
case KLOG_WRITE:
data = (char *) malloc(size + 1);
if (!data)
return (sys_errno_t) ENOMEM;
rc = copy_from_uspace(data, buf, size);
if (rc) {
free(data);
return (sys_errno_t) rc;
}
data[size] = 0;
if (level >= LVL_LIMIT)
level = LVL_NOTE;
log(LF_USPACE, level, "%s", data);
free(data);
return EOK;
case KLOG_READ:
data = (char *) malloc(size);
if (!data)
return (sys_errno_t) ENOMEM;
size_t entry_len = 0;
size_t copied = 0;
rc = EOK;
spinlock_lock(&log_lock);
while (next_for_uspace < log_used) {
size_t pos = (log_start + next_for_uspace) % LOG_LENGTH;
log_copy_from((uint8_t *) &entry_len, pos, sizeof(size_t));
if (entry_len > PAGE_SIZE) {
next_for_uspace += entry_len;
continue;
}
if (size < copied + entry_len) {
if (copied == 0)
rc = EOVERFLOW;
break;
}
log_copy_from((uint8_t *) (data + copied), pos, entry_len);
copied += entry_len;
next_for_uspace += entry_len;
}
spinlock_unlock(&log_lock);
if (rc != EOK) {
free(data);
return (sys_errno_t) rc;
}
rc = copy_to_uspace(buf, data, size);
free(data);
if (rc != EOK)
return (sys_errno_t) rc;
return copy_to_uspace(uspace_nread, &copied, sizeof(copied));
return EOK;
default:
return (sys_errno_t) ENOTSUP;
}
}
HelenOS homepage, sources at GitHub