2021-11-08 00:07:58 +08:00
|
|
|
|
|
|
|
#include "kthread.h"
|
|
|
|
#include "kthread_switch.h"
|
|
|
|
#include "internal.h"
|
|
|
|
|
|
|
|
#include "../runtime/stdio.h"
|
|
|
|
#include <string.h>
|
|
|
|
|
2021-11-08 01:34:06 +08:00
|
|
|
#include "../util/tree_internal.h"
|
|
|
|
|
2021-11-08 00:07:58 +08:00
|
|
|
|
|
|
|
// defined in assembly
|
|
|
|
SYSV_ABI void __smp_Switch_Idle();
|
|
|
|
|
2021-11-08 01:34:06 +08:00
|
|
|
#define NODE_POINTER(node) (*((__smp_Thread **)(node->data)))
|
|
|
|
|
|
|
|
static void printTree(tree_Node *root, int level, __tree_ConnectType type) {
|
|
|
|
if (!root)
|
|
|
|
return;
|
|
|
|
for (int i = 0; i < level * 4; i++)
|
|
|
|
io_WriteConsoleASCII(" ");
|
|
|
|
io_Printf("%s, key=%d, data=%llx, &data=%llx\n", type == __tree_Left ? "Left" : "Right", root->key, (uint64_t)NODE_POINTER(root), root->data);
|
|
|
|
printTree(root->left, level + 1, __tree_Left);
|
|
|
|
printTree(root->right, level + 1, __tree_Right);
|
|
|
|
}
|
|
|
|
|
2021-11-08 00:07:58 +08:00
|
|
|
SYSV_ABI uintptr_t __smp_Switch() {
|
|
|
|
// the calling function smp_IntSwitch already CLI-ed for us
|
|
|
|
|
|
|
|
|
|
|
|
__smp_Thread *t = __smp_Current[0];
|
|
|
|
|
2021-11-11 01:50:02 +08:00
|
|
|
uint64_t priority = UINT64_MAX;
|
2021-11-11 02:16:39 +08:00
|
|
|
if (t)
|
2021-11-11 01:50:02 +08:00
|
|
|
priority = t->nice + (t->lastTick > __smp_Now ? t->lastTick : __smp_Now); // new priority for the thread
|
2021-11-08 00:07:58 +08:00
|
|
|
|
2021-11-14 17:40:09 +08:00
|
|
|
// find the waiting thread with the least priority
|
|
|
|
tree_Node *first = tree_FirstNode(__smp_ThreadsWaiting);
|
|
|
|
while (first && (NODE_POINTER(first)->sleepUntil > __smp_Now || NODE_POINTER(first)->waitCondition != NULL))
|
2021-11-08 00:07:58 +08:00
|
|
|
first = tree_Node_Next(first);
|
|
|
|
|
2021-11-14 17:40:09 +08:00
|
|
|
|
|
|
|
if (first && (NODE_POINTER(first)->sleepUntil <= __smp_Now && NODE_POINTER(first)->waitCondition == NULL) && first->key > priority)
|
2021-11-08 00:07:58 +08:00
|
|
|
// the current thread is still the first, return
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
// we need a real context switch
|
|
|
|
// first save the current thread context
|
2021-11-11 02:16:39 +08:00
|
|
|
if (t) {
|
|
|
|
t->lastTick = __smp_Now;
|
|
|
|
memcpy(&t->state, &__smp_IntSwitch_LastState, sizeof(smp_thread_State));
|
|
|
|
tree_Node *node = 0;
|
|
|
|
bool ok = false;
|
2021-11-14 17:40:09 +08:00
|
|
|
while (!ok)
|
|
|
|
node = tree_InsertNode(__smp_ThreadsWaiting, priority++, &ok);
|
2021-11-11 02:16:39 +08:00
|
|
|
NODE_POINTER(node) = t;
|
|
|
|
}
|
2021-11-08 00:07:58 +08:00
|
|
|
|
|
|
|
if (!first) {
|
|
|
|
// no thread available, load a dummy idle thread
|
|
|
|
__smp_IntSwitch_LastState.rip = (uint64_t)__smp_Switch_Idle;
|
2021-11-11 02:16:39 +08:00
|
|
|
__smp_IntSwitch_LastState.rflags |= 1 << 9; // Interrupt Enable flag
|
|
|
|
__smp_Current[0] = 0;
|
2021-11-08 00:07:58 +08:00
|
|
|
} else {
|
|
|
|
// load the new context
|
2021-11-08 01:34:06 +08:00
|
|
|
memcpy(&__smp_IntSwitch_LastState, &NODE_POINTER(first)->state, sizeof(smp_thread_State));
|
|
|
|
__smp_Current[0] = NODE_POINTER(first);
|
2021-11-08 00:07:58 +08:00
|
|
|
tree_Delete(__smp_ThreadsWaiting, first);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 1;
|
|
|
|
}
|