From cc5094b3bfd34d1fe3aff6f1f9665f30227f58b6 Mon Sep 17 00:00:00 2001 From: Krzysztof Chruscinski Date: Thu, 16 May 2019 10:26:29 +0200 Subject: [PATCH] logging: Add option to block in thread context Added CONIFG_LOG_BLOCK_IN_THREAD option to block until buffer for log message is available. When log message is called in the thread and there is no buffer available in the pool, thread will block with configurable timeout (CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS). If buffer cannot be allocated by that time, message will be dropped. Signed-off-by: Krzysztof Chruscinski --- doc/reference/logging/index.rst | 5 +++++ subsys/logging/Kconfig | 20 ++++++++++++++++++++ subsys/logging/log_msg.c | 32 +++++++++++++++++++++++++++++++- 3 files changed, 56 insertions(+), 1 deletion(-) diff --git a/doc/reference/logging/index.rst b/doc/reference/logging/index.rst index 1fa655a30cc..cd3c0f6fafc 100644 --- a/doc/reference/logging/index.rst +++ b/doc/reference/logging/index.rst @@ -97,6 +97,11 @@ oldest one are discarded. :option:`CONFIG_LOG_MODE_NO_OVERFLOW`: When logger cannot allocate new message it is discarded. +:option:`CONFIG_LOG_BLOCK_IN_THREAD`: If enabled and new log message cannot +be allocated thread context will block for up to +:option:`CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS` or until log message is +allocated. + :option:`CONFIG_LOG_DEFAULT_LEVEL`: Default level, sets the logging level used by modules that are not setting their own logging level. diff --git a/subsys/logging/Kconfig b/subsys/logging/Kconfig index 530b9cb9ddf..ccd6b29c878 100644 --- a/subsys/logging/Kconfig +++ b/subsys/logging/Kconfig @@ -132,6 +132,26 @@ config LOG_MODE_NO_OVERFLOW endchoice +config LOG_BLOCK_IN_THREAD + bool "On log full block in thread context" + help + When enabled logger will block (if in the thread context) when + internal logger buffer is full and new message cannot be allocated. + +if LOG_BLOCK_IN_THREAD + +config LOG_BLOCK_IN_THREAD_TIMEOUT_MS + int "Maximum time (in milliseconds) thread can be blocked" + default 1000 + range -1 10000 + help + If new buffer for a log message cannot be allocated in that time, log + message is dropped. Forever blocking (-1) is possible however may lead + to the logger deadlock if logging is enabled in threads used for + logging (e.g. logger or shell thread). + +endif # LOG_BLOCK_IN_THREAD + config LOG_PROCESS_TRIGGER_THRESHOLD int "Amount of buffered logs which triggers processing thread." default 10 diff --git a/subsys/logging/log_msg.c b/subsys/logging/log_msg.c index ad3942fcc5f..541a976f544 100644 --- a/subsys/logging/log_msg.c +++ b/subsys/logging/log_msg.c @@ -31,6 +31,12 @@ BUILD_ASSERT_MSG((sizeof(union log_msg_head_data) == #define CONFIG_LOG_BUFFER_SIZE 0 #endif +/* Define needed when CONFIG_LOG_BLOCK_IN_THREAD is disabled to satisfy + * compiler. */ +#ifndef CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS +#define CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS 0 +#endif + #define MSG_SIZE sizeof(union log_msg_chunk) #define NUM_OF_MSGS (CONFIG_LOG_BUFFER_SIZE / MSG_SIZE) @@ -43,10 +49,34 @@ void log_msg_pool_init(void) k_mem_slab_init(&log_msg_pool, log_msg_pool_buf, MSG_SIZE, NUM_OF_MSGS); } +/* Return true if interrupts were locked in the context of this call. */ +static bool is_irq_locked(void) +{ + unsigned int key = z_arch_irq_lock(); + bool ret = z_arch_irq_unlocked(key); + + z_arch_irq_unlock(key); + return ret; +} + +/* Check if context can be blocked and pend on available memory slab. Context + * can be blocked if in a thread and interrupts are not locked. + */ +static bool block_on_alloc(void) +{ + if (!IS_ENABLED(CONFIG_LOG_BLOCK_IN_THREAD)) { + return false; + } + + return (!k_is_in_isr() && !is_irq_locked()); +} + union log_msg_chunk *log_msg_chunk_alloc(void) { union log_msg_chunk *msg = NULL; - int err = k_mem_slab_alloc(&log_msg_pool, (void **)&msg, K_NO_WAIT); + int err = k_mem_slab_alloc(&log_msg_pool, (void **)&msg, + block_on_alloc() ? + CONFIG_LOG_BLOCK_IN_THREAD_TIMEOUT_MS : K_NO_WAIT); if (err != 0) { msg = log_msg_no_space_handle();