smp: Add Condition, separate SleepUntil from LastTick
This commit is contained in:
parent
9eeb9c8632
commit
2fd9209b85
71
smp/condiction.c
Normal file
71
smp/condiction.c
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
|
||||||
|
#include "condiction.h"
|
||||||
|
#include "kthread.h"
|
||||||
|
#include "internal.h"
|
||||||
|
#include "../interrupt/interrupt.h"
|
||||||
|
#include "../memory/memory.h"
|
||||||
|
|
||||||
|
|
||||||
|
smp_Condition *smp_Condition_Create() {
|
||||||
|
smp_Condition *c = kMalloc(sizeof(smp_Condition));
|
||||||
|
c->threads = vector_Create(sizeof(__smp_Thread *));
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
void smp_Condition_Destroy(smp_Condition *c) {
|
||||||
|
vector_Destroy(c->threads);
|
||||||
|
kFree(c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *smp_Condition_Wait(smp_Condition *c) {
|
||||||
|
INTERRUPT_DISABLE;
|
||||||
|
|
||||||
|
__smp_Thread *t = __smp_Current[0];
|
||||||
|
t->waitCondition = c;
|
||||||
|
vector_Push(c->threads, &t);
|
||||||
|
|
||||||
|
INTERRUPT_RESTORE;
|
||||||
|
smp_thread_Yield();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool smp_Condition_NotifyOne(smp_Condition *c, void *data) {
|
||||||
|
INTERRUPT_DISABLE;
|
||||||
|
|
||||||
|
uintptr_t size = vector_Size(c->threads);
|
||||||
|
if (size == 0) {
|
||||||
|
INTERRUPT_RESTORE;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
__smp_Thread *last = *(__smp_Thread **)vector_At(c->threads, size - 1);
|
||||||
|
last->waitCondition = NULL;
|
||||||
|
vector_Resize(c->threads, size - 1);
|
||||||
|
|
||||||
|
INTERRUPT_RESTORE;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NotifyAll unblocks all waiting threads.
|
||||||
|
//
|
||||||
|
// The data is (for now) not sent.
|
||||||
|
//
|
||||||
|
// Returns the number of threads unblocked.
|
||||||
|
int smp_Condition_NotifyAll(smp_Condition *c, void *data) {
|
||||||
|
INTERRUPT_DISABLE;
|
||||||
|
|
||||||
|
uintptr_t size = vector_Size(c->threads);
|
||||||
|
if (size == 0) {
|
||||||
|
INTERRUPT_RESTORE;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uintptr_t i = 0; i < size; i++) {
|
||||||
|
__smp_Thread *t = *(__smp_Thread **)vector_At(c->threads, i);
|
||||||
|
t->waitCondition = NULL;
|
||||||
|
}
|
||||||
|
vector_Clear(c->threads);
|
||||||
|
|
||||||
|
INTERRUPT_RESTORE;
|
||||||
|
return true;
|
||||||
|
}
|
44
smp/condiction.h
Normal file
44
smp/condiction.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "../main.h"
|
||||||
|
#include "../util/vector.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
// Condition is a waiting condition.
|
||||||
|
typedef struct {
|
||||||
|
vector_Vector *threads; // threads waiting on the condition
|
||||||
|
} smp_Condition;
|
||||||
|
|
||||||
|
// Create allocates a new, empty Condition.
|
||||||
|
smp_Condition *smp_Condition_Create();
|
||||||
|
|
||||||
|
void smp_Condition_Destroy(smp_Condition *con);
|
||||||
|
|
||||||
|
// Wait waits until the condition is notified.
|
||||||
|
//
|
||||||
|
// The returned data is (for now) useless.
|
||||||
|
void *smp_Condition_Wait(smp_Condition *con);
|
||||||
|
|
||||||
|
// NotifyOne unblocks (at most) one waiting thread.
|
||||||
|
//
|
||||||
|
// The data is (for now) not sent.
|
||||||
|
//
|
||||||
|
// If there are actually threads waiting, true is returned.
|
||||||
|
bool smp_Condition_NotifyOne(smp_Condition *con, void *data);
|
||||||
|
|
||||||
|
// NotifyAll unblocks all waiting threads.
|
||||||
|
//
|
||||||
|
// The data is (for now) not sent.
|
||||||
|
//
|
||||||
|
// Returns the number of threads unblocked.
|
||||||
|
int smp_Condition_NotifyAll(smp_Condition *con, void *data);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
#include "kthread.h"
|
#include "kthread.h"
|
||||||
#include "kthread_switch.h"
|
#include "kthread_switch.h"
|
||||||
|
#include "condiction.h"
|
||||||
#include "../util/tree.h"
|
#include "../util/tree.h"
|
||||||
|
|
||||||
|
|
||||||
@ -14,8 +15,9 @@ typedef struct {
|
|||||||
unsigned int nice;
|
unsigned int nice;
|
||||||
|
|
||||||
// Last tick at which the thread started waiting
|
// Last tick at which the thread started waiting
|
||||||
// More than Now means the thread is actively sleeping and is not to be resumed.
|
uint64_t lastTick;
|
||||||
uint64_t lastTick;
|
uint64_t sleepUntil;
|
||||||
|
smp_Condition *waitCondition;
|
||||||
|
|
||||||
// Last-saved thread state after preemptive context switch
|
// Last-saved thread state after preemptive context switch
|
||||||
smp_thread_State state;
|
smp_thread_State state;
|
||||||
|
@ -22,6 +22,8 @@ smp_thread_ID smp_thread_Init() {
|
|||||||
t->nice = SMP_NICENESS_DEFAULT;
|
t->nice = SMP_NICENESS_DEFAULT;
|
||||||
t->id = id;
|
t->id = id;
|
||||||
t->lastTick = 1;
|
t->lastTick = 1;
|
||||||
|
t->sleepUntil = 0;
|
||||||
|
t->waitCondition = NULL;
|
||||||
__smp_Count = 1;
|
__smp_Count = 1;
|
||||||
|
|
||||||
__smp_Current = kMalloc(sizeof(void *) * __smp_Count);
|
__smp_Current = kMalloc(sizeof(void *) * __smp_Count);
|
||||||
@ -44,6 +46,8 @@ smp_thread_ID smp_thread_Start(void *entry, const smp_thread_Arguments *args, un
|
|||||||
t->nice = nice;
|
t->nice = nice;
|
||||||
t->id = id;
|
t->id = id;
|
||||||
t->lastTick = __smp_Now;
|
t->lastTick = __smp_Now;
|
||||||
|
t->sleepUntil = 0;
|
||||||
|
t->waitCondition = NULL;
|
||||||
|
|
||||||
t->state.cs = GDT_EXEC_SELECTOR;
|
t->state.cs = GDT_EXEC_SELECTOR;
|
||||||
t->state.ss = 0;
|
t->state.ss = 0;
|
||||||
@ -87,7 +91,7 @@ int smp_thread_Nice(smp_thread_ID id, int newnice) {
|
|||||||
|
|
||||||
void smp_thread_Sleep(int ticks) {
|
void smp_thread_Sleep(int ticks) {
|
||||||
INTERRUPT_DISABLE;
|
INTERRUPT_DISABLE;
|
||||||
__smp_Current[0]->lastTick = __smp_Now + ticks;
|
__smp_Current[0]->sleepUntil = __smp_Now + ticks;
|
||||||
INTERRUPT_RESTORE;
|
INTERRUPT_RESTORE;
|
||||||
smp_thread_Yield();
|
smp_thread_Yield();
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "../main.h"
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
@ -37,7 +38,7 @@ smp_thread_ID smp_thread_Start(void *entry, const smp_thread_Arguments *args, un
|
|||||||
int smp_thread_Nice(smp_thread_ID id, int newnice);
|
int smp_thread_Nice(smp_thread_ID id, int newnice);
|
||||||
|
|
||||||
// Yield pauses the execution of the current thread, possibly switching to another.
|
// Yield pauses the execution of the current thread, possibly switching to another.
|
||||||
void smp_thread_Yield();
|
SYSV_ABI void smp_thread_Yield();
|
||||||
|
|
||||||
// Sleep sleeps for a given amount of ticks (1024Hz)
|
// Sleep sleeps for a given amount of ticks (1024Hz)
|
||||||
void smp_thread_Sleep(int ticks);
|
void smp_thread_Sleep(int ticks);
|
||||||
|
@ -31,32 +31,24 @@ SYSV_ABI uintptr_t __smp_Switch() {
|
|||||||
|
|
||||||
__smp_Thread *t = __smp_Current[0];
|
__smp_Thread *t = __smp_Current[0];
|
||||||
|
|
||||||
tree_Node *node = 0;
|
uint64_t priority = UINT64_MAX;
|
||||||
// insert the current thread back into the waiting queue
|
// insert the current thread back into the waiting queue
|
||||||
if (t) {
|
if (t) {
|
||||||
uint64_t priority = t->nice + (t->lastTick > __smp_Now ? t->lastTick : __smp_Now); // new priority for the thread
|
priority = t->nice + (t->lastTick > __smp_Now ? t->lastTick : __smp_Now); // new priority for the thread
|
||||||
bool ok = false;
|
|
||||||
do {
|
|
||||||
node = tree_InsertNode(__smp_ThreadsWaiting, priority, &ok);
|
|
||||||
priority++;
|
|
||||||
} while (!ok);
|
|
||||||
NODE_POINTER(node) = t;
|
|
||||||
}
|
}
|
||||||
//printTree(__smp_Threads->root, 0, 0);
|
//printTree(__smp_Threads->root, 0, 0);
|
||||||
//printTree(__smp_ThreadsWaiting->root, 0, 0);
|
//printTree(__smp_ThreadsWaiting->root, 0, 0);
|
||||||
tree_Node *first = tree_FirstNode(__smp_ThreadsWaiting);
|
tree_Node *first = tree_FirstNode(__smp_ThreadsWaiting);
|
||||||
|
|
||||||
//io_Printf(" first0.id=%d\n", NODE_POINTER(first) ? NODE_POINTER(first)->id : 0);
|
//io_Printf(" first0.id=%d\n", NODE_POINTER(first) ? NODE_POINTER(first)->id : 0);
|
||||||
while (first && NODE_POINTER(first)->lastTick > __smp_Now) {
|
while (first && (NODE_POINTER(first)->sleepUntil > __smp_Now || NODE_POINTER(first)->waitCondition != NULL)) {
|
||||||
//io_Printf(" iterating, .id=%d\n", NODE_POINTER(first) ? NODE_POINTER(first)->id : 0);
|
//io_Printf(" iterating, .id=%d\n", NODE_POINTER(first) ? NODE_POINTER(first)->id : 0);
|
||||||
first = tree_Node_Next(first);
|
first = tree_Node_Next(first);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first == node) {
|
if ((t->sleepUntil <= __smp_Now && t->waitCondition == NULL) && first->key > priority) {
|
||||||
// the current thread is still the first, return
|
// the current thread is still the first, return
|
||||||
//io_Printf(" Not context switching, still running %d\n", t ? t->id : 0);
|
//io_Printf(" Not context switching, still running %d\n", t ? t->id : 0);
|
||||||
if (node)
|
|
||||||
tree_Delete(__smp_ThreadsWaiting, node);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -64,6 +56,13 @@ SYSV_ABI uintptr_t __smp_Switch() {
|
|||||||
// first save the current thread context
|
// first save the current thread context
|
||||||
t->lastTick = __smp_Now;
|
t->lastTick = __smp_Now;
|
||||||
memcpy(&t->state, &__smp_IntSwitch_LastState, sizeof(smp_thread_State));
|
memcpy(&t->state, &__smp_IntSwitch_LastState, sizeof(smp_thread_State));
|
||||||
|
tree_Node *node = 0;
|
||||||
|
bool ok = false;
|
||||||
|
do {
|
||||||
|
node = tree_InsertNode(__smp_ThreadsWaiting, priority, &ok);
|
||||||
|
priority++;
|
||||||
|
} while (!ok);
|
||||||
|
NODE_POINTER(node) = t;
|
||||||
|
|
||||||
if (!first) {
|
if (!first) {
|
||||||
// no thread available, load a dummy idle thread
|
// no thread available, load a dummy idle thread
|
||||||
|
Loading…
Reference in New Issue
Block a user