Implement yielding a timeslice to another thread.

This commit is contained in:
Jonas 'Sortie' Termansen 2014-10-02 15:38:06 +02:00
parent 78d9620b0f
commit 4c78239721
4 changed files with 66 additions and 12 deletions

View File

@ -67,6 +67,7 @@ void SaveInterruptedContext(const struct interrupt_context* intctx,
struct thread_registers* registers);
void LoadInterruptedContext(struct interrupt_context* intctx,
const struct thread_registers* registers);
void ScheduleTrueThread();
} // namespace Scheduler
} // namespace Sortix

View File

@ -25,6 +25,8 @@
#ifndef INCLUDE_SORTIX_KERNEL_THREAD_H
#define INCLUDE_SORTIX_KERNEL_THREAD_H
#include <stdint.h>
#include <sortix/sigaction.h>
#include <sortix/signal.h>
#include <sortix/sigset.h>
@ -65,6 +67,8 @@ public:
~Thread();
public:
uintptr_t system_tid;
uintptr_t yield_to_tid;
struct thread_registers registers;
uint8_t* self_allocation;
size_t id;

View File

@ -193,23 +193,51 @@ void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next)
static Thread* idle_thread;
static Thread* first_runnable_thread;
static Thread* true_current_thread;
static Process* init_process;
static Thread* PopNextThread()
static Thread* FindRunnableThreadWithSystemTid(uintptr_t system_tid)
{
if ( first_runnable_thread )
Thread* begun_thread = current_thread;
Thread* iter = begun_thread;
do
{
Thread* result = first_runnable_thread;
first_runnable_thread = first_runnable_thread->scheduler_list_next;
return result;
}
return idle_thread;
if ( iter->system_tid == system_tid )
return iter;
iter = iter->scheduler_list_next;
} while ( iter != begun_thread );
return NULL;
}
void Switch(struct interrupt_context* intctx)
static Thread* PopNextThread(bool yielded)
{
SwitchThread(intctx, CurrentThread(), PopNextThread());
Thread* result;
uintptr_t yield_to_tid = current_thread->yield_to_tid;
if ( yielded && yield_to_tid != 0 )
{
if ( (result = FindRunnableThreadWithSystemTid(yield_to_tid)) )
return result;
}
if ( first_runnable_thread )
{
result = first_runnable_thread;
first_runnable_thread = first_runnable_thread->scheduler_list_next;
}
else
{
result = idle_thread;
}
true_current_thread = result;
return result;
}
static void RealSwitch(struct interrupt_context* intctx, bool yielded)
{
SwitchThread(intctx, CurrentThread(), PopNextThread(yielded));
if ( intctx->signal_pending && InUserspace(intctx) )
{
@ -218,15 +246,20 @@ void Switch(struct interrupt_context* intctx)
}
}
void Switch(struct interrupt_context* intctx)
{
RealSwitch(intctx, false);
}
void InterruptYieldCPU(struct interrupt_context* intctx, void* /*user*/)
{
Switch(intctx);
RealSwitch(intctx, true);
}
void ThreadExitCPU(struct interrupt_context* intctx, void* /*user*/)
{
SetThreadState(current_thread, ThreadState::DEAD);
InterruptYieldCPU(intctx, NULL);
RealSwitch(intctx, false);
}
// The idle thread serves no purpose except being an infinite loop that does
@ -237,6 +270,7 @@ void SetIdleThread(Thread* thread)
idle_thread = thread;
SetThreadState(thread, ThreadState::NONE);
current_thread = thread;
true_current_thread = thread;
}
void SetInitProcess(Process* init)
@ -304,9 +338,22 @@ static int sys_sched_yield(void)
return kthread_yield(), 0;
}
void ScheduleTrueThread()
{
bool wasenabled = Interrupt::SetEnabled(false);
if ( true_current_thread != current_thread )
{
current_thread->yield_to_tid = 0;
first_runnable_thread = true_current_thread;
kthread_yield();
}
Interrupt::SetEnabled(wasenabled);
}
void Init()
{
first_runnable_thread = NULL;
true_current_thread = NULL;
idle_thread = NULL;
Syscall::Register(SYSCALL_SCHED_YIELD, (void*) sys_sched_yield);

View File

@ -78,6 +78,8 @@ void FreeThread(Thread* thread)
Thread::Thread()
{
assert(!((uintptr_t) registers.fpuenv & 0xFUL));
system_tid = (uintptr_t) this;
yield_to_tid = 0;
id = 0; // TODO: Make a thread id.
process = NULL;
prevsibling = NULL;