summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2018-11-17 20:29:18 +0100
committerRichard Braun <rbraun@sceen.net>2018-11-17 20:29:18 +0100
commit8835eb9113c3ce655b0d1040c4d6807bba6e1d82 (patch)
treee8007984f264e6395b65c6d9e971db05e4cb4506
parente0f66a3223c3abcb7d942b346b5af50978a47bc7 (diff)
kern/thread: fix suspend on dead threads
-rw-r--r--kern/thread.c38
-rw-r--r--kern/thread.h6
2 files changed, 24 insertions, 20 deletions
diff --git a/kern/thread.c b/kern/thread.c
index bd29ef84..498aae41 100644
--- a/kern/thread.c
+++ b/kern/thread.c
@@ -2634,33 +2634,35 @@ thread_suspend(struct thread *thread)
thread_preempt_disable();
runq = thread_lock_runq(thread, &flags);
- if ((thread == runq->idler) || (thread == runq->balancer)) {
+ if ((thread == runq->idler)
+ || (thread == runq->balancer)
+ || (thread->state == THREAD_DEAD)) {
error = EINVAL;
- goto done;
} else if ((thread->state == THREAD_SUSPENDED) || (thread->suspend)) {
- error = EAGAIN;
- goto done;
- }
-
- if (thread->state == THREAD_SLEEPING) {
- thread->state = THREAD_SUSPENDED;
- } else if (thread != runq->current) {
+ error = 0;
+ } else if (thread->state == THREAD_SLEEPING) {
thread->state = THREAD_SUSPENDED;
- thread_runq_remove(runq, thread);
+ error = 0;
} else {
- thread->suspend = true;
+ assert(thread->state == THREAD_RUNNING);
- if (runq == thread_runq_local()) {
- runq = thread_runq_schedule(runq);
+ if (thread != runq->current) {
+ thread->state = THREAD_SUSPENDED;
+ thread_runq_remove(runq, thread);
} else {
- thread_set_flag(thread, THREAD_YIELD);
- cpu_send_thread_schedule(thread_runq_cpu(runq));
+ thread->suspend = true;
+
+ if (runq == thread_runq_local()) {
+ runq = thread_runq_schedule(runq);
+ } else {
+ thread_set_flag(thread, THREAD_YIELD);
+ cpu_send_thread_schedule(thread_runq_cpu(runq));
+ }
}
- }
- error = 0;
+ error = 0;
+ }
-done:
thread_unlock_runq(runq, flags);
thread_preempt_enable();
diff --git a/kern/thread.h b/kern/thread.h
index 41cd6a5b..06dcad73 100644
--- a/kern/thread.h
+++ b/kern/thread.h
@@ -253,8 +253,10 @@ int thread_wakeup(struct thread *thread);
* This operation is asynchronous, i.e. the caller must not expect the target
* thread to be suspended on return.
*
- * If attempting to suspend core system threads, the request is ignored and
- * EINVAL is returned.
+ * If attempting to suspend core system threads, or threads in the dead state,
+ * or if the given thread is NULL, the request is ignored and EINVAL is
+ * returned. If the target thread is already suspended, the call turns into
+ * a no-op and merely returns success.
*/
int thread_suspend(struct thread *thread);