blob: caf7c07071823ba1b96beecc93a58a90a90b5287 [file] [log] [blame]
// Copyright 2019 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <zircon/process.h>
#include <zircon/syscalls.h>
#include <zircon/syscalls/log.h>
#include "vc.h"
static zx_koid_t proc_koid;
static port_handler_t log_ph;
static vc_t* log_vc;
// This is the list for logs on displays other than the main display.
static struct list_node log_list = LIST_INITIAL_VALUE(log_list);
void set_log_listener_active(bool active) {
if (active) {
port_wait(&port, &log_ph);
} else {
port_cancel(&port, &log_ph);
}
}
zx_status_t log_create_vc(vc_gfx_t* graphics, vc_t** vc_out) {
vc_t* vc;
zx_status_t status = vc_alloc(&vc, &color_schemes[kDefaultColorScheme]);
if (status != ZX_OK) {
return status;
}
// Copy the log buffer into the new vc.
size_t textbuf_size = log_vc->rows * log_vc->columns * sizeof(vc_char_t);
memcpy(vc->text_buf, log_vc->text_buf, textbuf_size);
vc->cursor_x = log_vc->cursor_x;
vc->cursor_y = log_vc->cursor_y;
// Set the new vc graphics and flush the text.
vc->active = true;
vc->graphics = graphics;
vc_attach_gfx(vc);
vc_full_repaint(vc);
list_add_tail(&log_list, &vc->node);
*vc_out = vc;
return ZX_OK;
}
void log_delete_vc(vc_t* vc) {
list_delete(&vc->node);
vc_free(vc);
}
int log_start(void) {
// Create initial console for debug log.
if (vc_create(&log_vc, &color_schemes[kDefaultColorScheme]) != ZX_OK) {
return -1;
}
snprintf(log_vc->title, sizeof(log_vc->title), "debuglog");
// Get our process koid so the log reader can
// filter out our own debug messages from the log.
zx_info_handle_basic_t info;
if (zx_object_get_info(zx_process_self(), ZX_INFO_HANDLE_BASIC, &info, sizeof(info), NULL,
NULL) == ZX_OK) {
proc_koid = info.koid;
}
log_ph.handle = zx_take_startup_handle(PA_HND(PA_USER0, 1));
if (log_ph.handle == ZX_HANDLE_INVALID) {
printf("vc log listener: did not receive log startup handle\n");
return -1;
}
log_ph.func = log_reader_cb;
log_ph.waitfor = ZX_LOG_READABLE;
return 0;
}
static void write_to_log(vc_t* vc, zx_log_record_t* rec) {
char tmp[64];
snprintf(tmp, 64,
"\033[32m%05d.%03d\033[39m] \033[31m%05" PRIu64 ".\033[36m%05" PRIu64 "\033[39m> ",
(int)(rec->timestamp / 1000000000ULL), (int)((rec->timestamp / 1000000ULL) % 1000ULL),
rec->pid, rec->tid);
vc_write(vc, tmp, strlen(tmp), 0);
vc_write(vc, rec->data, rec->datalen, 0);
if ((rec->datalen == 0) || (rec->data[rec->datalen - 1] != '\n')) {
vc_write(vc, "\n", 1, 0);
}
}
zx_status_t log_reader_cb(port_handler_t* ph, zx_signals_t signals, uint32_t evt) {
char buf[ZX_LOG_RECORD_MAX];
zx_log_record_t* rec = (zx_log_record_t*)buf;
zx_status_t status;
for (;;) {
if ((status = zx_debuglog_read(ph->handle, 0, rec, ZX_LOG_RECORD_MAX)) < 0) {
if (status == ZX_ERR_SHOULD_WAIT) {
return ZX_OK;
}
break;
}
// Don't print log messages from ourself.
if (rec->pid == proc_koid) {
continue;
}
write_to_log(log_vc, rec);
vc_t* vc = NULL;
list_for_every_entry (&log_list, vc, vc_t, node) { write_to_log(vc, rec); }
}
const char* oops = "<<LOG ERROR>>\n";
vc_write(log_vc, oops, strlen(oops), 0);
// Error reading the log, no point in continuing to try to read
// log messages.
port_cancel(&port, &log_ph);
return status;
}