kernel: Add alternative _arch_switch context switch primitive
The existing __swap() mechanism is too high level for some applications because of its scheduler-awareness. This introduces a new _arch_switch() mechanism, which is a simpler primitive that looks like: void _arch_switch(void *handle, void **old_handle_out); The new thread handle (typically just a stack pointer) is specified explicitly instead of being picked up from the scheduler by per-architecture code, and on return the "old" thread handle that got switched out is returned through the pointer. The new primitive (currently available only on xtensa) is selected when CONFIG_USE_SWITCH is "y". A new C _Swap() implementation based on this primitive is then added which operates compatibly. Signed-off-by: Andy Ross <andrew.j.ross@intel.com>
This commit is contained in:
parent
8ac9c082e6
commit
042d8ecca9
4 changed files with 69 additions and 9 deletions
|
@ -54,6 +54,10 @@ typedef struct _kernel_arch _kernel_arch_t;
|
|||
|
||||
#endif /*! _ASMLANGUAGE && ! __ASSEMBLER__ */
|
||||
|
||||
#ifdef CONFIG_USE_SWITCH
|
||||
void xtensa_switch(void *switch_to, void **switched_from);
|
||||
#define _arch_switch xtensa_switch
|
||||
#endif
|
||||
|
||||
/* stacks */
|
||||
#define STACK_ROUND_UP(x) ROUND_UP(x, STACK_ALIGN_SIZE)
|
||||
|
|
|
@ -469,6 +469,18 @@ struct k_thread {
|
|||
k_thread_stack_t *stack_obj;
|
||||
#endif /* CONFIG_USERSPACE */
|
||||
|
||||
#if defined(CONFIG_USE_SWITCH)
|
||||
/* When using __switch() a few previously arch-specific items
|
||||
* become part of the core OS
|
||||
*/
|
||||
|
||||
/* _Swap() return value */
|
||||
int swap_retval;
|
||||
|
||||
/* Context handle returned via _arch_switch() */
|
||||
void *switch_handle;
|
||||
#endif
|
||||
|
||||
/* arch-specifics: must always be at the end */
|
||||
struct _thread_arch arch;
|
||||
};
|
||||
|
|
|
@ -549,6 +549,18 @@ config MAX_DOMAIN_PARTITIONS
|
|||
help
|
||||
Configure the maximum number of partitions per memory domain.
|
||||
|
||||
config USE_SWITCH
|
||||
bool
|
||||
prompt "Use new-style _arch_switch instead of __swap"
|
||||
default n
|
||||
help
|
||||
The _arch_switch() API is a lower level context switching
|
||||
primitive than the original __swap mechanism. It is required
|
||||
for an SMP-aware scheduler, or if the architecture does not
|
||||
provide __swap. In uniprocess situations where the
|
||||
architecture provides both, _arch_switch incurs more somewhat
|
||||
overhead and may be slower.
|
||||
|
||||
source "kernel/Kconfig.event_logger"
|
||||
|
||||
source "kernel/Kconfig.power_mgmt"
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
#include <kernel.h>
|
||||
#include <kernel_structs.h>
|
||||
#include <ksched.h>
|
||||
|
||||
#ifndef _ASMLANGUAGE
|
||||
|
||||
|
@ -51,30 +52,61 @@ extern void _setup_new_thread(struct k_thread *new_thread,
|
|||
void *p1, void *p2, void *p3,
|
||||
int prio, u32_t options);
|
||||
|
||||
/* context switching and scheduling-related routines */
|
||||
|
||||
extern unsigned int __swap(unsigned int key);
|
||||
|
||||
#ifdef CONFIG_TIMESLICING
|
||||
extern void _update_time_slice_before_swap(void);
|
||||
#else
|
||||
#define _update_time_slice_before_swap() /**/
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_STACK_SENTINEL
|
||||
extern void _check_stack_sentinel(void);
|
||||
#else
|
||||
#define _check_stack_sentinel() /**/
|
||||
#endif
|
||||
|
||||
/* context switching and scheduling-related routines */
|
||||
#ifdef CONFIG_USE_SWITCH
|
||||
|
||||
/* New style context switching. _arch_switch() is a lower level
|
||||
* primitive that doesn't know about the scheduler or return value.
|
||||
* Needed for SMP, where the scheduler requires spinlocking that we
|
||||
* don't want to have to do in per-architecture assembly.
|
||||
*/
|
||||
static inline unsigned int _Swap(unsigned int key)
|
||||
{
|
||||
struct k_thread *new_thread, *old_thread;
|
||||
|
||||
old_thread = _kernel.current;
|
||||
|
||||
_check_stack_sentinel();
|
||||
_update_time_slice_before_swap();
|
||||
|
||||
new_thread = _get_next_ready_thread();
|
||||
|
||||
old_thread->swap_retval = -EAGAIN;
|
||||
|
||||
_kernel.current = new_thread;
|
||||
_arch_switch(new_thread->switch_handle,
|
||||
&old_thread->switch_handle);
|
||||
|
||||
irq_unlock(key);
|
||||
|
||||
return _kernel.current->swap_retval;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_USE_SWITCH */
|
||||
|
||||
extern unsigned int __swap(unsigned int key);
|
||||
|
||||
static inline unsigned int _Swap(unsigned int key)
|
||||
{
|
||||
|
||||
#ifdef CONFIG_STACK_SENTINEL
|
||||
_check_stack_sentinel();
|
||||
#endif
|
||||
#ifdef CONFIG_TIMESLICING
|
||||
_update_time_slice_before_swap();
|
||||
#endif
|
||||
|
||||
return __swap(key);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_USERSPACE
|
||||
/**
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue