Linux Audio

Check our new training course

Embedded Linux Audio

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

Bootlin logo

Elixir Cross Referencer

Loading...
/*
 * Copyright (c) 2010-2015 Wind River Systems, Inc.
 * Copyright (c) 2017 Oticon A/S
 *
 * SPDX-License-Identifier: Apache-2.0
 */

/**
 * @file
 * @brief Kernel swapper code for POSIX
 *
 * This module implements the __swap() routine for the POSIX architecture.
 *
 */

#include "kernel.h"
#include <kernel_structs.h>
#include "posix_core.h"
#include "irq.h"

/**
 *
 * @brief Initiate a cooperative context switch
 *
 * The __swap() routine is invoked by various kernel services to effect
 * a cooperative context switch.  Prior to invoking __swap(), the
 * caller disables interrupts (via irq_lock) and the return 'key'
 * is passed as a parameter to __swap().
 *
 *
 * @return -EAGAIN, or a return value set by a call to
 * _set_thread_return_value()
 *
 */

unsigned int __swap(unsigned int key)
{
/*
 * struct k_thread * _kernel.current is the currently runnig thread
 * struct k_thread * _kernel.ready_q.cache contains the next thread to run
 * (cannot be NULL)
 *
 * Here a "real" arch would save all processor registers, stack pointer and so
 * forth.
 * But we do not need to do so because we use posix threads => those are all
 * nicely kept by the native OS kernel
 */
	_kernel.current->callee_saved.key = key;
	_kernel.current->callee_saved.retval = -EAGAIN;
	/* retval may be modified with a call to _set_thread_return_value() */

#if CONFIG_KERNEL_EVENT_LOGGER_CONTEXT_SWITCH
	_sys_k_event_logger_context_switch();
#endif

	posix_thread_status_t *ready_thread_ptr =
		(posix_thread_status_t *)
		_kernel.ready_q.cache->callee_saved.thread_status;

	posix_thread_status_t *this_thread_ptr  =
		(posix_thread_status_t *)
		_kernel.current->callee_saved.thread_status;


	_kernel.current = _kernel.ready_q.cache;

	/*
	 * Here a "real" arch would load all processor registers for the thread
	 * to run. In this arch case, we just block this thread until allowed to
	 * run later, and signal to whomever is allowed to run to continue.
	 */
	posix_swap(ready_thread_ptr->thread_idx,
		this_thread_ptr->thread_idx);

	/* When we continue, _kernel->current points back to this thread */

	irq_unlock(_kernel.current->callee_saved.key);

	return _kernel.current->callee_saved.retval;
}



#ifdef CONFIG_ARCH_HAS_CUSTOM_SWAP_TO_MAIN
/**
 * This is just a version of __swap() in which we do not save anything about the
 * current thread.
 *
 * Note that we will never come back to this thread:
 * posix_core_main_thread_start() does never return
 */
void _arch_switch_to_main_thread(struct k_thread *main_thread,
		k_thread_stack_t *main_stack,
		size_t main_stack_size, k_thread_entry_t _main)
{
	posix_thread_status_t *ready_thread_ptr =
			(posix_thread_status_t *)
			_kernel.ready_q.cache->callee_saved.thread_status;
	_kernel.current = _kernel.ready_q.cache;

	posix_main_thread_start(ready_thread_ptr->thread_idx);
} /* LCOV_EXCL_LINE */
#endif

#ifdef CONFIG_SYS_POWER_MANAGEMENT
/**
 * If the kernel is in idle mode, take it out
 */
void posix_irq_check_idle_exit(void)
{
	if (_kernel.idle) {
		s32_t idle_val = _kernel.idle;

		_kernel.idle = 0;
		_sys_power_save_idle_exit(idle_val);
	}
}
#endif