smp: Add Condition, separate SleepUntil from LastTick
This commit is contained in:
		
							
								
								
									
										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
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user