logging: backend: notify when process thread finishes one cycle

This adds the bits to allow the process thread to notify
backends when it has finished processing pending log messages.

This allows, for example, flash-based backends to group writing
log messages to storage to limit wear, since log_output_flush()
is called per message. Also the backend does not have to resort
to using timer to periodically flush its buffer to storage,
avoiding waking up the device when there are no messages.
Another use of this is for backends requiring DMA transfers.
Grouping all pending log messages into one DMA transfer is
sometimes preferrable.

Signed-off-by: Daniel Leung <daniel.leung@intel.com>
This commit is contained in:
Daniel Leung 2022-04-30 17:18:35 -07:00 committed by Carles Cufí
commit d0d6e1181c
2 changed files with 30 additions and 0 deletions

View file

@ -31,6 +31,19 @@ struct log_backend;
* @brief Backend events * @brief Backend events
*/ */
enum log_backend_evt { enum log_backend_evt {
/**
* @brief Event when process thread finishes processing.
*
* This event is emitted when the process thread finishes
* processing pending log messages.
*
* @note This is not emitted when there are no pending
* log messages being processed.
*
* @note Deferred mode only.
*/
LOG_BACKEND_EVT_PROCESS_THREAD_DONE,
/** @brief Maximum number of backend events */ /** @brief Maximum number of backend events */
LOG_BACKEND_EVT_MAX, LOG_BACKEND_EVT_MAX,
}; };

View file

@ -624,6 +624,16 @@ int log_mem_get_max_usage(uint32_t *max)
return mpsc_pbuf_get_max_utilization(&log_buffer, max); return mpsc_pbuf_get_max_utilization(&log_buffer, max);
} }
static void log_backend_notify_all(enum log_backend_evt event,
union log_backend_evt_arg *arg)
{
for (int i = 0; i < log_backend_count_get(); i++) {
const struct log_backend *backend = log_backend_get(i);
log_backend_notify(backend, event, arg);
}
}
static void log_process_thread_timer_expiry_fn(struct k_timer *timer) static void log_process_thread_timer_expiry_fn(struct k_timer *timer)
{ {
k_sem_give(&log_process_thread_sem); k_sem_give(&log_process_thread_sem);
@ -635,6 +645,7 @@ static void log_process_thread_func(void *dummy1, void *dummy2, void *dummy3)
uint32_t activate_mask = z_log_init(false, false); uint32_t activate_mask = z_log_init(false, false);
k_timeout_t timeout = K_MSEC(50); /* Arbitrary value */ k_timeout_t timeout = K_MSEC(50); /* Arbitrary value */
bool processed_any = false;
thread_set(k_current_get()); thread_set(k_current_get());
@ -650,7 +661,13 @@ static void log_process_thread_func(void *dummy1, void *dummy2, void *dummy3)
} }
if (log_process() == false) { if (log_process() == false) {
if (processed_any) {
processed_any = false;
log_backend_notify_all(LOG_BACKEND_EVT_PROCESS_THREAD_DONE, NULL);
}
(void)k_sem_take(&log_process_thread_sem, timeout); (void)k_sem_take(&log_process_thread_sem, timeout);
} else {
processed_any = true;
} }
} }
} }