165 lines
4.6 KiB
C
165 lines
4.6 KiB
C
/*
|
|
* Copyright (c) 2015 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Event logger support.
|
|
*/
|
|
|
|
#include <logging/event_logger.h>
|
|
#include <ring_buffer.h>
|
|
#include <kernel_structs.h>
|
|
|
|
void sys_event_logger_init(struct event_logger *logger,
|
|
u32_t *logger_buffer, u32_t buffer_size)
|
|
{
|
|
sys_ring_buf_init(&logger->ring_buf, buffer_size, logger_buffer);
|
|
k_sem_init(&(logger->sync_sema), 0, UINT_MAX);
|
|
}
|
|
|
|
|
|
static void event_logger_put(struct event_logger *logger, u16_t event_id,
|
|
u32_t *event_data, u8_t data_size,
|
|
void (*sem_give_fn)(struct k_sem *))
|
|
{
|
|
int ret;
|
|
unsigned int key;
|
|
|
|
key = irq_lock();
|
|
|
|
ret = sys_ring_buf_put(&logger->ring_buf, event_id,
|
|
logger->ring_buf.dropped_put_count, event_data,
|
|
data_size);
|
|
if (ret == 0) {
|
|
logger->ring_buf.dropped_put_count = 0;
|
|
/* inform that there is event data available on the buffer */
|
|
sem_give_fn(&(logger->sync_sema));
|
|
}
|
|
irq_unlock(key);
|
|
}
|
|
|
|
|
|
void sys_event_logger_put(struct event_logger *logger, u16_t event_id,
|
|
u32_t *event_data, u8_t data_size)
|
|
{
|
|
/* The thread invoking sys_k_event_logger_get_wait() supposed
|
|
* to only read the events of the threads which logged to kernel event
|
|
* logger buffer. But it should not write to kernel event logger
|
|
* buffer. Otherwise it would cause the race condition.
|
|
*/
|
|
|
|
struct k_thread *event_logger_thread =
|
|
(struct k_thread *)sys_dlist_peek_head(&(logger->sync_sema.wait_q));
|
|
if (_current != event_logger_thread) {
|
|
event_logger_put(logger, event_id, event_data,
|
|
data_size, k_sem_give);
|
|
}
|
|
}
|
|
|
|
|
|
/**
|
|
* @brief Send an event message to the logger with a non preemptible
|
|
* behavior.
|
|
*
|
|
* @details Add an event message to the ring buffer and signal the sync
|
|
* semaphore using the internal function _sem_give_non_preemptible to inform
|
|
* that there are event messages available, avoiding the preemptible
|
|
* behavior when the function is called from a task. This function
|
|
* should be only used for special cases where the sys_event_logger_put
|
|
* does not satisfy the needs.
|
|
*
|
|
* @param logger Pointer to the event logger used.
|
|
* @param event_id The identification of the profiler event.
|
|
* @param data Pointer to the data of the message.
|
|
* @param data_size Size of the buffer in 32-bit words.
|
|
*
|
|
* @return No return value.
|
|
*/
|
|
void _sys_event_logger_put_non_preemptible(struct event_logger *logger,
|
|
u16_t event_id, u32_t *event_data, u8_t data_size)
|
|
{
|
|
extern void _sem_give_non_preemptible(struct k_sem *sem);
|
|
|
|
/* The thread invoking sys_k_event_logger_get_wait() supposed
|
|
* to only read the events of the threads which logged to kernel event
|
|
* logger buffer. But it should not write to kernel event logger
|
|
* buffer. Otherwise it would cause the race condition.
|
|
*/
|
|
|
|
struct k_thread *event_logger_thread =
|
|
(struct k_thread *)sys_dlist_peek_head(&(logger->sync_sema.wait_q));
|
|
|
|
if (_current != event_logger_thread) {
|
|
event_logger_put(logger, event_id, event_data, data_size,
|
|
_sem_give_non_preemptible);
|
|
}
|
|
}
|
|
|
|
|
|
static int event_logger_get(struct event_logger *logger,
|
|
u16_t *event_id, u8_t *dropped_event_count,
|
|
u32_t *buffer, u8_t *buffer_size)
|
|
{
|
|
int ret;
|
|
|
|
ret = sys_ring_buf_get(&logger->ring_buf, event_id, dropped_event_count,
|
|
buffer, buffer_size);
|
|
if (likely(!ret)) {
|
|
return *buffer_size;
|
|
}
|
|
switch (ret) {
|
|
case -EMSGSIZE:
|
|
/* if the user can not retrieve the message, we increase the
|
|
* semaphore to indicate that the message remains in the buffer
|
|
*/
|
|
k_sem_give(&(logger->sync_sema));
|
|
return -EMSGSIZE;
|
|
case -EAGAIN:
|
|
return 0;
|
|
default:
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
|
|
int sys_event_logger_get(struct event_logger *logger, u16_t *event_id,
|
|
u8_t *dropped_event_count, u32_t *buffer,
|
|
u8_t *buffer_size)
|
|
{
|
|
if (k_sem_take(&(logger->sync_sema), K_NO_WAIT) == 0) {
|
|
return event_logger_get(logger, event_id, dropped_event_count,
|
|
buffer, buffer_size);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
int sys_event_logger_get_wait(struct event_logger *logger, u16_t *event_id,
|
|
u8_t *dropped_event_count, u32_t *buffer,
|
|
u8_t *buffer_size)
|
|
{
|
|
k_sem_take(&(logger->sync_sema), K_FOREVER);
|
|
|
|
return event_logger_get(logger, event_id, dropped_event_count, buffer,
|
|
buffer_size);
|
|
}
|
|
|
|
|
|
#ifdef CONFIG_SYS_CLOCK_EXISTS
|
|
int sys_event_logger_get_wait_timeout(struct event_logger *logger,
|
|
u16_t *event_id,
|
|
u8_t *dropped_event_count,
|
|
u32_t *buffer, u8_t *buffer_size,
|
|
u32_t timeout)
|
|
{
|
|
if (k_sem_take(&(logger->sync_sema), __ticks_to_ms(timeout))) {
|
|
return event_logger_get(logger, event_id, dropped_event_count,
|
|
buffer, buffer_size);
|
|
}
|
|
return 0;
|
|
}
|
|
#endif /* CONFIG_SYS_CLOCK_EXISTS */
|