From cff2617a1dba2017d809fdccec1a12b6112c7e56 Mon Sep 17 00:00:00 2001 From: Krzysztof Chruscinski Date: Thu, 5 Jul 2018 09:21:35 +0200 Subject: [PATCH] logging: Add implicit initialization when logger used before init Logger must support the case when API is used before logger is explicitly initialized. When logger API is called and logger is not yet initialized, it is initialized implicitly with dummy timestamp function (timestamp source may not be yet available). Signed-off-by: Krzysztof Chruscinski --- subsys/logging/log_core.c | 133 +++++++++++++++++++++++++++++++------- 1 file changed, 111 insertions(+), 22 deletions(-) diff --git a/subsys/logging/log_core.c b/subsys/logging/log_core.c index fc508a46e3e6b..50819d0edad37 100644 --- a/subsys/logging/log_core.c +++ b/subsys/logging/log_core.c @@ -22,12 +22,43 @@ LOG_BACKEND_UART_DEFINE(log_backend_uart); #endif +#define LOG_STATE_UNINITIALIZED 0 +#define LOG_STATE_INIT_IN_PROGRESS 1 +#define LOG_STATE_INITIALIZED 2 + static struct log_list_t list; static bool panic_mode; -static bool initialized; - +static atomic_t log_state; static timestamp_get_t timestamp_func; +static int init(void); +static bool cond_init(void); + +/** @brief Macro for implicit logger initialization. + * + * If logger is used before being explicitly initialized it must be + * initialized implicitly and preemption must be considered. First flag + * is checked if log is initialized. Action is performed only if logger is not + * yet initialized. This initial check is performed in macro for performance + * reasons. + */ +#define _COND_INIT(_return) \ + do { \ + if (log_state < LOG_STATE_INITIALIZED) { \ + if (!cond_init()) { \ + _return; \ + } \ + } \ + } while (0) + +#define LOG_COND_INIT() _COND_INIT(return) +#define LOG_COND_INIT_PRINTK() _COND_INIT(return 0) + +static u32_t null_timestamp_get(void) +{ + return 0; +} + static inline void msg_finalize(struct log_msg *msg, struct log_msg_ids src_level) { @@ -44,13 +75,45 @@ static inline void msg_finalize(struct log_msg *msg, } } +/** @brief Function for conditional initialization. + * + * Log is initialized only if previously it was in uninit state. Otherwise + * log entry must be discarded. + * + * @return True if log message can be created, false if message must be dropped. + * + */ +static bool cond_init(void) +{ + atomic_val_t prev_log_state; + + prev_log_state = atomic_inc(&log_state); + + if (prev_log_state != LOG_STATE_UNINITIALIZED) { + /* Another initialization was interrupted, initialization may be + * in progress thus it is safer to drop the log. + */ + return false; + } + + init(); + log_set_timestamp_func(null_timestamp_get, 1); + + return true; +} + void log_0(const char *str, struct log_msg_ids src_level) { - struct log_msg *msg = log_msg_create_0(str); + struct log_msg *msg; + + LOG_COND_INIT(); + + msg = log_msg_create_0(str); if (msg == NULL) { return; } + msg_finalize(msg, src_level); } @@ -58,11 +121,16 @@ void log_1(const char *str, u32_t arg0, struct log_msg_ids src_level) { - struct log_msg *msg = log_msg_create_1(str, arg0); + struct log_msg *msg; + + LOG_COND_INIT(); + + msg = log_msg_create_1(str, arg0); if (msg == NULL) { return; } + msg_finalize(msg, src_level); } @@ -71,7 +139,11 @@ void log_2(const char *str, u32_t arg1, struct log_msg_ids src_level) { - struct log_msg *msg = log_msg_create_2(str, arg0, arg1); + struct log_msg *msg; + + LOG_COND_INIT(); + + msg = log_msg_create_2(str, arg0, arg1); if (msg == NULL) { return; @@ -86,7 +158,11 @@ void log_3(const char *str, u32_t arg2, struct log_msg_ids src_level) { - struct log_msg *msg = log_msg_create_3(str, arg0, arg1, arg2); + struct log_msg *msg; + + LOG_COND_INIT(); + + msg = log_msg_create_3(str, arg0, arg1, arg2); if (msg == NULL) { return; @@ -100,7 +176,11 @@ void log_n(const char *str, u32_t narg, struct log_msg_ids src_level) { - struct log_msg *msg = log_msg_create_n(str, args, narg); + struct log_msg *msg; + + LOG_COND_INIT(); + + msg = log_msg_create_n(str, args, narg); if (msg == NULL) { return; @@ -113,7 +193,11 @@ void log_hexdump(const u8_t *data, u32_t length, struct log_msg_ids src_level) { - struct log_msg *msg = log_msg_hexdump_create(data, length); + struct log_msg *msg; + + LOG_COND_INIT(); + + msg = log_msg_hexdump_create(data, length); if (msg == NULL) { return; @@ -130,9 +214,7 @@ int log_printk(const char *fmt, va_list ap) struct log_msg *msg; int length; - if (!initialized) { - log_init(); - } + LOG_COND_INIT_PRINTK(); length = vsnprintf(formatted_str, sizeof(formatted_str), fmt, ap); @@ -173,7 +255,7 @@ static u32_t timestamp_get(void) return k_cycle_get_32(); } -int log_init(void) +static int init(void) { assert(log_backend_count_get() < LOG_FILTERS_NUM_OF_SLOTS); @@ -181,17 +263,12 @@ int log_init(void) timestamp_func = timestamp_get; log_output_timestamp_freq_set(CONFIG_SYS_CLOCK_HW_CYCLES_PER_SEC); - if (!initialized) { - log_list_init(&list); - - /* Assign ids to backends. */ - for (int i = 0; i < log_backend_count_get(); i++) { - log_backend_id_set(log_backend_get(i), - i + LOG_FILTER_FIRST_BACKEND_SLOT_IDX); - } + log_list_init(&list); - panic_mode = false; - initialized = true; + /* Assign ids to backends. */ + for (int i = 0; i < log_backend_count_get(); i++) { + log_backend_id_set(log_backend_get(i), + i + LOG_FILTER_FIRST_BACKEND_SLOT_IDX); } #ifdef CONFIG_LOG_BACKEND_UART @@ -200,9 +277,21 @@ int log_init(void) NULL, CONFIG_LOG_DEFAULT_LEVEL); #endif + panic_mode = false; + atomic_inc(&log_state); + return 0; } +int log_init(void) +{ + if (atomic_inc(&log_state) != LOG_STATE_UNINITIALIZED) { + return 0; + } + + return init(); +} + int log_set_timestamp_func(timestamp_get_t timestamp_getter, u32_t freq) { if (!timestamp_getter) {