Boot Linux faster!

Check our new training course

Boot Linux faster!

Check our new training course
and Creative Commons CC-BY-SA
lecture and lab materials

Bootlin logo

Elixir Cross Referencer

/*
 * Copyright (c) 2018 Intel Corporation
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <kernel_structs.h>
#include "wrapper.h"

#define DONT_CARE               (0)
#define NSEC_PER_MSEC           (NSEC_PER_USEC * USEC_PER_MSEC)

/**
 * @brief Set the specified Thread Flags of a thread.
 */
uint32_t osThreadFlagsSet(osThreadId_t thread_id, uint32_t flags)
{
	int key;
	struct cv2_thread *tid = (struct cv2_thread *)thread_id;

	if ((thread_id == NULL) || (is_cmsis_rtos_v2_thread(thread_id) == NULL)
	    || (flags & 0x80000000)) {
		return osFlagsErrorParameter;
	}

	key = irq_lock();
	tid->signal_results |= flags;
	irq_unlock(key);

	k_poll_signal_raise(&tid->poll_signal, DONT_CARE);

	return tid->signal_results;
}

/**
 * @brief Get the current Thread Flags of current running thread.
 */
uint32_t osThreadFlagsGet(void)
{
	struct cv2_thread *tid;

	if (k_is_in_isr()) {
		return 0;
	}

	tid = (struct cv2_thread *)osThreadGetId();
	if (tid == NULL) {
		return 0;
	} else {
		return tid->signal_results;
	}
}

/**
 * @brief Clear the specified Thread Flags of current running thread.
 */
uint32_t osThreadFlagsClear(uint32_t flags)
{
	struct cv2_thread *tid;
	int sig, key;

	if (k_is_in_isr()) {
		return osFlagsErrorUnknown;
	}

	if (flags & 0x80000000) {
		return osFlagsErrorParameter;
	}

	tid = (struct cv2_thread *)osThreadGetId();
	if (tid == NULL) {
		return osFlagsErrorUnknown;
	}

	key = irq_lock();
	sig = tid->signal_results;
	tid->signal_results &= ~(flags);
	irq_unlock(key);

	return sig;
}

/**
 * @brief Wait for one or more Thread Flags of the current running thread to
 *        become signalled.
 */
uint32_t osThreadFlagsWait(uint32_t flags, uint32_t options, uint32_t timeout)
{
	struct cv2_thread *tid;
	int retval, key;
	u32_t sig;
	u32_t time_delta_ms, timeout_ms = __ticks_to_ms(timeout);
	u64_t time_stamp_start, hwclk_cycles_delta, time_delta_ns;

	if (k_is_in_isr()) {
		return osFlagsErrorUnknown;
	}

	if (flags & 0x80000000) {
		return osFlagsErrorParameter;
	}

	tid = (struct cv2_thread *)osThreadGetId();
	if (tid == NULL) {
		return osFlagsErrorUnknown;
	}

	for (;;) {

		time_stamp_start = (u64_t)k_cycle_get_32();

		switch (timeout) {
		case 0:
			retval = k_poll(&tid->poll_event, 1, K_NO_WAIT);
			break;
		case osWaitForever:
			retval = k_poll(&tid->poll_event, 1, K_FOREVER);
			break;
		default:
			retval = k_poll(&tid->poll_event, 1, timeout_ms);
			break;
		}

		switch (retval) {
		case 0:
			break;
		case -EAGAIN:
			return osFlagsErrorTimeout;
		default:
			return osFlagsErrorUnknown;
		}

		__ASSERT(tid->poll_event.state == K_POLL_STATE_SIGNALED,
			 "event state not signalled!");
		__ASSERT(tid->poll_event.signal->signaled == 1U,
			 "event signaled is not 1");

		/* Reset the states to facilitate the next trigger */
		tid->poll_event.signal->signaled = 0U;
		tid->poll_event.state = K_POLL_STATE_NOT_READY;

		if (options & osFlagsWaitAll) {
			/* Check if all events we are waiting on have
			 * been signalled
			 */
			if ((tid->signal_results & flags) == flags) {
				break;
			}

			/* If we need to wait on more signals, we need to
			 * adjust the timeout value accordingly based on
			 * the time that has already elapsed.
			 */
			hwclk_cycles_delta =
				(u64_t)k_cycle_get_32() - time_stamp_start;

			time_delta_ns =
				(u32_t)SYS_CLOCK_HW_CYCLES_TO_NS(hwclk_cycles_delta);

			time_delta_ms = (u32_t)time_delta_ns / NSEC_PER_MSEC;

			if (timeout_ms > time_delta_ms) {
				timeout_ms -= time_delta_ms;
			} else {
				timeout_ms = 0U;
			}
		} else {
			break;
		}
	}

	sig = tid->signal_results;
	if (!(options & osFlagsNoClear)) {

		/* Clear signal flags as the thread is ready now */
		key = irq_lock();
		tid->signal_results &= ~(flags);
		irq_unlock(key);
	}

	return sig;
}