Skip to content

Commit 457b9fb

Browse files
andyrosscfriedt
authored andcommitted
kernel/sched: Fix SMP must-wait-for-switch conditions in abort/join
As discovered by Carlo Caione, the k_thread_join code had a case where it detected it had been called on a thread already marked _THREAD_DEAD and exited early. That's not sufficient. The thread state is mutated from the thread itself on its exit path. It may still be running! Just like the code in z_swap(), we need to spin waiting on the other CPU to write the switch handle before knowing it's safe to return, otherwise the calling context might (and did) do something like immediately k_thread_create() a new thread in the "dead" thread's struct while it was still running on the other core. There was also a similar case in k_thread_abort() which had the same issue: it needs to spin waiting on the other CPU to kill the thread via the same mechanism. Fixes #58116 Originally-by: Carlo Caione <[email protected]> Signed-off-by: Andy Ross <[email protected]> (cherry picked from commit a08e23f)
1 parent 8307b30 commit 457b9fb

File tree

1 file changed

+8
-0
lines changed

1 file changed

+8
-0
lines changed

kernel/sched.c

+8
Original file line numberDiff line numberDiff line change
@@ -1584,6 +1584,13 @@ void z_thread_abort(struct k_thread *thread)
15841584
k_spin_unlock(&sched_spinlock, key);
15851585
while (is_aborting(thread)) {
15861586
}
1587+
1588+
/* Now we know it's dying, but not necessarily
1589+
* dead. Wait for the switch to happen!
1590+
*/
1591+
key = k_spin_lock(&sched_spinlock);
1592+
z_sched_switch_spin(thread);
1593+
k_spin_unlock(&sched_spinlock, key);
15871594
} else if (active) {
15881595
/* Threads can join */
15891596
add_to_waitq_locked(_current, &thread->join_queue);
@@ -1619,6 +1626,7 @@ int z_impl_k_thread_join(struct k_thread *thread, k_timeout_t timeout)
16191626
SYS_PORT_TRACING_OBJ_FUNC_ENTER(k_thread, join, thread, timeout);
16201627

16211628
if ((thread->base.thread_state & _THREAD_DEAD) != 0U) {
1629+
z_sched_switch_spin(thread);
16221630
ret = 0;
16231631
} else if (K_TIMEOUT_EQ(timeout, K_NO_WAIT)) {
16241632
ret = -EBUSY;

0 commit comments

Comments
 (0)