Message ID | 1408980152-10343-1-git-send-email-ola.liljedahl@linaro.org |
---|---|
State | New |
Headers | show |
Ping the list for reviewers. Please find a time to review/test/comment that patch. Maxim. On 08/25/2014 07:22 PM, Ola Liljedahl wrote: > Signed-off-by: Ola Liljedahl <ola.liljedahl@linaro.org> > --- > (This document/code contribution attached is provided under the terms of agreement LES-LTM-21309) > Log API for internal ODP use. > Logging can be compile time and run time disabled. > Compile out all log levels: -DODP_LOG_LEVEL=0 > Compile in all log levels: -DODP_LOG_LEVEL=7 > Enable all log levels: -DODP_LOG_DEFAULT_MASK=7 (default: fatal+error) > Run time setting: odp_log_set_level("module_name", level); > Log messages can be redirected: odp_log_set_callback(fn); > > Usage: > ODP_LOG_DECLARE(my_mod); /* File-scope declaration */ > ODP_LOG_REGISTER(my_mod); /* Init call */ > ODP_LOG_ERROR(my_mod, "Error %u has occured\n", 242); > > platform/linux-generic/Makefile.am | 2 + > platform/linux-generic/include/api/odp_log.h | 59 +++++++ > platform/linux-generic/include/odp_log_internal.h | 115 +++++++++++++ > platform/linux-generic/odp_init.c | 26 +-- > platform/linux-generic/odp_log.c | 189 ++++++++++++++++++++++ > 5 files changed, 382 insertions(+), 9 deletions(-) > create mode 100644 platform/linux-generic/include/api/odp_log.h > create mode 100644 platform/linux-generic/include/odp_log_internal.h > create mode 100644 platform/linux-generic/odp_log.c > > diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am > index f4dfdc1..f30c6ff 100644 > --- a/platform/linux-generic/Makefile.am > +++ b/platform/linux-generic/Makefile.am > @@ -20,6 +20,7 @@ include_HEADERS = \ > $(top_srcdir)/platform/linux-generic/include/api/odp_debug.h \ > $(top_srcdir)/platform/linux-generic/include/api/odp_hints.h \ > $(top_srcdir)/platform/linux-generic/include/api/odp_init.h \ > + $(top_srcdir)/platform/linux-generic/include/api/odp_log.h \ > $(top_srcdir)/platform/linux-generic/include/api/odp_packet_flags.h \ > $(top_srcdir)/platform/linux-generic/include/api/odp_packet.h \ > $(top_srcdir)/platform/linux-generic/include/api/odp_packet_io.h \ > @@ -58,6 +59,7 @@ __LIB__libodp_la_SOURCES = \ > odp_crypto.c \ > odp_init.c \ > odp_linux.c \ > + odp_log.c \ > odp_packet.c \ > odp_packet_flags.c \ > odp_packet_io.c \ > diff --git a/platform/linux-generic/include/api/odp_log.h b/platform/linux-generic/include/api/odp_log.h > new file mode 100644 > index 0000000..b8c49e3 > --- /dev/null > +++ b/platform/linux-generic/include/api/odp_log.h > @@ -0,0 +1,59 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > + > +/** > + * @file > + * > + * ODP internal logging facility - public management API > + */ > + > +#ifndef ODP_LOG_H_ > +#define ODP_LOG_H_ > + > +#include <stdarg.h> > +#include <stdbool.h> > +#include <stdint.h> > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +/** Fatal error for function, may not return to caller */ > +#define ODP_LOG_LVL_FATAL 1U > +/** Error prevented function to succeed but caller should be able to recover */ > +#define ODP_LOG_LVL_ERROR 2U > +/** Problem detected in function but recovered locally */ > +#define ODP_LOG_LVL_WARNING 3U > +/** Informational message intended for user */ > +#define ODP_LOG_LVL_INFORM 4U > +/** Debug message intended for developer */ > +#define ODP_LOG_LVL_DEBUG 5U > + > +#define ODP_LOG_LVL_NONE 0U /**< Disable all log levels */ > +#define ODP_LOG_LVL_ALL 7U /**< Enable all log levels */ > + > +typedef volatile uint32_t odp_log_t; > +#define ODP_LOG_INVALID 0U > + > +/** Call-back type definition for user-defined log facility */ > +typedef void (*odp_log_callback_t)(const char *name, > + unsigned level, > + const char *fmt, > + va_list ap); > + > +/** Set the log level for a source identified by name */ > +int odp_log_set_level(const char *name, unsigned level); > +/** Install a user-defined call-back for handling log messages */ > +void odp_log_set_callback(odp_log_callback_t cb); > +/** Iterate through all registered log sources */ > +int odp_log_next(odp_log_t *phdl, char *name, size_t namelen, unsigned *level); > + > +#ifdef __cplusplus > +} > +#endif > + > +#endif > diff --git a/platform/linux-generic/include/odp_log_internal.h b/platform/linux-generic/include/odp_log_internal.h > new file mode 100644 > index 0000000..7ac3ab1 > --- /dev/null > +++ b/platform/linux-generic/include/odp_log_internal.h > @@ -0,0 +1,115 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > + > +/** > + * @file > + * > + * ODP internal logging facility - client API > + */ > + > +#ifndef ODP_LOG_INTERNAL_H_ > +#define ODP_LOG_INTERNAL_H_ > + > +#include <stdint.h> > +#include <odp_log.h> > +#include <odp_hints.h> > + > +#ifdef __cplusplus > +extern "C" { > +#endif > + > +#ifndef ODP_LOG_LEVEL > +#define ODP_LOG_LEVEL ODP_LOG_LVL_ALL > +#endif > + > +/* Report a message to the log */ > +#define ODP_LOG_MSG(_lvl, _hdl, _fmt, ...) \ > +do { \ > + unsigned __lvl = (_lvl); \ > + odp_log_t __hdl = (_hdl); \ > + const char *__fmt = (_fmt); \ > + if (odp_unlikely((__hdl & 0x7) >= __lvl)) \ > + odp_log_printf(__lvl, __hdl, __fmt, ##__VA_ARGS__); \ > +} while (0) > + > +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_FATAL > +#define ODP_LOG_FATAL(_src, _fmt, ...) \ > +ODP_LOG_MSG(ODP_LOG_LVL_FATAL, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) > +#else > +#define ODP_LOG_FATAL(_src, _fmt, ...) (void)0 > +#endif > + > +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_ERROR > +#define ODP_LOG_ERROR(_src, _fmt, ...) \ > +ODP_LOG_MSG(ODP_LOG_LVL_ERROR, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) > +#else > +#define ODP_LOG_ERROR(_src, _fmt, ...) (void)0 > +#endif > + > +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_WARNING > +#define ODP_LOG_WARNING(_src, _fmt, ...) \ > +ODP_LOG_MSG(ODP_LOG_LVL_WARNING, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) > +#else > +#define ODP_LOG_WARNING(_src, _fmt, ...) (void)0 > +#endif > + > +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_INFORM > +#define ODP_LOG_INFORM(_src, _fmt, ...) \ > +ODP_LOG_MSG(ODP_LOG_LVL_INFORM, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) > +#else > +#define ODP_LOG_INFORM(_src, _fmt, ...) (void)0 > +#endif > + > +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_DEBUG > +#define ODP_LOG_DEBUG(_src, _fmt, ...) \ > +ODP_LOG_MSG(ODP_LOG_LVL_DEBUG, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) > +#else > +#define ODP_LOG_DEBUG(_src, _fmt, ...) (void)0 > +#endif > + > + > +#define ODP_LOG_DECLARE(src) odp_log_t _odp_log_src_ ## src > +#define ODP_LOG_REGISTER(src) odp_log_register(&_odp_log_src_ ## src, #src) > + > +/* Calls indirectly used by log clients. Use macros above! */ > +/* Register a log source with the specified name */ > +void odp_log_register(odp_log_t *hdl, const char *name); > +/* Report a log message */ > +void odp_log_printf(unsigned lvl, odp_log_t hdl, const char *fmt, ...); > + > +/* Init log module, specify call-back (or NULL for default behaviour) */ > +void odp_log_init(odp_log_callback_t cb); > + > + > +/* Example usage: > + > +ODP_LOG_DECLARE(odp_queue); > + > +//Use default output mechanism > +odp_log_init(NULL); > + > +//Register log source and set default log level > +ODP_LOG_REGISTER(odp_queue); > + > +//Log a message with severity error > +ODP_LOG_ERROR(odp_queue, "Failed to create queue, param=%u\n", 242); > + > +//Set log level for a source to log everything > +(void)odp_log_set_level("odp_queue", ODP_LOG_LVL_ALL); > + > +//Install a custom vprintf function to handle log messages > +odp_log_set_callback(my_vprintf); > + > +//Log a message that will be forwarded to the user-specified log > +ODP_LOG_INFORM(odp_queue, "Message printed using user-defined call-back\n"); > + > +*/ > + > +#ifdef __cplusplus > +} > +#endif > +#endif > diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c > index 5b7e192..3677f1b 100644 > --- a/platform/linux-generic/odp_init.c > +++ b/platform/linux-generic/odp_init.c > @@ -7,46 +7,54 @@ > #include <odp_init.h> > #include <odp_internal.h> > #include <odp_debug.h> > +#include <odp_log_internal.h> > > +ODP_LOG_DECLARE(odp_init); > > int odp_init_global(void) > { > + /* Init log mechanism first so that it can be used by all other > + modules (including init) */ > + odp_log_init(NULL); /* NULL => Use default output mechanism */ > + > + ODP_LOG_REGISTER(odp_init); > + > odp_thread_init_global(); > > odp_system_info_init(); > > if (odp_shm_init_global()) { > - ODP_ERR("ODP shm init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP shm init failed.\n"); > return -1; > } > > if (odp_buffer_pool_init_global()) { > - ODP_ERR("ODP buffer pool init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP buffer pool init failed.\n"); > return -1; > } > > if (odp_queue_init_global()) { > - ODP_ERR("ODP queue init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP queue init failed.\n"); > return -1; > } > > if (odp_schedule_init_global()) { > - ODP_ERR("ODP schedule init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP schedule init failed.\n"); > return -1; > } > > if (odp_pktio_init_global()) { > - ODP_ERR("ODP packet io init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP packet io init failed.\n"); > return -1; > } > > if (odp_timer_init_global()) { > - ODP_ERR("ODP timer init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP timer init failed.\n"); > return -1; > } > > if (odp_crypto_init_global()) { > - ODP_ERR("ODP crypto init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP crypto init failed.\n"); > return -1; > } > > @@ -59,12 +67,12 @@ int odp_init_local(int thr_id) > odp_thread_init_local(thr_id); > > if (odp_pktio_init_local()) { > - ODP_ERR("ODP packet io local init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP packet io local init failed.\n"); > return -1; > } > > if (odp_schedule_init_local()) { > - ODP_ERR("ODP schedule local init failed.\n"); > + ODP_LOG_FATAL(odp_init, "ODP schedule local init failed.\n"); > return -1; > } > > diff --git a/platform/linux-generic/odp_log.c b/platform/linux-generic/odp_log.c > new file mode 100644 > index 0000000..99b2803 > --- /dev/null > +++ b/platform/linux-generic/odp_log.c > @@ -0,0 +1,189 @@ > +/* Copyright (c) 2014, Linaro Limited > + * All rights reserved. > + * > + * SPDX-License-Identifier: BSD-3-Clause > + */ > + > + > +/** > + * @file > + * > + * ODP logging utility > + */ > + > +#include <errno.h> > +#include <limits.h> > +#include <stdarg.h> > +#include <stdint.h> > +#include <stdio.h> > +#include <stdlib.h> > +#include <string.h> > +#include <strings.h> > +#include <odp_debug.h> > +#include <odp_spinlock.h> > +#include <odp_sync.h> > +#include <odp_log.h> > +#include <odp_log_internal.h> > + > +#ifndef ODP_LOG_DEFAULT_MASK > +#define ODP_LOG_DEFAULT_MASK (ODP_LOG_LVL_FATAL | ODP_LOG_LVL_ERROR) > +#endif > + > +/* Maximum number of log sources */ > +#ifndef ODP_LOG_MAX > +#define ODP_LOG_MAX 64 > +#endif > + > +ODP_STATIC_ASSERT(ODP_LOG_LVL_ALL == 7U, "ODP_LOG_LVL_ALL_ERROR"); > + > +#define HDL_TO_LVL(hdl) ((hdl) & 0x7U) > +#define HDL_TO_SLOT(hdl) (((hdl) >> 3U) - 1U) > +#define SLOT_LVL_TO_HDL(slot, lvl) ((((slot) + 1U) << 3U) | (lvl)) > +#define INVALID_SLOT ~0U > + > +struct source { > + odp_log_t *phdl; /* Pointer to the user's odp_log_t variable */ > + const char *name; > +}; > + > +static odp_spinlock_t lock; > +static volatile odp_log_callback_t callback; > +ODP_LOG_DECLARE(odp_log); > +static struct source sources[ODP_LOG_MAX]; > + > +void > +odp_log_init(odp_log_callback_t cb) > +{ > + odp_spinlock_init(&lock); > + callback = cb; > + memset(sources, 0, sizeof(sources)); > + odp_sync_stores(); > + ODP_LOG_REGISTER(odp_log); > + odp_log_set_level("odp_log", ODP_LOG_LVL_ALL); > +} > + > +/* Register a log source with the specified name */ > +void > +odp_log_register(odp_log_t *phdl, const char *name) > +{ > + unsigned i; > + unsigned slot = INVALID_SLOT; > + odp_spinlock_lock(&lock); > + *phdl = ODP_LOG_INVALID; > + for (i = 0; i < ODP_LOG_MAX; i++) { > + /* Check for unused slot */ > + if (sources[i].phdl == NULL && slot == INVALID_SLOT) { > + /* Found first unused slot */ > + slot = i; > + } > + /* Check for source already present */ > + if (sources[i].name != NULL && > + strcmp(sources[i].name, name) == 0) { > + odp_spinlock_unlock(&lock); > + ODP_LOG_ERROR(odp_log, > + "Attempt to re-register source %s\n", > + name); > + return; > + } > + } > + if (slot != INVALID_SLOT) { > + sources[slot].phdl = phdl; > + sources[slot].name = name; > + *phdl = SLOT_LVL_TO_HDL(slot, ODP_LOG_DEFAULT_MASK); > + } > + odp_spinlock_unlock(&lock); > + if (slot != INVALID_SLOT) > + ODP_LOG_DEBUG(odp_log, "Registered source %s level %u\n", > + name, ODP_LOG_DEFAULT_MASK); > + else > + ODP_LOG_FATAL(odp_log, "Failed to register source %s\n", name); > +} > + > +/* Set the log level for a source identified by name */ > +int > +odp_log_set_level(const char *name, unsigned level) > +{ > + unsigned i; > + bool found = false; > + if (level > ODP_LOG_LVL_ALL) > + level = ODP_LOG_LVL_ALL; > + odp_spinlock_lock(&lock); > + for (i = 0; i < ODP_LOG_MAX; i++) { > + if (name == NULL || > + (sources[i].name != NULL && > + strcmp(sources[i].name, name) == 0)) { > + *sources[i].phdl = SLOT_LVL_TO_HDL(i, level); > + found = true; > + break; > + } > + } > + odp_spinlock_unlock(&lock); > + if (found) { > + if (name == NULL) > + ODP_LOG_DEBUG(odp_log, > + "Set log level for all sources to %u\n", > + level); > + else > + ODP_LOG_DEBUG(odp_log, > + "Set log level for source %s to %u\n", > + name, level); > + } else { > + errno = ENOENT; > + } > + return found ? 0 : -1; > +} > + > +/* Report a log message */ > +void > +odp_log_printf(unsigned lvl, odp_log_t hdl, const char *fmt, ...) > +{ > + unsigned slot = HDL_TO_SLOT(hdl); > + if (odp_likely(slot < ODP_LOG_MAX)) { > + const char *name = sources[slot].name; > + va_list ap; > + odp_log_callback_t cb; > + va_start(ap, fmt); > + cb = callback; > + if (cb != NULL) { > + cb(name, lvl, fmt, ap); > + } else { > + fprintf(stderr, "%s/%c: ", name, > + " FEWID67"[lvl & 0x7U]); > + vfprintf(stderr, fmt, ap); > + } > + va_end(ap); > + } > + /* Else ignore call with invalid handle */ > +} > + > +/* Install a user-defined call-back for handling log messages */ > +void > +odp_log_set_callback(odp_log_callback_t cb) > +{ > + callback = cb; > + odp_sync_stores(); > +} > + > +/* Iterate through all registered log sources */ > +int > +odp_log_next(odp_log_t *phdl, char *name, size_t namelen, unsigned *plvl) > +{ > + int another; > + unsigned slot; > + odp_spinlock_lock(&lock); > + if (*phdl == ODP_LOG_INVALID) > + slot = 0; /* First slot */ > + else > + slot = HDL_TO_SLOT(*phdl) + 1U; /* Next slot */ > + if (slot < ODP_LOG_MAX && sources[slot].phdl != NULL) { > + *phdl = SLOT_LVL_TO_HDL(slot, 0); > + strncpy(name, sources[slot].name, namelen - 1U); > + name[namelen - 1U] = 0; > + *plvl = HDL_TO_LVL(*sources[slot].phdl); > + another = 1; /* true */ > + } else { > + another = 0; /* false */ > + } > + odp_spinlock_unlock(&lock); > + return another; > +}
diff --git a/platform/linux-generic/Makefile.am b/platform/linux-generic/Makefile.am index f4dfdc1..f30c6ff 100644 --- a/platform/linux-generic/Makefile.am +++ b/platform/linux-generic/Makefile.am @@ -20,6 +20,7 @@ include_HEADERS = \ $(top_srcdir)/platform/linux-generic/include/api/odp_debug.h \ $(top_srcdir)/platform/linux-generic/include/api/odp_hints.h \ $(top_srcdir)/platform/linux-generic/include/api/odp_init.h \ + $(top_srcdir)/platform/linux-generic/include/api/odp_log.h \ $(top_srcdir)/platform/linux-generic/include/api/odp_packet_flags.h \ $(top_srcdir)/platform/linux-generic/include/api/odp_packet.h \ $(top_srcdir)/platform/linux-generic/include/api/odp_packet_io.h \ @@ -58,6 +59,7 @@ __LIB__libodp_la_SOURCES = \ odp_crypto.c \ odp_init.c \ odp_linux.c \ + odp_log.c \ odp_packet.c \ odp_packet_flags.c \ odp_packet_io.c \ diff --git a/platform/linux-generic/include/api/odp_log.h b/platform/linux-generic/include/api/odp_log.h new file mode 100644 index 0000000..b8c49e3 --- /dev/null +++ b/platform/linux-generic/include/api/odp_log.h @@ -0,0 +1,59 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/** + * @file + * + * ODP internal logging facility - public management API + */ + +#ifndef ODP_LOG_H_ +#define ODP_LOG_H_ + +#include <stdarg.h> +#include <stdbool.h> +#include <stdint.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** Fatal error for function, may not return to caller */ +#define ODP_LOG_LVL_FATAL 1U +/** Error prevented function to succeed but caller should be able to recover */ +#define ODP_LOG_LVL_ERROR 2U +/** Problem detected in function but recovered locally */ +#define ODP_LOG_LVL_WARNING 3U +/** Informational message intended for user */ +#define ODP_LOG_LVL_INFORM 4U +/** Debug message intended for developer */ +#define ODP_LOG_LVL_DEBUG 5U + +#define ODP_LOG_LVL_NONE 0U /**< Disable all log levels */ +#define ODP_LOG_LVL_ALL 7U /**< Enable all log levels */ + +typedef volatile uint32_t odp_log_t; +#define ODP_LOG_INVALID 0U + +/** Call-back type definition for user-defined log facility */ +typedef void (*odp_log_callback_t)(const char *name, + unsigned level, + const char *fmt, + va_list ap); + +/** Set the log level for a source identified by name */ +int odp_log_set_level(const char *name, unsigned level); +/** Install a user-defined call-back for handling log messages */ +void odp_log_set_callback(odp_log_callback_t cb); +/** Iterate through all registered log sources */ +int odp_log_next(odp_log_t *phdl, char *name, size_t namelen, unsigned *level); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/platform/linux-generic/include/odp_log_internal.h b/platform/linux-generic/include/odp_log_internal.h new file mode 100644 index 0000000..7ac3ab1 --- /dev/null +++ b/platform/linux-generic/include/odp_log_internal.h @@ -0,0 +1,115 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/** + * @file + * + * ODP internal logging facility - client API + */ + +#ifndef ODP_LOG_INTERNAL_H_ +#define ODP_LOG_INTERNAL_H_ + +#include <stdint.h> +#include <odp_log.h> +#include <odp_hints.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef ODP_LOG_LEVEL +#define ODP_LOG_LEVEL ODP_LOG_LVL_ALL +#endif + +/* Report a message to the log */ +#define ODP_LOG_MSG(_lvl, _hdl, _fmt, ...) \ +do { \ + unsigned __lvl = (_lvl); \ + odp_log_t __hdl = (_hdl); \ + const char *__fmt = (_fmt); \ + if (odp_unlikely((__hdl & 0x7) >= __lvl)) \ + odp_log_printf(__lvl, __hdl, __fmt, ##__VA_ARGS__); \ +} while (0) + +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_FATAL +#define ODP_LOG_FATAL(_src, _fmt, ...) \ +ODP_LOG_MSG(ODP_LOG_LVL_FATAL, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) +#else +#define ODP_LOG_FATAL(_src, _fmt, ...) (void)0 +#endif + +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_ERROR +#define ODP_LOG_ERROR(_src, _fmt, ...) \ +ODP_LOG_MSG(ODP_LOG_LVL_ERROR, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) +#else +#define ODP_LOG_ERROR(_src, _fmt, ...) (void)0 +#endif + +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_WARNING +#define ODP_LOG_WARNING(_src, _fmt, ...) \ +ODP_LOG_MSG(ODP_LOG_LVL_WARNING, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) +#else +#define ODP_LOG_WARNING(_src, _fmt, ...) (void)0 +#endif + +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_INFORM +#define ODP_LOG_INFORM(_src, _fmt, ...) \ +ODP_LOG_MSG(ODP_LOG_LVL_INFORM, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) +#else +#define ODP_LOG_INFORM(_src, _fmt, ...) (void)0 +#endif + +#if ODP_LOG_LEVEL >= ODP_LOG_LVL_DEBUG +#define ODP_LOG_DEBUG(_src, _fmt, ...) \ +ODP_LOG_MSG(ODP_LOG_LVL_DEBUG, (_odp_log_src_ ## _src), (_fmt), ##__VA_ARGS__) +#else +#define ODP_LOG_DEBUG(_src, _fmt, ...) (void)0 +#endif + + +#define ODP_LOG_DECLARE(src) odp_log_t _odp_log_src_ ## src +#define ODP_LOG_REGISTER(src) odp_log_register(&_odp_log_src_ ## src, #src) + +/* Calls indirectly used by log clients. Use macros above! */ +/* Register a log source with the specified name */ +void odp_log_register(odp_log_t *hdl, const char *name); +/* Report a log message */ +void odp_log_printf(unsigned lvl, odp_log_t hdl, const char *fmt, ...); + +/* Init log module, specify call-back (or NULL for default behaviour) */ +void odp_log_init(odp_log_callback_t cb); + + +/* Example usage: + +ODP_LOG_DECLARE(odp_queue); + +//Use default output mechanism +odp_log_init(NULL); + +//Register log source and set default log level +ODP_LOG_REGISTER(odp_queue); + +//Log a message with severity error +ODP_LOG_ERROR(odp_queue, "Failed to create queue, param=%u\n", 242); + +//Set log level for a source to log everything +(void)odp_log_set_level("odp_queue", ODP_LOG_LVL_ALL); + +//Install a custom vprintf function to handle log messages +odp_log_set_callback(my_vprintf); + +//Log a message that will be forwarded to the user-specified log +ODP_LOG_INFORM(odp_queue, "Message printed using user-defined call-back\n"); + +*/ + +#ifdef __cplusplus +} +#endif +#endif diff --git a/platform/linux-generic/odp_init.c b/platform/linux-generic/odp_init.c index 5b7e192..3677f1b 100644 --- a/platform/linux-generic/odp_init.c +++ b/platform/linux-generic/odp_init.c @@ -7,46 +7,54 @@ #include <odp_init.h> #include <odp_internal.h> #include <odp_debug.h> +#include <odp_log_internal.h> +ODP_LOG_DECLARE(odp_init); int odp_init_global(void) { + /* Init log mechanism first so that it can be used by all other + modules (including init) */ + odp_log_init(NULL); /* NULL => Use default output mechanism */ + + ODP_LOG_REGISTER(odp_init); + odp_thread_init_global(); odp_system_info_init(); if (odp_shm_init_global()) { - ODP_ERR("ODP shm init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP shm init failed.\n"); return -1; } if (odp_buffer_pool_init_global()) { - ODP_ERR("ODP buffer pool init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP buffer pool init failed.\n"); return -1; } if (odp_queue_init_global()) { - ODP_ERR("ODP queue init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP queue init failed.\n"); return -1; } if (odp_schedule_init_global()) { - ODP_ERR("ODP schedule init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP schedule init failed.\n"); return -1; } if (odp_pktio_init_global()) { - ODP_ERR("ODP packet io init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP packet io init failed.\n"); return -1; } if (odp_timer_init_global()) { - ODP_ERR("ODP timer init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP timer init failed.\n"); return -1; } if (odp_crypto_init_global()) { - ODP_ERR("ODP crypto init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP crypto init failed.\n"); return -1; } @@ -59,12 +67,12 @@ int odp_init_local(int thr_id) odp_thread_init_local(thr_id); if (odp_pktio_init_local()) { - ODP_ERR("ODP packet io local init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP packet io local init failed.\n"); return -1; } if (odp_schedule_init_local()) { - ODP_ERR("ODP schedule local init failed.\n"); + ODP_LOG_FATAL(odp_init, "ODP schedule local init failed.\n"); return -1; } diff --git a/platform/linux-generic/odp_log.c b/platform/linux-generic/odp_log.c new file mode 100644 index 0000000..99b2803 --- /dev/null +++ b/platform/linux-generic/odp_log.c @@ -0,0 +1,189 @@ +/* Copyright (c) 2014, Linaro Limited + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + + +/** + * @file + * + * ODP logging utility + */ + +#include <errno.h> +#include <limits.h> +#include <stdarg.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <strings.h> +#include <odp_debug.h> +#include <odp_spinlock.h> +#include <odp_sync.h> +#include <odp_log.h> +#include <odp_log_internal.h> + +#ifndef ODP_LOG_DEFAULT_MASK +#define ODP_LOG_DEFAULT_MASK (ODP_LOG_LVL_FATAL | ODP_LOG_LVL_ERROR) +#endif + +/* Maximum number of log sources */ +#ifndef ODP_LOG_MAX +#define ODP_LOG_MAX 64 +#endif + +ODP_STATIC_ASSERT(ODP_LOG_LVL_ALL == 7U, "ODP_LOG_LVL_ALL_ERROR"); + +#define HDL_TO_LVL(hdl) ((hdl) & 0x7U) +#define HDL_TO_SLOT(hdl) (((hdl) >> 3U) - 1U) +#define SLOT_LVL_TO_HDL(slot, lvl) ((((slot) + 1U) << 3U) | (lvl)) +#define INVALID_SLOT ~0U + +struct source { + odp_log_t *phdl; /* Pointer to the user's odp_log_t variable */ + const char *name; +}; + +static odp_spinlock_t lock; +static volatile odp_log_callback_t callback; +ODP_LOG_DECLARE(odp_log); +static struct source sources[ODP_LOG_MAX]; + +void +odp_log_init(odp_log_callback_t cb) +{ + odp_spinlock_init(&lock); + callback = cb; + memset(sources, 0, sizeof(sources)); + odp_sync_stores(); + ODP_LOG_REGISTER(odp_log); + odp_log_set_level("odp_log", ODP_LOG_LVL_ALL); +} + +/* Register a log source with the specified name */ +void +odp_log_register(odp_log_t *phdl, const char *name) +{ + unsigned i; + unsigned slot = INVALID_SLOT; + odp_spinlock_lock(&lock); + *phdl = ODP_LOG_INVALID; + for (i = 0; i < ODP_LOG_MAX; i++) { + /* Check for unused slot */ + if (sources[i].phdl == NULL && slot == INVALID_SLOT) { + /* Found first unused slot */ + slot = i; + } + /* Check for source already present */ + if (sources[i].name != NULL && + strcmp(sources[i].name, name) == 0) { + odp_spinlock_unlock(&lock); + ODP_LOG_ERROR(odp_log, + "Attempt to re-register source %s\n", + name); + return; + } + } + if (slot != INVALID_SLOT) { + sources[slot].phdl = phdl; + sources[slot].name = name; + *phdl = SLOT_LVL_TO_HDL(slot, ODP_LOG_DEFAULT_MASK); + } + odp_spinlock_unlock(&lock); + if (slot != INVALID_SLOT) + ODP_LOG_DEBUG(odp_log, "Registered source %s level %u\n", + name, ODP_LOG_DEFAULT_MASK); + else + ODP_LOG_FATAL(odp_log, "Failed to register source %s\n", name); +} + +/* Set the log level for a source identified by name */ +int +odp_log_set_level(const char *name, unsigned level) +{ + unsigned i; + bool found = false; + if (level > ODP_LOG_LVL_ALL) + level = ODP_LOG_LVL_ALL; + odp_spinlock_lock(&lock); + for (i = 0; i < ODP_LOG_MAX; i++) { + if (name == NULL || + (sources[i].name != NULL && + strcmp(sources[i].name, name) == 0)) { + *sources[i].phdl = SLOT_LVL_TO_HDL(i, level); + found = true; + break; + } + } + odp_spinlock_unlock(&lock); + if (found) { + if (name == NULL) + ODP_LOG_DEBUG(odp_log, + "Set log level for all sources to %u\n", + level); + else + ODP_LOG_DEBUG(odp_log, + "Set log level for source %s to %u\n", + name, level); + } else { + errno = ENOENT; + } + return found ? 0 : -1; +} + +/* Report a log message */ +void +odp_log_printf(unsigned lvl, odp_log_t hdl, const char *fmt, ...) +{ + unsigned slot = HDL_TO_SLOT(hdl); + if (odp_likely(slot < ODP_LOG_MAX)) { + const char *name = sources[slot].name; + va_list ap; + odp_log_callback_t cb; + va_start(ap, fmt); + cb = callback; + if (cb != NULL) { + cb(name, lvl, fmt, ap); + } else { + fprintf(stderr, "%s/%c: ", name, + " FEWID67"[lvl & 0x7U]); + vfprintf(stderr, fmt, ap); + } + va_end(ap); + } + /* Else ignore call with invalid handle */ +} + +/* Install a user-defined call-back for handling log messages */ +void +odp_log_set_callback(odp_log_callback_t cb) +{ + callback = cb; + odp_sync_stores(); +} + +/* Iterate through all registered log sources */ +int +odp_log_next(odp_log_t *phdl, char *name, size_t namelen, unsigned *plvl) +{ + int another; + unsigned slot; + odp_spinlock_lock(&lock); + if (*phdl == ODP_LOG_INVALID) + slot = 0; /* First slot */ + else + slot = HDL_TO_SLOT(*phdl) + 1U; /* Next slot */ + if (slot < ODP_LOG_MAX && sources[slot].phdl != NULL) { + *phdl = SLOT_LVL_TO_HDL(slot, 0); + strncpy(name, sources[slot].name, namelen - 1U); + name[namelen - 1U] = 0; + *plvl = HDL_TO_LVL(*sources[slot].phdl); + another = 1; /* true */ + } else { + another = 0; /* false */ + } + odp_spinlock_unlock(&lock); + return another; +}
Signed-off-by: Ola Liljedahl <ola.liljedahl@linaro.org> --- (This document/code contribution attached is provided under the terms of agreement LES-LTM-21309) Log API for internal ODP use. Logging can be compile time and run time disabled. Compile out all log levels: -DODP_LOG_LEVEL=0 Compile in all log levels: -DODP_LOG_LEVEL=7 Enable all log levels: -DODP_LOG_DEFAULT_MASK=7 (default: fatal+error) Run time setting: odp_log_set_level("module_name", level); Log messages can be redirected: odp_log_set_callback(fn); Usage: ODP_LOG_DECLARE(my_mod); /* File-scope declaration */ ODP_LOG_REGISTER(my_mod); /* Init call */ ODP_LOG_ERROR(my_mod, "Error %u has occured\n", 242); platform/linux-generic/Makefile.am | 2 + platform/linux-generic/include/api/odp_log.h | 59 +++++++ platform/linux-generic/include/odp_log_internal.h | 115 +++++++++++++ platform/linux-generic/odp_init.c | 26 +-- platform/linux-generic/odp_log.c | 189 ++++++++++++++++++++++ 5 files changed, 382 insertions(+), 9 deletions(-) create mode 100644 platform/linux-generic/include/api/odp_log.h create mode 100644 platform/linux-generic/include/odp_log_internal.h create mode 100644 platform/linux-generic/odp_log.c