summaryrefslogtreecommitdiff
path: root/kern
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2017-03-04 15:40:44 +0100
committerRichard Braun <rbraun@sceen.net>2017-03-04 15:40:44 +0100
commit6fecd5cef7a2f549b4d81053a3b80365ed7828f5 (patch)
treec33dd6dc6acca615c606238608109acf05bf89ec /kern
parent4d09b9e73ab6d5f2c1365736b81ab0600584c7f0 (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.c15
-rw-r--r--kern/thread_i.h3
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;