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 <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2017-08-30 11:01:56 -07:00 committed by Andrew Boie
commit 7d627c5971
4 changed files with 46 additions and 5 deletions

View file

@ -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
*/

View file

@ -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;
}

View file

@ -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),

View file

@ -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);
}