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
|
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
|
pointer to such a handle into which it should store the handle
|
||||||
resulting from the thread that is being switched out.
|
resulting from the thread that is being switched out.
|
||||||
|
|
||||||
The kernel then implements a portable :c:func:`z_swap` implementation on top
|
The kernel then implements a portable :c:func:`z_swap` implementation on top
|
||||||
of this primitive which includes the relevant scheduler logic in a
|
of this primitive which includes the relevant scheduler logic in a
|
||||||
location where the architecture doesn't need to understand it.
|
location where the architecture doesn't need to understand it.
|
||||||
|
|
||||||
Similarly, on interrupt exit, switch-based architectures are expected
|
Similarly, on interrupt exit, switch-based architectures are expected
|
||||||
to call :c:func:`z_get_next_switch_handle` to retrieve the next thread to
|
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
|
run from the scheduler. The argument to :c:func:`z_get_next_switch_handle`
|
||||||
the same opaque type used by switch, which the kernel will then save
|
is either the interrupted thread's "handle" reflecting the same opaque type
|
||||||
in the interrupted thread struct.
|
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
|
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
|
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;
|
_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)
|
void *z_get_next_switch_handle(void *interrupted)
|
||||||
{
|
{
|
||||||
z_check_stack_sentinel();
|
z_check_stack_sentinel();
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue