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 <cmsis_os.h>

#define NSEC_PER_MSEC (NSEC_PER_USEC * USEC_PER_MSEC)

void *k_thread_other_custom_data_get(struct k_thread *thread_id)
{
	return thread_id->custom_data;
}

/**
 * @brief Set the specified Signal Flags of an active thread.
 */
int32_t osSignalSet(osThreadId thread_id, int32_t signals)
{
	int sig, key;
	osThreadDef_t *thread_def =
		(osThreadDef_t *)k_thread_other_custom_data_get(
						(struct k_thread *)thread_id);

	if (_is_in_isr() || (thread_id == NULL) ||
		(signals >= (1 << (osFeature_Signals + 1)))) {
		return 0x80000000;
	}

	key = irq_lock();
	sig = thread_def->signal_results;
	thread_def->signal_results |= signals;
	irq_unlock(key);

	k_poll_signal(thread_def->poll_signal, signals);

	return sig;
}

/**
 * @brief Clear the specified Signal Flags of an active thread.
 */
int32_t osSignalClear(osThreadId thread_id, int32_t signals)
{
	int sig, key;
	osThreadDef_t *thread_def =
		(osThreadDef_t *)k_thread_other_custom_data_get(
						(struct k_thread *)thread_id);

	if (_is_in_isr() || (thread_id == NULL) ||
		(signals >= (1 << (osFeature_Signals + 1)))) {
		return 0x80000000;
	}

	key = irq_lock();
	sig = thread_def->signal_results;
	thread_def->signal_results &= ~(signals);
	irq_unlock(key);

	return sig;
}

/**
 * @brief Wait for one or more Signal Flags to become signalled for the
 * current running thread.
 */
osEvent osSignalWait(int32_t signals, uint32_t millisec)
{
	int retval, key;
	osEvent evt;
	u32_t time_delta_ms, timeout = millisec;
	u64_t time_stamp_start, hwclk_cycles_delta, time_delta_ns;

	if (_is_in_isr()) {
		evt.status = osErrorISR;
		return evt;
	}

	/* Check if signals is within the permitted range */
	if (signals >= (1 << (osFeature_Signals + 1))) {
		evt.status = osErrorValue;
		return evt;
	}

	osThreadDef_t *thread_def = k_thread_custom_data_get();

	for (;;) {

		time_stamp_start = (u64_t)k_cycle_get_32();

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

		switch (retval) {
		case 0:
			evt.status = osEventSignal;
			break;
		case -EAGAIN:
			if (millisec == 0) {
				evt.status = osOK;
			} else {
				evt.status = osEventTimeout;
			}
			return evt;
		default:
			evt.status = osErrorValue;
			return evt;
		}

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

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

		/* Check if all events we are waiting on have been signalled */
		if ((thread_def->signal_results & signals) == signals) {
			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 > time_delta_ms) {
			timeout -= time_delta_ms;
		} else {
			timeout = 0;
		}
	}

	evt.value.signals = thread_def->signal_results;

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

	return evt;
}