Implement LOG to Terminal adapter (issue #169)

This commit adds a terminal_log component, and a run-script which demonstrates
its usage. The terminal_log component provides the LOG service, and prints
every log-output prefixed by the session-label via a terminal-session.
This commit is contained in:
Stefan Kalkowski 2012-05-21 15:39:57 +02:00 committed by Norman Feske
parent 3bffcc17de
commit bd3c53be31
3 changed files with 330 additions and 0 deletions

160
gems/run/terminal_log.run Normal file
View File

@ -0,0 +1,160 @@
#
# \brief Showcases terminal_log server
# \author Stefan Kalkowski
# \date 2012-05-21
#
build {
core
init
drivers/framebuffer
drivers/input
drivers/pci
server/nitpicker
server/nit_fb
server/terminal
server/terminal_log
}
create_boot_directory
append config {
<config>
<parent-provides>
<service name="ROM"/>
<service name="RAM"/>
<service name="IRQ"/>
<service name="IO_MEM"/>
<service name="IO_PORT"/>
<service name="CAP"/>
<service name="PD"/>
<service name="RM"/>
<service name="CPU"/>
<service name="LOG"/>
<service name="SIGNAL"/>
</parent-provides>
<default-route>
<service name="Nitpicker"> <child name="nitpicker"/> </service>
<service name="Timer"> <child name="timer"/> </service>
<service name="Terminal"> <child name="terminal"/> </service>
<service name="PCI"> <child name="pci_drv"/> </service>
<any-service><parent/></any-service>
</default-route>
<start name="timer">
<resource name="RAM" quantum="1M"/>
<provides><service name="Timer"/></provides>
</start>
}
append_if [have_spec sdl] config {
<start name="fb_sdl">
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Input"/>
<service name="Framebuffer"/>
</provides>
</start>
<start name="nitpicker">
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<route>
<service name="Input"> <child name="fb_sdl"/> </service>
<service name="Framebuffer"> <child name="fb_sdl"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
append_if [have_spec pci] config {
<start name="pci_drv">
<resource name="RAM" quantum="1M"/>
<provides><service name="PCI"/></provides>
</start>}
append_if [have_spec vesa] config {
<start name="fb_drv">
<binary name="vesa_drv"/>
<resource name="RAM" quantum="1M"/>
<provides><service name="Framebuffer"/></provides>
</start>}
append_if [have_spec pl11x] config {
<start name="fb_drv">
<binary name="pl11x_drv"/>
<resource name="RAM" quantum="2M"/>
<provides><service name="Framebuffer"/></provides>
</start>}
append_if [have_spec ps2] config {
<start name="input_drv">
<binary name="ps2_drv"/>
<resource name="RAM" quantum="1M"/>
<provides><service name="Input"/></provides>
</start> }
append_if [expr ! [have_spec sdl]] config {
<start name="nitpicker">
<resource name="RAM" quantum="1M"/>
<provides><service name="Nitpicker"/></provides>
<route>
<service name="Input"> <child name="input_drv"/> </service>
<service name="Framebuffer"> <child name="fb_drv"/> </service>
<any-service> <parent/> <any-child/> </any-service>
</route>
</start>}
append config {
<start name="terminal_fb">
<binary name="nit_fb"/>
<resource name="RAM" quantum="4M"/>
<provides>
<service name="Framebuffer"/>
<service name="Input"/>
</provides>
<config xpos="0" ypos="0" width="640" height="480" refresh_rate="25"/>
</start>
<start name="terminal">
<resource name="RAM" quantum="3M"/>
<provides><service name="Terminal"/></provides>
<route>
<service name="Input"> <child name="terminal_fb"/> </service>
<service name="Framebuffer"> <child name="terminal_fb"/> </service>
<any-service> <parent/> <any-child/></any-service>
</route>
</start>
<start name="terminal_log">
<resource name="RAM" quantum="1M"/>
<provides><service name="LOG"/></provides>
</start>
<start name="launchpad">
<resource name="RAM" quantum="32M"/>
<route>
<service name="LOG"> <child name="terminal_log"/> </service>
<any-service> <any-child/> <parent/></any-service>
</route>
</start>
</config>
}
install_config $config
# generic modules
set boot_modules {
core init
timer
nitpicker
launchpad
testnit
nit_fb
terminal
terminal_log
}
# platform-specific modules
lappend_if [have_spec linux] boot_modules fb_sdl
lappend_if [have_spec pci] boot_modules pci_drv
lappend_if [have_spec vesa] boot_modules vesa_drv
lappend_if [have_spec ps2] boot_modules ps2_drv
lappend_if [have_spec pl11x] boot_modules pl11x_drv
build_boot_image $boot_modules
append qemu_args " -m 256 "
run_genode_until forever

View File

@ -0,0 +1,167 @@
/*
* \brief LOG service that prints to a terminal
* \author Stefan Kalkowski
* \date 2012-05-21
*/
/*
* Copyright (C) 2012 Genode Labs GmbH
*
* This file is part of the Genode OS framework, which is distributed
* under the terms of the GNU General Public License version 2.
*/
#include <base/env.h>
#include <base/rpc_server.h>
#include <base/sleep.h>
#include <root/component.h>
#include <util/string.h>
#include <terminal_session/connection.h>
#include <cap_session/connection.h>
#include <log_session/log_session.h>
namespace Genode {
class Termlog_component : public Rpc_object<Log_session>
{
public:
enum { LABEL_LEN = 64 };
private:
char _label[LABEL_LEN];
Terminal::Connection *_terminal;
public:
/**
* Constructor
*/
Termlog_component(const char *label, Terminal::Connection *terminal)
: _terminal(terminal) { snprintf(_label, LABEL_LEN, "[%s] ", label); }
/*****************
** Log session **
*****************/
/**
* Write a log-message to the terminal.
*
* The following function's code is a modified variant of the one in:
* 'base/src/core/include/log_session_component.h'
*/
size_t write(String const &string_buf)
{
if (!(string_buf.is_valid_string())) {
PERR("corrupted string");
return 0;
}
char const *string = string_buf.string();
int len = strlen(string);
/*
* Heuristic: The Log console implementation flushes
* the output preferably in front of escape
* sequences. If the line contains only
* the escape sequence, we skip the printing
* of the label and cut the line break (last
* character).
*/
enum { ESC = 27 };
if ((string[0] == ESC) && (len == 5) && (string[4] == '\n')) {
char buf[5];
strncpy(buf, string, 5);
_terminal->write(buf, len);
return len;
}
_terminal->write(_label, strlen(_label));
_terminal->write(string, len);
/* if last character of string was not a line break, add one */
if ((len > 0) && (string[len - 1] != '\n'))
_terminal->write("\n", 1);
return len;
}
};
class Termlog_root : public Root_component<Termlog_component>
{
private:
Terminal::Connection *_terminal;
protected:
/**
* Root component interface
*/
Termlog_component *_create_session(const char *args)
{
size_t ram_quota =
Arg_string::find_arg(args, "ram_quota" ).ulong_value(0);
/* delete ram quota by the memory needed for the session */
size_t session_size = max((size_t)4096, sizeof(Termlog_component));
if (ram_quota < session_size)
throw Root::Quota_exceeded();
char label_buf[Termlog_component::LABEL_LEN];
Arg label_arg = Arg_string::find_arg(args, "label");
label_arg.string(label_buf, sizeof(label_buf), "");
return new (md_alloc()) Termlog_component(label_buf, _terminal);
}
public:
/**
* Constructor
*
* \param session_ep entry point for managing cpu session objects
* \param md_alloc meta-data allocator to be used by root component
*/
Termlog_root(Rpc_entrypoint *session_ep, Allocator *md_alloc,
Terminal::Connection *terminal)
: Root_component<Termlog_component>(session_ep, md_alloc),
_terminal(terminal) { }
};
}
int main(int argc, char **argv)
{
using namespace Genode;
/*
* Open Terminal session
*/
static Terminal::Connection terminal;
/*
* Initialize server entry point
*/
enum { STACK_SIZE = 4096 };
static Cap_connection cap;
static Rpc_entrypoint ep(&cap, STACK_SIZE, "termlog_ep");
static Termlog_root termlog_root(&ep, env()->heap(), &terminal);
/*
* Announce services
*/
env()->parent()->announce(ep.manage(&termlog_root));
/**
* Got to sleep forever
*/
sleep_forever();
return 0;
}

View File

@ -0,0 +1,3 @@
TARGET = terminal_log
SRC_CC = main.cc
LIBS = cxx env server signal