diff --git a/repos/base-fiasco/src/core/target.inc b/repos/base-fiasco/src/core/target.inc
index 155aed53b..cbdd6ed24 100644
--- a/repos/base-fiasco/src/core/target.inc
+++ b/repos/base-fiasco/src/core/target.inc
@@ -9,6 +9,7 @@ SRC_CC += stack_area.cc \
cpu_session_component.cc \
cpu_session_support.cc \
dataspace_component.cc \
+ default_log.cc \
dump_alloc.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
@@ -64,6 +65,7 @@ vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
+vpath default_log.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath stack_area.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
diff --git a/repos/base-foc/src/core/target.inc b/repos/base-foc/src/core/target.inc
index 4e2949eb3..edcfca630 100644
--- a/repos/base-foc/src/core/target.inc
+++ b/repos/base-foc/src/core/target.inc
@@ -12,6 +12,7 @@ SRC_CC += stack_area.cc \
cpu_session_component.cc \
cpu_session_support.cc \
dataspace_component.cc \
+ default_log.cc \
dump_alloc.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
@@ -52,6 +53,7 @@ vpath cpu_session_component.cc $(GEN_CORE_DIR)
vpath cpu_session_support.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
+vpath default_log.cc $(GEN_CORE_DIR)
vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath main.cc $(GEN_CORE_DIR)
diff --git a/repos/base-hw/lib/mk/core.inc b/repos/base-hw/lib/mk/core.inc
index 75420f562..d15cd9c9c 100644
--- a/repos/base-hw/lib/mk/core.inc
+++ b/repos/base-hw/lib/mk/core.inc
@@ -22,6 +22,7 @@ SRC_CC += core_region_map.cc
SRC_CC += core_mem_alloc.cc
SRC_CC += core_rpc_cap_alloc.cc
SRC_CC += dataspace_component.cc
+SRC_CC += default_log.cc
SRC_CC += dump_alloc.cc
SRC_CC += io_mem_session_component.cc
SRC_CC += io_mem_session_support.cc
diff --git a/repos/base-linux/src/core/target.mk b/repos/base-linux/src/core/target.mk
index a4a8905a4..914dbf50e 100644
--- a/repos/base-linux/src/core/target.mk
+++ b/repos/base-linux/src/core/target.mk
@@ -26,6 +26,7 @@ SRC_CC = main.cc \
thread_linux.cc \
stack_area.cc \
core_printf.cc \
+ default_log.cc \
env_reinit.cc \
thread.cc thread_myself.cc
@@ -49,6 +50,7 @@ vpath platform_services.cc $(GEN_CORE_DIR)
vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
+vpath default_log.cc $(GEN_CORE_DIR)
vpath core_printf.cc $(BASE_DIR)/src/lib/base
vpath thread.cc $(BASE_DIR)/src/lib/base
vpath thread_myself.cc $(BASE_DIR)/src/lib/base
diff --git a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc
index b0ff9364d..05a26f759 100644
--- a/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc
+++ b/repos/base-linux/src/lib/lx_hybrid/lx_hybrid.cc
@@ -19,6 +19,7 @@
/* base-internal includes */
#include
+#include
extern "C" int raw_write_str(const char *str);
@@ -109,6 +110,7 @@ void Genode::call_global_static_constructors() { }
int main()
{
+ Genode::init_log();
Genode::bootstrap_component();
/* never reached */
diff --git a/repos/base-nova/src/core/target.inc b/repos/base-nova/src/core/target.inc
index 8104d9efa..c5604c06f 100644
--- a/repos/base-nova/src/core/target.inc
+++ b/repos/base-nova/src/core/target.inc
@@ -12,6 +12,7 @@ SRC_CC = stack_area.cc \
cpu_session_extension.cc \
cpu_session_support.cc \
dataspace_component.cc \
+ default_log.cc \
dump_alloc.cc \
echo.cc \
io_mem_session_component.cc \
@@ -61,6 +62,7 @@ vpath io_mem_session_component.cc $(GEN_CORE_DIR)
vpath io_mem_session_support.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
+vpath default_log.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
vpath platform_services.cc $(GEN_CORE_DIR)/spec/x86
vpath stack_area.cc $(GEN_CORE_DIR)
diff --git a/repos/base-okl4/src/core/target.inc b/repos/base-okl4/src/core/target.inc
index 4c2714873..31c10b166 100644
--- a/repos/base-okl4/src/core/target.inc
+++ b/repos/base-okl4/src/core/target.inc
@@ -12,6 +12,7 @@ SRC_CC += stack_area.cc \
cpu_session_component.cc \
cpu_session_support.cc \
dataspace_component.cc \
+ default_log.cc \
dump_alloc.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
@@ -60,6 +61,7 @@ vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath core_mem_alloc.cc $(GEN_CORE_DIR)
vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
+vpath default_log.cc $(GEN_CORE_DIR)
vpath stack_area.cc $(GEN_CORE_DIR)
vpath pager_ep.cc $(GEN_CORE_DIR)
vpath %.cc $(REP_DIR)/src/core
diff --git a/repos/base-pistachio/src/core/target.inc b/repos/base-pistachio/src/core/target.inc
index ca4be55b6..d4bb70adf 100644
--- a/repos/base-pistachio/src/core/target.inc
+++ b/repos/base-pistachio/src/core/target.inc
@@ -11,6 +11,7 @@ SRC_CC = stack_area.cc \
cpu_session_component.cc \
cpu_session_platform.cc \
dataspace_component.cc \
+ default_log.cc \
dump_alloc.cc \
io_mem_session_component.cc \
io_mem_session_support.cc \
@@ -59,6 +60,7 @@ vpath signal_source_component.cc $(GEN_CORE_DIR)
vpath trace_session_component.cc $(GEN_CORE_DIR)
vpath dataspace_component.cc $(GEN_CORE_DIR)
vpath dump_alloc.cc $(GEN_CORE_DIR)
+vpath default_log.cc $(GEN_CORE_DIR)
vpath core_rpc_cap_alloc.cc $(GEN_CORE_DIR)
vpath core_region_map.cc $(GEN_CORE_DIR)
vpath stack_area.cc $(GEN_CORE_DIR)
diff --git a/repos/base-sel4/lib/mk/core_printf.mk b/repos/base-sel4/lib/mk/core_printf.mk
index 73575bc93..c34a6f380 100644
--- a/repos/base-sel4/lib/mk/core_printf.mk
+++ b/repos/base-sel4/lib/mk/core_printf.mk
@@ -1,5 +1,6 @@
-SRC_CC = core_printf.cc
-INC_DIR += $(REP_DIR)/src/include
+SRC_CC = core_printf.cc default_log.cc
+INC_DIR += $(REP_DIR)/src/include $(BASE_DIR)/src/include
LIBS += syscall
vpath core_printf.cc $(BASE_DIR)/src/lib/base
+vpath default_log.cc $(BASE_DIR)/src/core
diff --git a/repos/base/include/base/log.h b/repos/base/include/base/log.h
new file mode 100644
index 000000000..eb96fb3b5
--- /dev/null
+++ b/repos/base/include/base/log.h
@@ -0,0 +1,109 @@
+/*
+ * \brief LOG output functions
+ * \author Norman Feske
+ * \date 2016-05-03
+ */
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _INCLUDE__BASE__LOG_H_
+#define _INCLUDE__BASE__LOG_H_
+
+#include
+#include
+
+namespace Genode { class Log; }
+
+
+/**
+ * Interface for writing output to the component's LOG session
+ *
+ * The LOG session is not used directly by the 'log', 'warning', and
+ * 'error' functions. They access the LOG indirectly via this interface
+ * instead, which ensures the proper synchronization of the output in the
+ * presence of multiple threads and to apply distinguishable colors to the
+ * different types of messages.
+ */
+class Genode::Log
+{
+ public:
+
+ /**
+ * Type of message
+ */
+ enum Type { LOG, WARNING, ERROR };
+
+ private:
+
+ Lock _lock;
+ void _acquire(Type);
+ void _release();
+ Output &_output;
+
+ /**
+ * Helper for the sequential output of a variable list of arguments
+ */
+ template
+ void _output_args(Output &output, HEAD && head, TAIL &&... tail)
+ {
+ print(output, head);
+ _output_args(output, tail...);
+ }
+
+ template
+ void _output_args(Output &output, LAST && last) { print(output, last); }
+
+ public:
+
+ Log(Output &output) : _output(output) { }
+
+ template
+ void output(Type type, ARGS &&... args)
+ {
+ /*
+ * This function is being inlined. Hence, we try to keep it as
+ * small as possible. For this reason, the lock operations are
+ * performed by the '_acquire' and '_release' functions instead of
+ * using a lock guard.
+ */
+ _acquire(type);
+ _output_args(_output, args...);
+ _release();
+ }
+
+ /**
+ * Return component-global singleton instance of the 'Log'
+ */
+ static Log &log();
+};
+
+
+namespace Genode {
+
+ /**
+ * Write 'args' as a regular message to the log
+ */
+ template
+ void log(ARGS &&... args) { Log::log().output(Log::LOG, args...); }
+
+
+ /**
+ * Write 'args' as a warning message to the log
+ */
+ template
+ void warning(ARGS &&... args) { Log::log().output(Log::WARNING, args...); }
+
+
+ /**
+ * Write 'args' as an error message to the log
+ */
+ template
+ void error(ARGS &&... args) { Log::log().output(Log::ERROR, args...); }
+}
+
+#endif /* _INCLUDE__BASE__LOG_H_ */
diff --git a/repos/base/include/base/output.h b/repos/base/include/base/output.h
new file mode 100644
index 000000000..9628c32eb
--- /dev/null
+++ b/repos/base/include/base/output.h
@@ -0,0 +1,154 @@
+/*
+ * \brief Interface for textual output
+ * \author Norman Feske
+ * \date 2016-05-03
+ */
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _INCLUDE__BASE__OUTPUT_H_
+#define _INCLUDE__BASE__OUTPUT_H_
+
+#include
+#include
+
+namespace Genode { struct Output; }
+
+
+struct Genode::Output
+{
+ /**
+ * Output single character
+ */
+ virtual void out_char(char) = 0;
+
+ /**
+ * Output string
+ *
+ * \param n maximum number of characters to output
+ *
+ * The output stops on the first occurrence of a null character in the
+ * string or after 'n' characters.
+ *
+ * The default implementation uses 'out_char'. This method may be
+ * overridden by the backend for improving efficiency.
+ */
+ virtual void out_string(char const *str, size_t n = ~0UL);
+};
+
+
+namespace Genode {
+
+ /**
+ * Print null-terminated string
+ */
+ void print(Output &output, char const *);
+
+ /**
+ * Print pointer value
+ */
+ void print(Output &output, void const *);
+
+ /**
+ * Print arbitrary pointer types
+ *
+ * This function template takes precedence over the one that takes a
+ * constant object reference as argument.
+ */
+ template
+ static inline void print(Output &output, T *ptr)
+ {
+ print(output, (void const *)ptr);
+ }
+
+ /**
+ * Print unsigned long value
+ */
+ void print(Output &output, unsigned long);
+
+ /**
+ * Print unsigned integer value
+ */
+ static inline void print(Output &output, unsigned value)
+ {
+ print(output, (unsigned long)value);
+ }
+
+ /**
+ * Print signed long value
+ */
+ void print(Output &output, long);
+
+ /**
+ * Print signed integer value
+ */
+ static inline void print(Output &output, int value)
+ {
+ print(output, (long)value);
+ }
+
+ /**
+ * Print signed long long value
+ */
+ void print(Output &output, long long);
+
+ /**
+ * Helper for the hexadecimal output of integer values
+ *
+ * To output an integer value as hexadecimal number, the value can be
+ * wrapped into an 'Hex' object, thereby selecting the corresponding
+ * overloaded 'print' function below.
+ */
+ struct Hex
+ {
+ enum Prefix { PREFIX, OMIT_PREFIX };
+ enum Pad { PAD, NO_PAD };
+
+ unsigned long const value;
+ size_t const digits;
+ Prefix const prefix;
+ Pad const pad;
+
+ /**
+ * Constructor
+ *
+ * \param prefix by default, the value is prepended with the prefix
+ * '0x'. The prefix can be suppressed by specifying
+ * 'OMIT_PREFIX' as argument.
+ * \param pad by default, leading zeros are stripped from the
+ * output. If set to 'PAD', the leading zeros will be
+ * printed.
+ */
+ template
+ explicit Hex(T value, Prefix prefix = PREFIX, Pad pad = NO_PAD)
+ : value(value), digits(2*sizeof(T)), prefix(prefix), pad(pad) { }
+ };
+
+ /**
+ * Print hexadecimal number
+ */
+ void print(Output &output, Hex const &);
+
+ /**
+ * Print information about object 'obj'
+ *
+ * The object type must provide a const 'print(Output &)' method that
+ * produces the textual representation of the object.
+ *
+ * In contrast to overloads of the 'Genode::print' function, the 'T::print'
+ * method is able to access object-internal state, which can thereby be
+ * incorporated into the textual output.
+ */
+ template
+ static inline void print(Output &output, T const &obj)
+ {
+ obj.print(output);
+ }
+}
+
+#endif /* _INCLUDE__BASE__OUTPUT_H_ */
diff --git a/repos/base/lib/mk/base-common.inc b/repos/base/lib/mk/base-common.inc
index 83e2ed042..d692e0dbe 100644
--- a/repos/base/lib/mk/base-common.inc
+++ b/repos/base/lib/mk/base-common.inc
@@ -11,11 +11,13 @@ SRC_CC += slab.cc
SRC_CC += allocator_avl.cc
SRC_CC += heap.cc sliced_heap.cc
SRC_CC += console.cc
+SRC_CC += output.cc
SRC_CC += child.cc
SRC_CC += child_process.cc
SRC_CC += elf_binary.cc
SRC_CC += ipc.cc
SRC_CC += lock.cc
+SRC_CC += log.cc
SRC_CC += rpc_entrypoint.cc
SRC_CC += signal.cc signal_common.cc
SRC_CC += sleep.cc
diff --git a/repos/base/lib/mk/base.inc b/repos/base/lib/mk/base.inc
index 5db96c6ff..3764f77f2 100644
--- a/repos/base/lib/mk/base.inc
+++ b/repos/base/lib/mk/base.inc
@@ -1,4 +1,4 @@
-SRC_CC += log_console.cc
+SRC_CC += log_console.cc default_log.cc
SRC_CC += env_deprecated.cc stack_area.cc env_reinit.cc
SRC_CC += rpc_cap_alloc.cc
diff --git a/repos/base/src/core/default_log.cc b/repos/base/src/core/default_log.cc
new file mode 100644
index 000000000..26f5ad22a
--- /dev/null
+++ b/repos/base/src/core/default_log.cc
@@ -0,0 +1,51 @@
+/*
+ * \brief Access to the core's log facility
+ * \author Norman Feske
+ * \date 2016-05-03
+ */
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* base-internal includes */
+#include
+#include
+#include
+
+using namespace Genode;
+
+
+static Log *log_ptr;
+
+
+Log &Log::log() { return *log_ptr; }
+
+
+void Genode::init_log()
+{
+ /* ignore subsequent calls */
+ if (log_ptr)
+ return;
+
+ /*
+ * Currently, we still rely on the old format-string support and
+ * produce output via 'core_printf.cc'.
+ */
+ struct Write_fn { void operator () (char const *s) { printf("%s", s); } };
+
+ typedef Buffered_output<512, Write_fn> Buffered_log_output;
+
+ static Buffered_log_output *buffered_log_output =
+ unmanaged_singleton(Write_fn());
+
+ log_ptr = unmanaged_singleton(*buffered_log_output);
+}
+
diff --git a/repos/base/src/core/main.cc b/repos/base/src/core/main.cc
index 5eb01c268..998322c8f 100644
--- a/repos/base/src/core/main.cc
+++ b/repos/base/src/core/main.cc
@@ -16,6 +16,7 @@
#include
#include
#include
+#include
#include
#include
#include
@@ -225,7 +226,7 @@ int main()
*/
inhibit_tracing = true;
- PINF("Genode %s", Genode::version_string);
+ log("Genode ", Genode::version_string);
PDBG("--- create local services ---");
diff --git a/repos/base/src/include/base/internal/globals.h b/repos/base/src/include/base/internal/globals.h
index 13f9f1ff5..7b6df12ca 100644
--- a/repos/base/src/include/base/internal/globals.h
+++ b/repos/base/src/include/base/internal/globals.h
@@ -26,6 +26,7 @@ namespace Genode {
extern Ram_session *env_stack_area_ram_session;
void init_signal_thread();
+ void init_log();
}
#endif /* _INCLUDE__BASE__INTERNAL__GLOBALS_H_ */
diff --git a/repos/base/src/include/base/internal/output.h b/repos/base/src/include/base/internal/output.h
new file mode 100644
index 000000000..479d1306c
--- /dev/null
+++ b/repos/base/src/include/base/internal/output.h
@@ -0,0 +1,160 @@
+/*
+ * \brief Internal utilities used for implementing the 'Output' funtions
+ * \author Norman Feske
+ * \date 2016-05-03
+ */
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef _INCLUDE__BASE__INTERNAL__OUTPUT_H_
+#define _INCLUDE__BASE__INTERNAL__OUTPUT_H_
+
+
+#include
+
+using namespace Genode;
+
+
+/**
+ * Convert digit to ASCII value
+ */
+static inline char ascii(int digit, int uppercase = 0)
+{
+ if (digit > 9)
+ return digit + (uppercase ? 'A' : 'a') - 10;
+
+ return digit + '0';
+}
+
+
+/**
+ * Output signed value with the specified base
+ */
+template
+static inline void out_signed(T value, unsigned base, OUT_CHAR_FN const &out_char)
+{
+ /**
+ * for base 8, the number of digits is the number of value bytes times 3
+ * at a max, because 0xff is 0o377 and accumulating this implies a
+ * strictly decreasing factor
+ */
+ char buf[sizeof(value)*3];
+
+ /* set flag if value is negative */
+ int neg = value < 0 ? 1 : 0;
+
+ /* get absolute value */
+ value = value < 0 ? -value : value;
+
+ int i = 0;
+
+ /* handle zero as special case */
+ if (value == 0)
+ buf[i++] = ascii(0);
+
+ /* fill buffer starting with the least significant digits */
+ else
+ for (; value > 0; value /= base)
+ buf[i++] = ascii(value % base);
+
+ /* add sign to buffer for negative values */
+ if (neg)
+ out_char('-');
+
+ /* output buffer in reverse order */
+ for (; i--; )
+ out_char(buf[i]);
+}
+
+
+/**
+ * Output unsigned value with the specified base and padding
+ */
+template
+static inline void out_unsigned(T value, unsigned base, int pad,
+ OUT_CHAR_FN const &out_char)
+{
+ /**
+ * for base 8, the number of digits is the number of value bytes times 3
+ * at a max, because 0xff is 0o377 and accumulating this implies a
+ * strictly decreasing factor
+ */
+ char buf[sizeof(value)*3];
+
+ int i = 0;
+
+ /* handle zero as special case */
+ if (value == 0) {
+ buf[i++] = ascii(0);
+ pad--;
+ }
+
+ /* fill buffer starting with the least significant digits */
+ for (; value > 0; value /= base, pad--)
+ buf[i++] = ascii(value % base);
+
+ /* add padding zeros */
+ for (; pad-- > 0; )
+ out_char(ascii(0));
+
+ /* output buffer in reverse order */
+ for (; i--; )
+ out_char(buf[i]);
+}
+
+
+namespace Genode { template class Buffered_output; }
+
+
+/**
+ * Implementation of the output interface that buffers characters
+ *
+ * \param BUF_SIZE maximum number of characters to buffer before writing
+ * \param WRITE_FN functor called to writing the buffered characters to a
+ * backend.
+ *
+ * The 'WRITE_FN' functor is called with a null-terminated 'char const *'
+ * as argument.
+ */
+template
+class Genode::Buffered_output : public Output
+{
+ private:
+
+ BACKEND_WRITE_FN _write_fn;
+ char _buf[BUF_SIZE];
+ unsigned _num_chars = 0;
+
+ void _flush()
+ {
+ /* null-terminate string */
+ _buf[_num_chars] = 0;
+ _write_fn(_buf);
+
+ /* restart with empty buffer */
+ _num_chars = 0;
+ }
+
+ public:
+
+ Buffered_output(BACKEND_WRITE_FN const &write_fn) : _write_fn(write_fn) { }
+
+ void out_char(char c) override
+ {
+ /* ensure enough buffer space for complete escape sequence */
+ if ((c == 27) && (_num_chars + 8 > BUF_SIZE)) _flush();
+
+ _buf[_num_chars++] = c;
+
+ /* flush immediately on line break */
+ if (c == '\n' || _num_chars >= sizeof(_buf) - 1)
+ _flush();
+ }
+};
+
+#endif /* _INCLUDE__BASE__INTERNAL__OUTPUT_H_ */
diff --git a/repos/base/src/lib/base/console.cc b/repos/base/src/lib/base/console.cc
index 5e56277aa..3b83897dc 100644
--- a/repos/base/src/lib/base/console.cc
+++ b/repos/base/src/lib/base/console.cc
@@ -17,9 +17,13 @@
* under the terms of the GNU General Public License version 2.
*/
+/* Genode includes */
#include
#include
+/* base-internal includes */
+#include
+
using namespace Genode;
@@ -138,93 +142,6 @@ class Format_command
};
-/**
- * Convert digit to ASCII value
- */
-static char ascii(int digit, int uppercase = 0)
-{
- if (digit > 9)
- return digit + (uppercase ? 'A' : 'a') - 10;
-
- return digit + '0';
-}
-
-
-/**
- * Output signed value with the specified base
- */
-template
-void Console::_out_signed(T value, unsigned base)
-{
- /**
- * for base 8, the number of digits is the number of value bytes times 3
- * at a max, because 0xff is 0o377 and accumulating this implies a
- * strictly decreasing factor
- */
- char buf[sizeof(value)*3];
-
- /* set flag if value is negative */
- int neg = value < 0 ? 1 : 0;
-
- /* get absolute value */
- value = value < 0 ? -value : value;
-
- int i = 0;
-
- /* handle zero as special case */
- if (value == 0)
- buf[i++] = ascii(0);
-
- /* fill buffer starting with the least significant digits */
- else
- for (; value > 0; value /= base)
- buf[i++] = ascii(value % base);
-
- /* add sign to buffer for negative values */
- if (neg)
- _out_char('-');
-
- /* output buffer in reverse order */
- for (; i--; )
- _out_char(buf[i]);
-}
-
-
-/**
- * Output unsigned value with the specified base and padding
- */
-template
-void Console::_out_unsigned(T value, unsigned base, int pad)
-{
- /**
- * for base 8, the number of digits is the number of value bytes times 3
- * at a max, because 0xff is 0o377 and accumulating this implies a
- * strictly decreasing factor
- */
- char buf[sizeof(value)*3];
-
- int i = 0;
-
- /* handle zero as special case */
- if (value == 0) {
- buf[i++] = ascii(0);
- pad--;
- }
-
- /* fill buffer starting with the least significant digits */
- for (; value > 0; value /= base, pad--)
- buf[i++] = ascii(value % base);
-
- /* add padding zeros */
- for (; pad-- > 0; )
- _out_char(ascii(0));
-
- /* output buffer in reverse order */
- for (; i--; )
- _out_char(buf[i]);
-}
-
-
void Console::_out_string(const char *str)
{
if (!str)
@@ -292,15 +209,18 @@ void Console::vprintf(const char *format, va_list list)
case Format_command::INT:
if (cmd.length == Format_command::LONG_LONG)
- _out_signed(numeric_arg, cmd.base);
+ out_signed(numeric_arg, cmd.base,
+ [&] (char c) { _out_char(c); });
else
- _out_signed(numeric_arg, cmd.base);
+ out_signed(numeric_arg, cmd.base,
+ [&] (char c) { _out_char(c); });
break;
case Format_command::UINT:
if (cmd.length == Format_command::LONG_LONG) {
- _out_unsigned(numeric_arg, cmd.base, cmd.padding);
+ out_unsigned(numeric_arg, cmd.base, cmd.padding,
+ [&] (char c) { _out_char(c); });
break;
}
@@ -308,7 +228,8 @@ void Console::vprintf(const char *format, va_list list)
case Format_command::PTR:
- _out_unsigned(numeric_arg, cmd.base, cmd.padding);
+ out_unsigned(numeric_arg, cmd.base, cmd.padding,
+ [&] (char c) { _out_char(c); });
break;
case Format_command::CHAR:
diff --git a/repos/base/src/lib/base/default_log.cc b/repos/base/src/lib/base/default_log.cc
new file mode 100644
index 000000000..9f681c123
--- /dev/null
+++ b/repos/base/src/lib/base/default_log.cc
@@ -0,0 +1,51 @@
+/*
+ * \brief Access to the component's LOG session
+ * \author Norman Feske
+ * \date 2016-05-03
+ */
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/* Genode includes */
+#include
+#include
+
+/* base-internal includes */
+#include
+#include
+#include
+
+using namespace Genode;
+
+
+static Log *log_ptr;
+
+
+Log &Log::log() { return *log_ptr; }
+
+
+extern "C" int stdout_write(const char *s);
+
+
+void Genode::init_log()
+{
+ /* ignore subsequent calls */
+ if (log_ptr)
+ return;
+
+ struct Write_fn { void operator () (char const *s) { stdout_write(s); } };
+
+ typedef Buffered_output
+ Buffered_log_output;
+
+ static Buffered_log_output *buffered_log_output =
+ unmanaged_singleton(Write_fn());
+
+ log_ptr = unmanaged_singleton(*buffered_log_output);
+}
+
diff --git a/repos/base/src/lib/base/log.cc b/repos/base/src/lib/base/log.cc
new file mode 100644
index 000000000..6a61882a9
--- /dev/null
+++ b/repos/base/src/lib/base/log.cc
@@ -0,0 +1,44 @@
+/*
+ * \brief Access to the component's LOG session
+ * \author Norman Feske
+ * \date 2016-05-03
+ */
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/* Genode includes */
+#include
+
+using namespace Genode;
+
+
+void Log::_acquire(Type type)
+{
+ _lock.lock();
+
+ /*
+ * Mark warnings and errors via distinct colors.
+ */
+ switch (type) {
+ case LOG: break;
+ case WARNING: _output.out_string("\033[34mWarning: "); break;
+ case ERROR: _output.out_string("\033[31mError: "); break;
+ };
+}
+
+
+void Log::_release()
+{
+ /*
+ * Reset color and add newline
+ */
+ _output.out_string("\033[0m\n");
+
+ _lock.unlock();
+}
+
diff --git a/repos/base/src/lib/base/output.cc b/repos/base/src/lib/base/output.cc
new file mode 100644
index 000000000..66648f24f
--- /dev/null
+++ b/repos/base/src/lib/base/output.cc
@@ -0,0 +1,83 @@
+/*
+ * \brief Textual output functions
+ * \author Norman Feske
+ * \date 2016-05-03
+ */
+
+/*
+ * Copyright (C) 2016 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.
+ */
+
+/* Genode includes */
+#include
+
+/* base-internal includes */
+#include
+
+using namespace Genode;
+
+
+/************
+ ** Output **
+ ************/
+
+void Output::out_string(char const *str, size_t n)
+{
+ if (!str)
+ return;
+
+ while (*str && n--) out_char(*str++);
+}
+
+
+/******************************
+ ** Print function overloads **
+ ******************************/
+
+void Genode::print(Output &output, char const *str)
+{
+ if (!str)
+ output.out_string("");
+ else
+ while (*str) output.out_char(*str++);
+}
+
+
+void Genode::print(Output &output, void const *ptr)
+{
+ print(output, Hex(reinterpret_cast(ptr)));
+}
+
+
+void Genode::print(Output &output, unsigned long value)
+{
+ out_unsigned(value, 10, 0, [&] (char c) { output.out_char(c); });
+}
+
+
+void Genode::print(Output &output, long value)
+{
+ out_signed(value, 10, [&] (char c) { output.out_char(c); });
+}
+
+
+void Genode::print(Output &output, long long value)
+{
+ out_signed(value, 10, [&] (char c) { output.out_char(c); });
+}
+
+
+void Genode::print(Output &output, Hex const &value)
+{
+ if (value.prefix == Hex::PREFIX)
+ output.out_string("0x");
+
+ size_t const pad_len = value.pad ? value.digits : 0;
+
+ out_unsigned(value.value, 16, pad_len,
+ [&] (char c) { output.out_char(c); });
+}
+
diff --git a/repos/base/src/lib/startup/init_main_thread.cc b/repos/base/src/lib/startup/init_main_thread.cc
index b08329832..5cccb3159 100644
--- a/repos/base/src/lib/startup/init_main_thread.cc
+++ b/repos/base/src/lib/startup/init_main_thread.cc
@@ -19,8 +19,12 @@
#include
#include
+/* base-internal includes */
+#include
+
using namespace Genode;
+
addr_t init_main_thread_result;
extern void init_exception_handling();
@@ -89,6 +93,7 @@ extern "C" void init_main_thread()
* destructor won't be registered for the atexit routine.
*/
(void*)env();
+ init_log();
/* initialize exception handling */
init_exception_handling();