logging: Add option for prolonged backend initialization
Extended logging backend API with log_backend_is_ready call which returns 0 is backend is ready. Logging core will make sure that all autostarted backends are ready before they are enabled. This option allows to handle backends which are not yet ready after init function is called (e.g. usb backend that is not plugged in). If this is the only backend in the system, logging processing will not start util first backend is ready. Function for checking readiness is optional and when backend has no such function it is assumed that backend is ready after initialization function returns which makes this feature backward compatible. Signed-off-by: Krzysztof Chruscinski <krzysztof.chruscinski@nordicsemi.no>
This commit is contained in:
parent
d84989a718
commit
d660492914
2 changed files with 108 additions and 12 deletions
|
@ -49,6 +49,7 @@ struct log_backend_api {
|
|||
void (*dropped)(const struct log_backend *const backend, uint32_t cnt);
|
||||
void (*panic)(const struct log_backend *const backend);
|
||||
void (*init)(const struct log_backend *const backend);
|
||||
int (*is_ready)(const struct log_backend *const backend);
|
||||
int (*format_set)(const struct log_backend *const backend,
|
||||
uint32_t log_type);
|
||||
};
|
||||
|
@ -101,6 +102,45 @@ extern const struct log_backend __log_backends_end[];
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Initialize or initiate the logging backend.
|
||||
*
|
||||
* If backend initialization takes longer time it could block logging thread
|
||||
* if backend is autostarted. That is because all backends are initilized in
|
||||
* the context of the logging thread. In that case, backend shall provide
|
||||
* function for polling for readiness (@ref log_backend_is_ready).
|
||||
*
|
||||
* @param[in] backend Pointer to the backend instance.
|
||||
*/
|
||||
static inline void log_backend_init(const struct log_backend *const backend)
|
||||
{
|
||||
__ASSERT_NO_MSG(backend != NULL);
|
||||
if (backend->api->init) {
|
||||
backend->api->init(backend);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Poll for backend readiness.
|
||||
*
|
||||
* If backend is ready immediately after initialization then backend may not
|
||||
* provide this function.
|
||||
*
|
||||
* @param[in] backend Pointer to the backend instance.
|
||||
*
|
||||
* @retval 0 if backend is ready.
|
||||
* @retval -EBUSY if backend is not yet ready.
|
||||
*/
|
||||
static inline int log_backend_is_ready(const struct log_backend *const backend)
|
||||
{
|
||||
__ASSERT_NO_MSG(backend != NULL);
|
||||
if (backend->api->is_ready) {
|
||||
return backend->api->is_ready(backend);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Put message with log entry to the backend.
|
||||
*
|
||||
|
|
|
@ -622,13 +622,35 @@ void log_core_init(void)
|
|||
}
|
||||
}
|
||||
|
||||
void log_init(void)
|
||||
static uint32_t activate_foreach_backend(uint32_t mask)
|
||||
{
|
||||
uint32_t mask_cpy = mask;
|
||||
|
||||
while (mask_cpy) {
|
||||
uint32_t i = __builtin_ctz(mask_cpy);
|
||||
const struct log_backend *backend = log_backend_get(i);
|
||||
|
||||
mask_cpy &= ~BIT(i);
|
||||
if (log_backend_is_ready(backend) == 0) {
|
||||
mask &= ~BIT(i);
|
||||
log_backend_enable(backend,
|
||||
backend->cb->ctx,
|
||||
CONFIG_LOG_MAX_LEVEL);
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
static uint32_t z_log_init(bool blocking, bool can_sleep)
|
||||
{
|
||||
uint32_t mask = 0;
|
||||
|
||||
__ASSERT_NO_MSG(log_backend_count_get() < LOG_FILTERS_NUM_OF_SLOTS);
|
||||
int i;
|
||||
|
||||
if (atomic_inc(&initialized) != 0) {
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Assign ids to backends. */
|
||||
|
@ -636,17 +658,39 @@ void log_init(void)
|
|||
const struct log_backend *backend = log_backend_get(i);
|
||||
|
||||
if (backend->autostart) {
|
||||
if (backend->api->init != NULL) {
|
||||
backend->api->init(backend);
|
||||
}
|
||||
log_backend_init(backend);
|
||||
|
||||
/* If backend has activation function then backend is
|
||||
* not ready until activated.
|
||||
*/
|
||||
if (log_backend_is_ready(backend) == 0) {
|
||||
log_backend_enable(backend,
|
||||
backend->cb->ctx,
|
||||
CONFIG_LOG_MAX_LEVEL);
|
||||
} else {
|
||||
mask |= BIT(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If blocking init, wait until all backends are activated. */
|
||||
if (blocking) {
|
||||
while (mask) {
|
||||
mask = activate_foreach_backend(mask);
|
||||
if (IS_ENABLED(CONFIG_MULTITHREADING) && can_sleep) {
|
||||
k_msleep(10);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return mask;
|
||||
}
|
||||
|
||||
void log_init(void)
|
||||
{
|
||||
(void)z_log_init(true, true);
|
||||
}
|
||||
|
||||
static void thread_set(k_tid_t process_tid)
|
||||
{
|
||||
proc_tid = process_tid;
|
||||
|
@ -694,7 +738,7 @@ void z_impl_log_panic(void)
|
|||
/* If panic happened early logger might not be initialized.
|
||||
* Forcing initialization of the logger and auto-starting backends.
|
||||
*/
|
||||
log_init();
|
||||
(void)z_log_init(true, false);
|
||||
|
||||
if (IS_ENABLED(CONFIG_LOG_FRONTEND)) {
|
||||
log_frontend_panic();
|
||||
|
@ -1338,12 +1382,24 @@ static void log_process_thread_func(void *dummy1, void *dummy2, void *dummy3)
|
|||
{
|
||||
__ASSERT_NO_MSG(log_backend_count_get() > 0);
|
||||
|
||||
log_init();
|
||||
uint32_t activate_mask = z_log_init(false, false);
|
||||
k_timeout_t timeout = K_MSEC(50); /* Arbitrary value */
|
||||
|
||||
thread_set(k_current_get());
|
||||
|
||||
/* Logging thread is periodically waken up until all backends that
|
||||
* should be autostarted are ready.
|
||||
*/
|
||||
while (true) {
|
||||
if (activate_mask) {
|
||||
activate_mask = activate_foreach_backend(activate_mask);
|
||||
if (!activate_mask) {
|
||||
timeout = K_FOREVER;
|
||||
}
|
||||
}
|
||||
|
||||
if (log_process(false) == false) {
|
||||
k_sem_take(&log_process_thread_sem, K_FOREVER);
|
||||
(void)k_sem_take(&log_process_thread_sem, timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1368,7 +1424,7 @@ static int enable_logger(const struct device *arg)
|
|||
K_NO_WAIT));
|
||||
k_thread_name_set(&logging_thread, "logging");
|
||||
} else {
|
||||
log_init();
|
||||
(void)z_log_init(false, false);
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue