diff --git a/headers/private/kernel/thread.h b/headers/private/kernel/thread.h index e7ceb5adc2..bd35d34fb6 100644 --- a/headers/private/kernel/thread.h +++ b/headers/private/kernel/thread.h @@ -34,7 +34,7 @@ void thread_reset_for_exec(void); status_t thread_init(struct kernel_args *args); status_t thread_preboot_init_percpu(struct kernel_args *args, int32 cpuNum); -void thread_yield(void); +void thread_yield(bool force); void thread_exit(void); int32 thread_max_threads(void); diff --git a/src/system/kernel/thread.cpp b/src/system/kernel/thread.cpp index 83433b4e69..c8f6b86ebe 100644 --- a/src/system/kernel/thread.cpp +++ b/src/system/kernel/thread.cpp @@ -1622,29 +1622,45 @@ peek_next_thread_id(void) } +/*! Yield the CPU to other threads. + If \a force is \c true, the thread will almost guaranteedly be unscheduled. + If \c false, it will continue to run, if there's no other thread in ready + state, and if it has a higher priority than the other ready threads, it + still has a good chance to continue. +*/ void -thread_yield(void) +thread_yield(bool force) { - // snooze for roughly 3 thread quantums - snooze_etc(9000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); + if (force) { + // snooze for roughly 3 thread quantums + snooze_etc(9000, B_SYSTEM_TIMEBASE, B_RELATIVE_TIMEOUT | B_CAN_INTERRUPT); #if 0 - cpu_status state; + cpu_status state; - struct thread *thread = thread_get_current_thread(); - if (thread == NULL) - return; + struct thread *thread = thread_get_current_thread(); + if (thread == NULL) + return; - state = disable_interrupts(); - GRAB_THREAD_LOCK(); + state = disable_interrupts(); + GRAB_THREAD_LOCK(); - // mark the thread as yielded, so it will not be scheduled next - //thread->was_yielded = true; - thread->next_priority = B_LOWEST_ACTIVE_PRIORITY; - scheduler_reschedule(); + // mark the thread as yielded, so it will not be scheduled next + //thread->was_yielded = true; + thread->next_priority = B_LOWEST_ACTIVE_PRIORITY; + scheduler_reschedule(); - RELEASE_THREAD_LOCK(); - restore_interrupts(state); + RELEASE_THREAD_LOCK(); + restore_interrupts(state); #endif + } else { + struct thread *thread = thread_get_current_thread(); + if (thread == NULL) + return; + + // Don't force the thread off the CPU, just reschedule. + InterruptsSpinLocker _(thread_spinlock); + scheduler_reschedule(); + } } @@ -2463,7 +2479,7 @@ _user_snooze_etc(bigtime_t timeout, int timebase, uint32 flags) void _user_thread_yield(void) { - thread_yield(); + thread_yield(true); } diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp index f104c5e2fc..666cdb2c16 100644 --- a/src/system/kernel/vm/vm.cpp +++ b/src/system/kernel/vm/vm.cpp @@ -718,7 +718,7 @@ MultiAddressSpaceLocker::AddAreaCacheAndLock(area_id areaID, memcpy(fItems, originalItems, fCount * sizeof(lock_item)); if (yield) - thread_yield(); + thread_yield(true); } } @@ -3941,7 +3941,7 @@ fault_find_page(vm_translation_map *map, vm_cache *topCache, // with his only consumer (cacheRef); since its pages are moved // upwards, too, we try this cache again mutex_unlock(&cache->lock); - thread_yield(); + thread_yield(true); mutex_lock(&cache->lock); if (cache->busy) { // The cache became busy, which means, it is about to be diff --git a/src/system/kernel/vm/vm_page.cpp b/src/system/kernel/vm/vm_page.cpp index adc9b8c156..4539f83869 100644 --- a/src/system/kernel/vm/vm_page.cpp +++ b/src/system/kernel/vm/vm_page.cpp @@ -959,7 +959,7 @@ page_writer(void* /*unused*/) if (cache->store->ops->acquire_unreferenced_ref(cache->store) != B_OK) { cacheLocker.Unlock(); - thread_yield(); + thread_yield(true); continue; } }