mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-11 02:13:18 +00:00
This is needed because some thread termination paths can be invoked with no guarantee that thread preemption won't happen. (It also aligns with the approach taken by the thread monitoring initialization code.) Change-Id: I28a384e051775390eb047498cb23fed22910e4df Signed-off-by: Allan Stephens <allan.stephens@windriver.com>
246 lines
5.9 KiB
C
246 lines
5.9 KiB
C
/*
|
|
* Copyright (c) 2010-2014 Wind River Systems, Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Nanokernel thread support
|
|
*
|
|
* This module provides general purpose thread support, with applies to both
|
|
* tasks or fibers.
|
|
*/
|
|
|
|
#include <toolchain.h>
|
|
#include <sections.h>
|
|
|
|
#include <nano_private.h>
|
|
#include <misc/printk.h>
|
|
#include <sys_clock.h>
|
|
#include <drivers/system_timer.h>
|
|
|
|
|
|
nano_thread_id_t sys_thread_self_get(void)
|
|
{
|
|
return _nanokernel.current;
|
|
}
|
|
|
|
nano_context_type_t sys_execution_context_type_get(void)
|
|
{
|
|
if (_IS_IN_ISR())
|
|
return NANO_CTX_ISR;
|
|
|
|
if ((_nanokernel.current->flags & TASK) == TASK)
|
|
return NANO_CTX_TASK;
|
|
|
|
return NANO_CTX_FIBER;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Mark thread as essential to system
|
|
*
|
|
* This function tags the running fiber or task as essential to system
|
|
* operation; exceptions raised by this thread will be treated as a fatal
|
|
* system error.
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void _thread_essential_set(void)
|
|
{
|
|
_nanokernel.current->flags |= ESSENTIAL;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Mark thread as not essential to system
|
|
*
|
|
* This function tags the running fiber or task as not essential to system
|
|
* operation; exceptions raised by this thread may be recoverable.
|
|
* (This is the default tag for a thread.)
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void _thread_essential_clear(void)
|
|
{
|
|
_nanokernel.current->flags &= ~ESSENTIAL;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Is the specified thread essential?
|
|
*
|
|
* This routine indicates if the running fiber or task is an essential system
|
|
* thread.
|
|
*
|
|
* @return Non-zero if current thread is essential, zero if it is not
|
|
*/
|
|
int _is_thread_essential(void)
|
|
{
|
|
return _nanokernel.current->flags & ESSENTIAL;
|
|
}
|
|
|
|
void sys_thread_busy_wait(uint32_t usec_to_wait)
|
|
{
|
|
/* use 64-bit math to prevent overflow when multiplying */
|
|
uint32_t cycles_to_wait = (uint32_t)(
|
|
(uint64_t)usec_to_wait *
|
|
(uint64_t)sys_clock_hw_cycles_per_sec /
|
|
(uint64_t)USEC_PER_SEC
|
|
);
|
|
uint32_t start_cycles = sys_cycle_get_32();
|
|
|
|
for (;;) {
|
|
uint32_t current_cycles = sys_cycle_get_32();
|
|
|
|
/* this handles the rollover on an unsigned 32-bit value */
|
|
if ((current_cycles - start_cycles) >= cycles_to_wait) {
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_THREAD_CUSTOM_DATA
|
|
|
|
/**
|
|
*
|
|
* @brief Set thread's custom data
|
|
*
|
|
* This routine sets the custom data value for the current task or fiber.
|
|
* Custom data is not used by the kernel itself, and is freely available
|
|
* for the thread to use as it sees fit.
|
|
*
|
|
* @param value New to set the thread's custom data to.
|
|
*
|
|
* @return N/A
|
|
*/
|
|
void sys_thread_custom_data_set(void *value)
|
|
{
|
|
_nanokernel.current->custom_data = value;
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @brief Get thread's custom data
|
|
*
|
|
* This function returns the custom data value for the current task or fiber.
|
|
*
|
|
* @return current handle value
|
|
*/
|
|
void *sys_thread_custom_data_get(void)
|
|
{
|
|
return _nanokernel.current->custom_data;
|
|
}
|
|
|
|
#endif /* CONFIG_THREAD_CUSTOM_DATA */
|
|
|
|
#if defined(CONFIG_THREAD_MONITOR)
|
|
/*
|
|
* Remove a thread from the kernel's list of active threads.
|
|
*/
|
|
void _thread_monitor_exit(struct tcs *thread)
|
|
{
|
|
unsigned int key = irq_lock();
|
|
|
|
if (thread == _nanokernel.threads) {
|
|
_nanokernel.threads = _nanokernel.threads->next_thread;
|
|
} else {
|
|
struct tcs *prev_thread;
|
|
|
|
prev_thread = _nanokernel.threads;
|
|
while (thread != prev_thread->next_thread) {
|
|
prev_thread = prev_thread->next_thread;
|
|
}
|
|
prev_thread->next_thread = thread->next_thread;
|
|
}
|
|
|
|
irq_unlock(key);
|
|
}
|
|
#endif /* CONFIG_THREAD_MONITOR */
|
|
|
|
/**
|
|
*
|
|
* @brief Common thread entry point function
|
|
*
|
|
* This function serves as the entry point for _all_ threads, i.e. both
|
|
* task and fibers are instantiated such that initial execution starts
|
|
* here.
|
|
*
|
|
* This routine invokes the actual task or fiber entry point function and
|
|
* passes it three arguments. It also handles graceful termination of the
|
|
* task or fiber if the entry point function ever returns.
|
|
*
|
|
* @param pEntry address of the app entry point function
|
|
* @param parameter1 1st arg to the app entry point function
|
|
* @param parameter2 2nd arg to the app entry point function
|
|
* @param parameter3 3rd arg to the app entry point function
|
|
*
|
|
* @internal
|
|
* The 'noreturn' attribute is applied to this function so that the compiler
|
|
* can dispense with generating the usual preamble that is only required for
|
|
* functions that actually return.
|
|
*
|
|
* @return Does not return
|
|
*
|
|
*/
|
|
FUNC_NORETURN void _thread_entry(_thread_entry_t pEntry,
|
|
_thread_arg_t parameter1,
|
|
_thread_arg_t parameter2,
|
|
_thread_arg_t parameter3)
|
|
{
|
|
/* Execute the "application" entry point function */
|
|
|
|
pEntry(parameter1, parameter2, parameter3);
|
|
|
|
/* Determine if thread can legally terminate itself via "return" */
|
|
|
|
if (_is_thread_essential()) {
|
|
#ifdef CONFIG_NANOKERNEL
|
|
/*
|
|
* Nanokernel's background task must always be present,
|
|
* so if it has nothing left to do just let it idle forever
|
|
*/
|
|
|
|
while (((_nanokernel.current)->flags & TASK) == TASK) {
|
|
nano_cpu_idle();
|
|
}
|
|
#endif /* CONFIG_NANOKERNEL */
|
|
|
|
/* Loss of essential thread is a system fatal error */
|
|
|
|
_NanoFatalErrorHandler(_NANO_ERR_INVALID_TASK_EXIT,
|
|
&_default_esf);
|
|
}
|
|
|
|
/* Gracefully terminate the currently executing thread */
|
|
|
|
#ifdef CONFIG_MICROKERNEL
|
|
if (((_nanokernel.current)->flags & TASK) == TASK) {
|
|
extern FUNC_NORETURN void _TaskAbort(void);
|
|
_TaskAbort();
|
|
} else
|
|
#endif /* CONFIG_MICROKERNEL */
|
|
{
|
|
fiber_abort();
|
|
}
|
|
|
|
/*
|
|
* Compiler can't tell that fiber_abort() won't return and issues
|
|
* a warning unless we explicitly tell it that control never gets this
|
|
* far.
|
|
*/
|
|
|
|
CODE_UNREACHABLE;
|
|
}
|