kernel: fix issue with k_thread_join() timeouts

If k_thread_join() was passed with an actual timeout value,
and not K_FOREVER, the blocking thread was not being properly
woken up when the target thread exits. The timeout itself
was never aborted, causing the joining thread to remain
un-scheduled until the timeout expires.

Amend the k_thread_join() test cases to check that the join
completed before the provided timeout period expired.

Fixes: #24744

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2020-05-04 14:36:49 -07:00 committed by Andrew Boie
parent 113c814517
commit f1b5d9db8e
2 changed files with 20 additions and 0 deletions

View file

@ -542,6 +542,7 @@ void z_thread_single_abort(struct k_thread *thread)
*/
while ((waiter = z_waitq_head(&thread->base.join_waiters)) !=
NULL) {
(void)z_abort_thread_timeout(waiter);
_priq_wait_remove(&pended_on(waiter)->waitq, waiter);
z_mark_thread_as_not_pending(waiter);
waiter->base.pended_on = NULL;

View file

@ -282,6 +282,7 @@ enum control_method {
NO_WAIT,
SELF_ABORT,
OTHER_ABORT,
OTHER_ABORT_TIMEOUT,
ALREADY_EXIT,
ISR_ALREADY_EXIT,
ISR_RUNNING
@ -295,6 +296,7 @@ void join_entry(void *p1, void *p2, void *p3)
case TIMEOUT:
case NO_WAIT:
case OTHER_ABORT:
case OTHER_ABORT_TIMEOUT:
case ISR_RUNNING:
printk("join_thread: sleeping forever\n");
k_sleep(K_FOREVER);
@ -322,6 +324,8 @@ void do_join_from_isr(void *arg)
printk("isr: k_thread_join() returned with %d\n", *ret);
}
#define JOIN_TIMEOUT_MS 100
int join_scenario(enum control_method m)
{
k_timeout_t timeout = K_FOREVER;
@ -338,6 +342,9 @@ int join_scenario(enum control_method m)
/* Let join_thread run first */
k_msleep(50);
break;
case OTHER_ABORT_TIMEOUT:
timeout = K_MSEC(JOIN_TIMEOUT_MS);
/* Fall through */
case OTHER_ABORT:
printk("ztest_thread: create control_thread\n");
k_thread_create(&control_thread, control_stack, STACK_SIZE,
@ -366,12 +373,17 @@ int join_scenario(enum control_method m)
if (ret != 0) {
k_thread_abort(&join_thread);
}
if (m == OTHER_ABORT || m == OTHER_ABORT_TIMEOUT) {
k_thread_join(&control_thread, K_FOREVER);
}
return ret;
}
void test_thread_join(void)
{
s64_t interval;
#ifdef CONFIG_USERSPACE
/* scenario: thread never started */
zassert_equal(k_thread_join(&join_thread, K_FOREVER), 0,
@ -381,6 +393,13 @@ void test_thread_join(void)
zassert_equal(join_scenario(NO_WAIT), -EBUSY, "failed no-wait case");
zassert_equal(join_scenario(SELF_ABORT), 0, "failed self-abort case");
zassert_equal(join_scenario(OTHER_ABORT), 0, "failed other-abort case");
interval = k_uptime_get();
zassert_equal(join_scenario(OTHER_ABORT_TIMEOUT), 0,
"failed other-abort case with timeout");
interval = k_uptime_get() - interval;
zassert_true(interval < JOIN_TIMEOUT_MS, "join took too long (%lld ms)",
interval);
zassert_equal(join_scenario(ALREADY_EXIT), 0,
"failed already exit case");