mirror of
https://github.com/zephyrproject-rtos/zephyr
synced 2025-09-04 02:41:57 +00:00
The z_reschedule() call (as of the accompanying fix) will not swap away from a thread if called with a nested irq lock held. But for the specific case of aborting the current thread, we absolutely need to swap regardless of how many locks the thread that just aborted might have held. So call z_swap() explicitly here. This preserves the existing z_reschedule() call in other circumstances for compatibility with existing test cases, but adds a note explaining why it's there when the only obvious reason for it is already covered. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
74 lines
2.0 KiB
C
74 lines
2.0 KiB
C
/*
|
|
* Copyright (c) 2016 Wind River Systems, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* @brief Primitive for aborting a thread when an arch-specific one is not
|
|
* needed..
|
|
*/
|
|
|
|
#include <kernel.h>
|
|
#include <kernel_structs.h>
|
|
#include <kernel_internal.h>
|
|
#include <kswap.h>
|
|
#include <string.h>
|
|
#include <toolchain.h>
|
|
#include <linker/sections.h>
|
|
#include <wait_q.h>
|
|
#include <ksched.h>
|
|
#include <misc/__assert.h>
|
|
#include <syscall_handler.h>
|
|
|
|
extern void z_thread_single_abort(struct k_thread *thread);
|
|
|
|
#if !defined(CONFIG_ARCH_HAS_THREAD_ABORT)
|
|
void z_impl_k_thread_abort(k_tid_t thread)
|
|
{
|
|
/* We aren't trying to synchronize data access here (these
|
|
* APIs are internally synchronized). The original lock seems
|
|
* to have been in place to prevent the thread from waking up
|
|
* due to a delivered interrupt. Leave a dummy spinlock in
|
|
* place to do that. This API should be revisted though, it
|
|
* doesn't look SMP-safe as it stands.
|
|
*/
|
|
struct k_spinlock lock = {};
|
|
k_spinlock_key_t key = k_spin_lock(&lock);
|
|
|
|
__ASSERT((thread->base.user_options & K_ESSENTIAL) == 0U,
|
|
"essential thread aborted");
|
|
|
|
z_thread_single_abort(thread);
|
|
z_thread_monitor_exit(thread);
|
|
|
|
if (thread == _current && !z_is_in_isr()) {
|
|
z_swap(&lock, key);
|
|
} else {
|
|
/* Really, there's no good reason for this to be a
|
|
* scheduling point if we aren't aborting _current (by
|
|
* definition, no higher priority thread is runnable,
|
|
* because we're running!). But it always has been
|
|
* and is thus part of our API, and we have tests that
|
|
* rely on k_thread_abort() scheduling out of
|
|
* cooperative threads.
|
|
*/
|
|
z_reschedule(&lock, key);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
#ifdef CONFIG_USERSPACE
|
|
Z_SYSCALL_HANDLER(k_thread_abort, thread_p)
|
|
{
|
|
struct k_thread *thread = (struct k_thread *)thread_p;
|
|
Z_OOPS(Z_SYSCALL_OBJ(thread, K_OBJ_THREAD));
|
|
Z_OOPS(Z_SYSCALL_VERIFY_MSG(!(thread->base.user_options & K_ESSENTIAL),
|
|
"aborting essential thread %p", thread));
|
|
|
|
z_impl_k_thread_abort((struct k_thread *)thread);
|
|
return 0;
|
|
}
|
|
#endif
|