text: /*
   * Copyright (c) 2015 Intel Corporation
   *
   * SPDX-License-Identifier: Apache-2.0
   */
  
  /**
   * @file
   * @brief Event logger support.
   */
  
  #include <logging/event_logger.h>
  #include <misc/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 */
  