diff options
author | Richard Braun <rbraun@sceen.net> | 2017-03-04 15:40:44 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2017-03-04 15:40:44 +0100 |
commit | 6fecd5cef7a2f549b4d81053a3b80365ed7828f5 (patch) | |
tree | c33dd6dc6acca615c606238608109acf05bf89ec /kern | |
parent | 4d09b9e73ab6d5f2c1365736b81ab0600584c7f0 (diff) |
kern/thread: fix thread_setscheduler
Make thread_setscheduler correctly handle a transient state made possible
by the way the thread_wakeup function works.
Diffstat (limited to 'kern')
-rw-r--r-- | kern/thread.c | 15 | ||||
-rw-r--r-- | kern/thread_i.h | 3 |
2 files changed, 15 insertions, 3 deletions
diff --git a/kern/thread.c b/kern/thread.c index e2b09ff4..069881c0 100644 --- a/kern/thread.c +++ b/kern/thread.c @@ -81,6 +81,7 @@ * weights in a smoother way than a raw scaling). */ +#include <stdbool.h> #include <stddef.h> #include <string.h> @@ -455,6 +456,7 @@ thread_runq_add(struct thread_runq *runq, struct thread *thread) assert(!cpu_intr_enabled()); spinlock_assert_locked(&runq->lock); + assert(!thread->in_runq); ops = thread_get_sched_ops(thread); ops->add(runq, thread); @@ -470,6 +472,7 @@ thread_runq_add(struct thread_runq *runq, struct thread *thread) } thread->runq = runq; + thread->in_runq = true; } static void @@ -479,6 +482,7 @@ thread_runq_remove(struct thread_runq *runq, struct thread *thread) assert(!cpu_intr_enabled()); spinlock_assert_locked(&runq->lock); + assert(thread->in_runq); runq->nr_threads--; @@ -488,6 +492,8 @@ thread_runq_remove(struct thread_runq *runq, struct thread *thread) ops = thread_get_sched_ops(thread); ops->remove(runq, thread); + + thread->in_runq = false; } static void @@ -1704,6 +1710,7 @@ thread_init(struct thread *thread, void *stack, const struct thread_attr *attr, thread->nr_refs = 1; thread->flags = 0; thread->runq = NULL; + thread->in_runq = false; thread_set_wchan(thread, thread, "init"); thread->state = THREAD_SLEEPING; thread->priv_sleepq = sleepq_create(); @@ -2379,7 +2386,7 @@ thread_setscheduler(struct thread *thread, unsigned char policy, { struct thread_runq *runq; unsigned long flags; - bool current; + bool requeue, current; runq = thread_lock_runq(thread, &flags); @@ -2388,7 +2395,9 @@ thread_setscheduler(struct thread *thread, unsigned char policy, goto out; } - if (thread->state != THREAD_RUNNING) { + requeue = thread->in_runq; + + if (!requeue) { current = false; } else { if (thread != runq->current) { @@ -2410,7 +2419,7 @@ thread_setscheduler(struct thread *thread, unsigned char policy, thread_init_sched(thread, priority); } - if (thread->state == THREAD_RUNNING) { + if (requeue) { thread_runq_add(runq, thread); if (current) { diff --git a/kern/thread_i.h b/kern/thread_i.h index af278b26..55f96082 100644 --- a/kern/thread_i.h +++ b/kern/thread_i.h @@ -18,6 +18,8 @@ #ifndef _KERN_THREAD_I_H #define _KERN_THREAD_I_H +#include <stdbool.h> + #include <kern/condition_types.h> #include <kern/cpumap.h> #include <kern/list_types.h> @@ -93,6 +95,7 @@ struct thread { /* Sleep/wakeup synchronization members */ struct thread_runq *runq; + bool in_runq; const void *wchan_addr; const char *wchan_desc; unsigned short state; |