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 <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
Krzysztof Chruscinski 2019-05-16 10:26:29 +02:00 committed by Andrew Boie
commit cc5094b3bf
3 changed files with 56 additions and 1 deletions

View file

@ -97,6 +97,11 @@ oldest one are discarded.
:option:`CONFIG_LOG_MODE_NO_OVERFLOW`: When logger cannot allocate new message :option:`CONFIG_LOG_MODE_NO_OVERFLOW`: When logger cannot allocate new message
it is discarded. 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 :option:`CONFIG_LOG_DEFAULT_LEVEL`: Default level, sets the logging level
used by modules that are not setting their own logging level. used by modules that are not setting their own logging level.

View file

@ -132,6 +132,26 @@ config LOG_MODE_NO_OVERFLOW
endchoice 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 config LOG_PROCESS_TRIGGER_THRESHOLD
int "Amount of buffered logs which triggers processing thread." int "Amount of buffered logs which triggers processing thread."
default 10 default 10

View file

@ -31,6 +31,12 @@ BUILD_ASSERT_MSG((sizeof(union log_msg_head_data) ==
#define CONFIG_LOG_BUFFER_SIZE 0 #define CONFIG_LOG_BUFFER_SIZE 0
#endif #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 MSG_SIZE sizeof(union log_msg_chunk)
#define NUM_OF_MSGS (CONFIG_LOG_BUFFER_SIZE / MSG_SIZE) #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); 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 *log_msg_chunk_alloc(void)
{ {
union log_msg_chunk *msg = NULL; 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) { if (err != 0) {
msg = log_msg_no_space_handle(); msg = log_msg_no_space_handle();