From 7d627c59716bddab61a2300b0c8f1c4f394dfcc7 Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Wed, 30 Aug 2017 11:01:56 -0700 Subject: [PATCH] k_thread_create(): allow K_FOREVER delay It's now possible to instantiate a thread object, but delay its execution indefinitely. This was already supported with K_THREAD_DEFINE. A new API, k_thread_start(), now exists to start threads that are in this state. The intended use-case is to initialize a thread with K_USER, then grant it various access permissions, and only then start it. Signed-off-by: Andrew Boie --- include/kernel.h | 15 ++++++++++++++- kernel/thread.c | 15 +++++++++++---- .../lifecycle/lifecycle_api/src/main.c | 2 ++ .../lifecycle_api/src/test_threads_spawn.c | 19 +++++++++++++++++++ 4 files changed, 46 insertions(+), 5 deletions(-) diff --git a/include/kernel.h b/include/kernel.h index 5483c84dd96..c9a28b82cc5 100644 --- a/include/kernel.h +++ b/include/kernel.h @@ -496,7 +496,8 @@ typedef struct _k_thread_stack_element *k_thread_stack_t; * @param p3 3rd entry point parameter. * @param prio Thread priority. * @param options Thread options. - * @param delay Scheduling delay (in milliseconds), or K_NO_WAIT (for no delay). + * @param delay Scheduling delay (in milliseconds), or K_NO_WAIT (for no delay), + * or K_FOREVER (to not run until k_thread_start() is called) * * @return ID of new thread. */ @@ -626,6 +627,18 @@ extern int k_thread_cancel(k_tid_t thread); */ extern void k_thread_abort(k_tid_t thread); + +/** + * @brief Start an inactive thread + * + * If a thread was created with K_FOREVER in the delay parameter, it will + * not be added to the scheduling queue until this function is called + * on it. + * + * @param thread thread to start + */ +extern void k_thread_start(k_tid_t thread); + /** * @cond INTERNAL_HIDDEN */ diff --git a/kernel/thread.c b/kernel/thread.c index 3b4a89b9bb0..a07be883a4a 100644 --- a/kernel/thread.c +++ b/kernel/thread.c @@ -209,10 +209,15 @@ FUNC_NORETURN void _thread_entry(void (*entry)(void *, void *, void *), } #ifdef CONFIG_MULTITHREADING -static void start_thread(struct k_thread *thread) +void k_thread_start(struct k_thread *thread) { int key = irq_lock(); /* protect kernel queues */ + if (_has_thread_started(thread)) { + irq_unlock(key); + return; + } + _mark_thread_as_started(thread); if (_is_thread_ready(thread)) { @@ -232,7 +237,7 @@ static void schedule_new_thread(struct k_thread *thread, s32_t delay) { #ifdef CONFIG_SYS_CLOCK_EXISTS if (delay == 0) { - start_thread(thread); + k_thread_start(thread); } else { s32_t ticks = _TICK_ALIGN + _ms_to_ticks(delay); int key = irq_lock(); @@ -242,7 +247,7 @@ static void schedule_new_thread(struct k_thread *thread, s32_t delay) } #else ARG_UNUSED(delay); - start_thread(thread); + k_thread_start(thread); #endif } #endif @@ -260,7 +265,9 @@ k_tid_t k_thread_create(struct k_thread *new_thread, prio, options); _k_object_init(new_thread); - schedule_new_thread(new_thread, delay); + if (delay != K_FOREVER) { + schedule_new_thread(new_thread, delay); + } return new_thread; } diff --git a/tests/kernel/threads/lifecycle/lifecycle_api/src/main.c b/tests/kernel/threads/lifecycle/lifecycle_api/src/main.c index cb63dada781..843f1f3ca70 100644 --- a/tests/kernel/threads/lifecycle/lifecycle_api/src/main.c +++ b/tests/kernel/threads/lifecycle/lifecycle_api/src/main.c @@ -16,6 +16,7 @@ extern void test_threads_spawn_params(void); extern void test_threads_spawn_priority(void); extern void test_threads_spawn_delay(void); +extern void test_threads_spawn_forever(void); extern void test_threads_suspend_resume_cooperative(void); extern void test_threads_suspend_resume_preemptible(void); extern void test_threads_cancel_undelayed(void); @@ -31,6 +32,7 @@ void test_main(void) ztest_unit_test(test_threads_spawn_params), ztest_unit_test(test_threads_spawn_priority), ztest_unit_test(test_threads_spawn_delay), + ztest_unit_test(test_threads_spawn_forever), ztest_unit_test(test_threads_suspend_resume_cooperative), ztest_unit_test(test_threads_suspend_resume_preemptible), ztest_unit_test(test_threads_cancel_undelayed), diff --git a/tests/kernel/threads/lifecycle/lifecycle_api/src/test_threads_spawn.c b/tests/kernel/threads/lifecycle/lifecycle_api/src/test_threads_spawn.c index 817c418de25..ccb4c4c8d85 100644 --- a/tests/kernel/threads/lifecycle/lifecycle_api/src/test_threads_spawn.c +++ b/tests/kernel/threads/lifecycle/lifecycle_api/src/test_threads_spawn.c @@ -80,3 +80,22 @@ void test_threads_spawn_delay(void) zassert_true(tp2 == 100, NULL); k_thread_abort(tid); } + +void test_threads_spawn_forever(void) +{ + /* spawn thread with highest priority. It will run immediately once + * started. + */ + tp2 = 10; + k_tid_t tid = k_thread_create(&tdata, tstack, STACK_SIZE, + thread_entry_delay, NULL, NULL, NULL, + K_HIGHEST_THREAD_PRIO, 0, K_FOREVER); + k_yield(); + /* checkpoint: check spawn thread not execute */ + zassert_true(tp2 == 10, NULL); + /* checkpoint: check spawn thread executed */ + k_thread_start(tid); + k_yield(); + zassert_true(tp2 == 100, NULL); + k_thread_abort(tid); +}