From eb117b4bfd8d52824a07804854c2412c9cef90cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Tue, 6 Feb 2007 02:29:17 +0000 Subject: [PATCH] Reworked the way thread_yield() works: just setting the thread to B_LOWEST_ACTIVE_PRIORITY for one quantum wasn't really a good idea, as this could get quite expensive for the thread (depending on the system load, it might have taken a long time until the thread was scheduled again, no matter what priority it was). Also, calling thread_yield() in a loop would have taken 100% CPU time. Now, we sort the thread into the queue as with any other thread, but we'll ignore it once. This now guarantees an actual context switch, as well as a much fairer rescheduling policy for threads calling that function. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@20077 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/thread_types.h | 1 + src/system/kernel/scheduler.cpp | 10 +++++++++- src/system/kernel/thread.c | 11 ++++++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index 095e411dbb..5aac26716b 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -142,6 +142,7 @@ struct thread { struct sigaction sig_action[32]; bool in_kernel; + bool was_yielded; struct { sem_id blocking; diff --git a/src/system/kernel/scheduler.cpp b/src/system/kernel/scheduler.cpp index 893c2974fa..cda511151b 100644 --- a/src/system/kernel/scheduler.cpp +++ b/src/system/kernel/scheduler.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. * Copyright 2002, Angelo Mottola, a.mottola@libero.it. * Distributed under the terms of the MIT License. * @@ -189,6 +189,13 @@ scheduler_reschedule(void) } else { // select next thread from the run queue while (nextThread && nextThread->priority > B_IDLE_PRIORITY) { + if (oldThread == nextThread && nextThread->was_yielded) { + // ignore threads that called thread_yield() once + nextThread->was_yielded = false; + prevThread = nextThread; + nextThread = nextThread->queue_next; + } + // always extract real time threads if (nextThread->priority >= B_FIRST_REAL_TIME_PRIORITY) break; @@ -222,6 +229,7 @@ scheduler_reschedule(void) nextThread->state = B_THREAD_RUNNING; nextThread->next_state = B_THREAD_READY; + oldThread->was_yielded = false; // track kernel time (user time is tracked in thread_at_kernel_entry()) bigtime_t now = system_time(); diff --git a/src/system/kernel/thread.c b/src/system/kernel/thread.c index 2f401a0c45..8bf780edbe 100644 --- a/src/system/kernel/thread.c +++ b/src/system/kernel/thread.c @@ -214,6 +214,7 @@ create_thread_struct(const char *name, thread_id threadID) thread->sig_block_mask = 0; memset(thread->sig_action, 0, 32 * sizeof(struct sigaction)); thread->in_kernel = true; + thread->was_yielded = false; thread->user_time = 0; thread->kernel_time = 0; thread->last_time = 0; @@ -915,13 +916,13 @@ thread_exit(void) struct thread_debug_info debugInfo; team_id teamID = team->id; - if (!are_interrupts_enabled()) - dprintf("thread_exit() called with interrupts disabled!\n"); - TRACE(("thread 0x%lx exiting %s w/return code 0x%x\n", thread->id, thread->exit.reason == THREAD_RETURN_INTERRUPTED ? "due to signal" : "normally", (int)thread->exit.status)); + if (!are_interrupts_enabled()) + panic("thread_exit() called with interrupts disabled!\n"); + // boost our priority to get this over with thread->priority = thread->next_priority = B_URGENT_DISPLAY_PRIORITY; @@ -1298,8 +1299,8 @@ thread_yield(void) state = disable_interrupts(); GRAB_THREAD_LOCK(); - // just add the thread at the end of the run queue - thread->next_priority = B_LOWEST_ACTIVE_PRIORITY; + // mark the thread as yielded, so it will not be scheduled next + thread->was_yielded = true; scheduler_reschedule(); RELEASE_THREAD_LOCK();