summaryrefslogtreecommitdiff
path: root/kernel/event_logger.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/event_logger.c')
-rw-r--r--kernel/event_logger.c151
1 files changed, 151 insertions, 0 deletions
diff --git a/kernel/event_logger.c b/kernel/event_logger.c
new file mode 100644
index 000000000..eb9366c3a
--- /dev/null
+++ b/kernel/event_logger.c
@@ -0,0 +1,151 @@
+/*
+ * Copyright (c) 2015 Intel Corporation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @file
+ * @brief Event logger support.
+ */
+
+#include <misc/event_logger.h>
+#include <misc/ring_buffer.h>
+
+void sys_event_logger_init(struct event_logger *logger,
+ uint32_t *logger_buffer, uint32_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, uint16_t event_id,
+ uint32_t *event_data, uint8_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, uint16_t event_id,
+ uint32_t *event_data, uint8_t data_size)
+{
+ 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
+ * behaviour.
+ *
+ * @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
+ * behaviour 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,
+ uint16_t event_id, uint32_t *event_data, uint8_t data_size)
+{
+ extern void _sem_give_non_preemptible(struct k_sem *sem);
+
+ event_logger_put(logger, event_id, event_data, data_size,
+ _sem_give_non_preemptible);
+}
+
+
+static int event_logger_get(struct event_logger *logger,
+ uint16_t *event_id, uint8_t *dropped_event_count,
+ uint32_t *buffer, uint8_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, uint16_t *event_id,
+ uint8_t *dropped_event_count, uint32_t *buffer,
+ uint8_t *buffer_size)
+{
+ if (k_sem_take(&(logger->sync_sema), K_NO_WAIT)) {
+ 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, uint16_t *event_id,
+ uint8_t *dropped_event_count, uint32_t *buffer,
+ uint8_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_NANO_TIMEOUTS
+int sys_event_logger_get_wait_timeout(struct event_logger *logger,
+ uint16_t *event_id,
+ uint8_t *dropped_event_count,
+ uint32_t *buffer, uint8_t *buffer_size,
+ uint32_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_NANO_TIMEOUTS */