Signed-off-by: Ola Liljedahl <[email protected]>
---
(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;
+}