sched: formalize the passing of NULL to z_get_next_switch_handle()
This is an attempt at formally distinguishing and supporting the case described in 40795 where an architecture doesn't preserve/restore the complete thread state upon entering/exiting interrupt exception state. This is mainly about promoting the current behavior from the accepted workaround to a formal API specification. This workaround is currently used on ARM64 but RISC-V requires it too. Signed-off-by: Nicolas Pitre <npitre@baylibre.com>
This commit is contained in:
parent
f483b1bc4c
commit
c9e3e0d956
2 changed files with 53 additions and 4 deletions
|
@ -283,15 +283,33 @@ exactly two arguments. The first is an opaque (architecture defined)
|
|||
handle to the context to which it should switch, and the second is a
|
||||
pointer to such a handle into which it should store the handle
|
||||
resulting from the thread that is being switched out.
|
||||
|
||||
The kernel then implements a portable :c:func:`z_swap` implementation on top
|
||||
of this primitive which includes the relevant scheduler logic in a
|
||||
location where the architecture doesn't need to understand it.
|
||||
|
||||
Similarly, on interrupt exit, switch-based architectures are expected
|
||||
to call :c:func:`z_get_next_switch_handle` to retrieve the next thread to
|
||||
run from the scheduler, passing in an "interrupted" handle reflecting
|
||||
the same opaque type used by switch, which the kernel will then save
|
||||
in the interrupted thread struct.
|
||||
run from the scheduler. The argument to :c:func:`z_get_next_switch_handle`
|
||||
is either the interrupted thread's "handle" reflecting the same opaque type
|
||||
used by :c:func:`arch_switch`, or NULL if that thread cannot be released
|
||||
to the scheduler just yet. The choice between a handle value or NULL
|
||||
depends on the way CPU interrupt mode is implemented.
|
||||
|
||||
Architectures with a large CPU register file would typically preserve only
|
||||
the caller-saved registers on the current thread's stack when interrupted
|
||||
in order to minimize interrupt latency, and preserve the callee-saved
|
||||
registers only when :c:func:`arch_switch` is called to minimize context
|
||||
switching latency. Such architectures must use NULL as the argument to
|
||||
:c:func:`z_get_next_switch_handle` to determine if there is a new thread
|
||||
to schedule, and follow through with their own :c:func:`arch_switch` or
|
||||
derrivative if so, or directly leave interrupt mode otherwise.
|
||||
In the former case it is up to that switch code to store the handle
|
||||
resulting from the thread that is being switched out in that thread's
|
||||
"switch_handle" field after its context has fully been saved.
|
||||
|
||||
Architectures whose entry in interrupt mode already preserves the entire
|
||||
thread state may pass that thread's handle directly to
|
||||
:c:func:`z_get_next_switch_handle` and be done in one step.
|
||||
|
||||
Note that while SMP requires :kconfig:option:`CONFIG_USE_SWITCH`, the reverse is not
|
||||
true. A uniprocessor architecture built with :kconfig:option:`CONFIG_SMP` set to No might
|
||||
|
|
|
@ -984,6 +984,37 @@ static inline void set_current(struct k_thread *new_thread)
|
|||
_current_cpu->current = new_thread;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Determine next thread to execute upon completion of an interrupt
|
||||
*
|
||||
* Thread preemption is performed by context switching after the completion
|
||||
* of a non-recursed interrupt. This function determines which thread to
|
||||
* switch to if any. This function accepts as @p interrupted either:
|
||||
*
|
||||
* - The handle for the interrupted thread in which case the thread's context
|
||||
* must already be fully saved and ready to be picked up by a different CPU.
|
||||
*
|
||||
* - NULL if more work is required to fully save the thread's state after
|
||||
* it is known that a new thread is to be scheduled. It is up to the caller
|
||||
* to store the handle resulting from the thread that is being switched out
|
||||
* in that thread's "switch_handle" field after its
|
||||
* context has fully been saved, following the same requirements as with
|
||||
* the @ref arch_switch() function.
|
||||
*
|
||||
* If a new thread needs to be scheduled then its handle is returned.
|
||||
* Otherwise the same value provided as @p interrupted is returned back.
|
||||
* Those handles are the same opaque types used by the @ref arch_switch()
|
||||
* function.
|
||||
*
|
||||
* @warning
|
||||
* The @ref _current value may have changed after this call and not refer
|
||||
* to the interrupted thread anymore. It might be necessary to make a local
|
||||
* copy before calling this function.
|
||||
*
|
||||
* @param interrupted Handle for the thread that was interrupted or NULL.
|
||||
* @retval Handle for the next thread to execute, or @p interrupted when
|
||||
* no new thread is to be scheduled.
|
||||
*/
|
||||
void *z_get_next_switch_handle(void *interrupted)
|
||||
{
|
||||
z_check_stack_sentinel();
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue