mirror of
https://gitlab.com/sortix/sortix.git
synced 2023-02-13 20:55:38 -05:00
Implement yielding a timeslice to another thread.
This commit is contained in:
parent
78d9620b0f
commit
4c78239721
4 changed files with 66 additions and 12 deletions
|
@ -67,6 +67,7 @@ void SaveInterruptedContext(const struct interrupt_context* intctx,
|
||||||
struct thread_registers* registers);
|
struct thread_registers* registers);
|
||||||
void LoadInterruptedContext(struct interrupt_context* intctx,
|
void LoadInterruptedContext(struct interrupt_context* intctx,
|
||||||
const struct thread_registers* registers);
|
const struct thread_registers* registers);
|
||||||
|
void ScheduleTrueThread();
|
||||||
|
|
||||||
} // namespace Scheduler
|
} // namespace Scheduler
|
||||||
} // namespace Sortix
|
} // namespace Sortix
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#ifndef INCLUDE_SORTIX_KERNEL_THREAD_H
|
#ifndef INCLUDE_SORTIX_KERNEL_THREAD_H
|
||||||
#define INCLUDE_SORTIX_KERNEL_THREAD_H
|
#define INCLUDE_SORTIX_KERNEL_THREAD_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
#include <sortix/sigaction.h>
|
#include <sortix/sigaction.h>
|
||||||
#include <sortix/signal.h>
|
#include <sortix/signal.h>
|
||||||
#include <sortix/sigset.h>
|
#include <sortix/sigset.h>
|
||||||
|
@ -65,6 +67,8 @@ public:
|
||||||
~Thread();
|
~Thread();
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
uintptr_t system_tid;
|
||||||
|
uintptr_t yield_to_tid;
|
||||||
struct thread_registers registers;
|
struct thread_registers registers;
|
||||||
uint8_t* self_allocation;
|
uint8_t* self_allocation;
|
||||||
size_t id;
|
size_t id;
|
||||||
|
|
|
@ -193,23 +193,51 @@ void SwitchThread(struct interrupt_context* intctx, Thread* prev, Thread* next)
|
||||||
|
|
||||||
static Thread* idle_thread;
|
static Thread* idle_thread;
|
||||||
static Thread* first_runnable_thread;
|
static Thread* first_runnable_thread;
|
||||||
|
static Thread* true_current_thread;
|
||||||
static Process* init_process;
|
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;
|
if ( iter->system_tid == system_tid )
|
||||||
first_runnable_thread = first_runnable_thread->scheduler_list_next;
|
return iter;
|
||||||
return result;
|
iter = iter->scheduler_list_next;
|
||||||
}
|
} while ( iter != begun_thread );
|
||||||
|
return NULL;
|
||||||
return idle_thread;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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) )
|
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*/)
|
void InterruptYieldCPU(struct interrupt_context* intctx, void* /*user*/)
|
||||||
{
|
{
|
||||||
Switch(intctx);
|
RealSwitch(intctx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadExitCPU(struct interrupt_context* intctx, void* /*user*/)
|
void ThreadExitCPU(struct interrupt_context* intctx, void* /*user*/)
|
||||||
{
|
{
|
||||||
SetThreadState(current_thread, ThreadState::DEAD);
|
SetThreadState(current_thread, ThreadState::DEAD);
|
||||||
InterruptYieldCPU(intctx, NULL);
|
RealSwitch(intctx, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// The idle thread serves no purpose except being an infinite loop that does
|
// The idle thread serves no purpose except being an infinite loop that does
|
||||||
|
@ -237,6 +270,7 @@ void SetIdleThread(Thread* thread)
|
||||||
idle_thread = thread;
|
idle_thread = thread;
|
||||||
SetThreadState(thread, ThreadState::NONE);
|
SetThreadState(thread, ThreadState::NONE);
|
||||||
current_thread = thread;
|
current_thread = thread;
|
||||||
|
true_current_thread = thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetInitProcess(Process* init)
|
void SetInitProcess(Process* init)
|
||||||
|
@ -304,9 +338,22 @@ static int sys_sched_yield(void)
|
||||||
return kthread_yield(), 0;
|
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()
|
void Init()
|
||||||
{
|
{
|
||||||
first_runnable_thread = NULL;
|
first_runnable_thread = NULL;
|
||||||
|
true_current_thread = NULL;
|
||||||
idle_thread = NULL;
|
idle_thread = NULL;
|
||||||
|
|
||||||
Syscall::Register(SYSCALL_SCHED_YIELD, (void*) sys_sched_yield);
|
Syscall::Register(SYSCALL_SCHED_YIELD, (void*) sys_sched_yield);
|
||||||
|
|
|
@ -78,6 +78,8 @@ void FreeThread(Thread* thread)
|
||||||
Thread::Thread()
|
Thread::Thread()
|
||||||
{
|
{
|
||||||
assert(!((uintptr_t) registers.fpuenv & 0xFUL));
|
assert(!((uintptr_t) registers.fpuenv & 0xFUL));
|
||||||
|
system_tid = (uintptr_t) this;
|
||||||
|
yield_to_tid = 0;
|
||||||
id = 0; // TODO: Make a thread id.
|
id = 0; // TODO: Make a thread id.
|
||||||
process = NULL;
|
process = NULL;
|
||||||
prevsibling = NULL;
|
prevsibling = NULL;
|
||||||
|
|
Loading…
Add table
Reference in a new issue