smp: Add Condition, separate SleepUntil from LastTick
This commit is contained in:
parent
9eeb9c8632
commit
845f82afc9
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_switch.h"
|
||||
#include "condiction.h"
|
||||
#include "../util/tree.h"
|
||||
|
||||
|
||||
@ -14,8 +15,9 @@ typedef struct {
|
||||
unsigned int nice;
|
||||
|
||||
// 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
|
||||
smp_thread_State state;
|
||||
|
@ -87,7 +87,7 @@ int smp_thread_Nice(smp_thread_ID id, int newnice) {
|
||||
|
||||
void smp_thread_Sleep(int ticks) {
|
||||
INTERRUPT_DISABLE;
|
||||
__smp_Current[0]->lastTick = __smp_Now + ticks;
|
||||
__smp_Current[0]->sleepUntil = __smp_Now + ticks;
|
||||
INTERRUPT_RESTORE;
|
||||
smp_thread_Yield();
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "../main.h"
|
||||
#include <stdint.h>
|
||||
|
||||
#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);
|
||||
|
||||
// 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)
|
||||
void smp_thread_Sleep(int ticks);
|
||||
|
@ -31,32 +31,24 @@ SYSV_ABI uintptr_t __smp_Switch() {
|
||||
|
||||
__smp_Thread *t = __smp_Current[0];
|
||||
|
||||
tree_Node *node = 0;
|
||||
uint64_t priority = UINT64_MAX;
|
||||
// insert the current thread back into the waiting queue
|
||||
if (t) {
|
||||
uint64_t 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;
|
||||
priority = t->nice + (t->lastTick > __smp_Now ? t->lastTick : __smp_Now); // new priority for the thread
|
||||
}
|
||||
//printTree(__smp_Threads->root, 0, 0);
|
||||
//printTree(__smp_ThreadsWaiting->root, 0, 0);
|
||||
tree_Node *first = tree_FirstNode(__smp_ThreadsWaiting);
|
||||
|
||||
//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);
|
||||
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
|
||||
//io_Printf(" Not context switching, still running %d\n", t ? t->id : 0);
|
||||
if (node)
|
||||
tree_Delete(__smp_ThreadsWaiting, node);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -64,6 +56,13 @@ SYSV_ABI uintptr_t __smp_Switch() {
|
||||
// first save the current thread context
|
||||
t->lastTick = __smp_Now;
|
||||
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) {
|
||||
// no thread available, load a dummy idle thread
|
||||
|
Loading…
Reference in New Issue
Block a user