| /* |
| * 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" |
| #include "kswap.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 |
| * z_set_thread_return_value() |
| * |
| */ |
| |
| 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 z_set_thread_return_value() */ |
| |
| 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 z_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; |
| |
| z_sys_trace_thread_switched_out(); |
| |
| _kernel.current = _kernel.ready_q.cache; |
| |
| z_sys_trace_thread_switched_in(); |
| |
| 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; |
| z_sys_power_save_idle_exit(idle_val); |
| } |
| } |
| #endif |