diff options
author | Richard Braun <rbraun@sceen.net> | 2018-11-17 20:29:18 +0100 |
---|---|---|
committer | Richard Braun <rbraun@sceen.net> | 2018-11-17 20:29:18 +0100 |
commit | 8835eb9113c3ce655b0d1040c4d6807bba6e1d82 (patch) | |
tree | e8007984f264e6395b65c6d9e971db05e4cb4506 | |
parent | e0f66a3223c3abcb7d942b346b5af50978a47bc7 (diff) |
kern/thread: fix suspend on dead threads
-rw-r--r-- | kern/thread.c | 38 | ||||
-rw-r--r-- | kern/thread.h | 6 |
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); |