aboutsummaryrefslogtreecommitdiff
path: root/src/sys/schedule.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/sys/schedule.c')
-rw-r--r--src/sys/schedule.c54
1 files changed, 35 insertions, 19 deletions
diff --git a/src/sys/schedule.c b/src/sys/schedule.c
index 347b91a..b068963 100644
--- a/src/sys/schedule.c
+++ b/src/sys/schedule.c
@@ -55,23 +55,6 @@ struct RStack get_stack(void)
return r;
}
-void draw_stacks(void)
-{
- unsigned long ioff = 0;
- unsigned long yoff = STACK_DRAW_YOFF;
- for(int i = 0; i < MAX_THREADS; i++) {
- if(stacks_table[i])
- draw_cbox(ioff, yoff, STACK_DRAW_SIZE, STACK_DRAW_SIZE, 0xFFFFFF);
- else
- draw_cbox(ioff, yoff, STACK_DRAW_SIZE, STACK_DRAW_SIZE, 0x000000);
- ioff += STACK_DRAW_SIZE;
- if(ioff % STACK_DRAW_WIDTH == 0) {
- yoff += STACK_DRAW_SIZE;
- ioff = 0;
- }
- }
-}
-
void add_thread(void* pc, void* arg, unsigned char priority)
{
//void* sp = get_stack();
@@ -79,6 +62,7 @@ void add_thread(void* pc, void* arg, unsigned char priority)
//struct Thread* thread = (struct Thread*)malloca(sizeof(struct Thread), 4);
struct Thread* thread = (struct Thread*)kmalloc(sizeof(struct Thread));
thread->pc = pc;
+ // Valid stack has been obtained for this thread
if (r.sp) {
thread->sp_base = r.idx;
unsigned long* argp = r.sp;
@@ -89,26 +73,35 @@ void add_thread(void* pc, void* arg, unsigned char priority)
thread->sp = (void*)argp;
thread->status = THREAD_READY;
sched_stack_count++;
- } else {
+ }
+ // Couldn't allocate a proper stack
+ else {
thread->sp_base = r.idx;
thread->sp = r.sp;
thread->status = THREAD_SERROR;
}
thread->mptr = (void*)0;
thread->pid = nextpid++;
+ // Reset next pid on overflow
+ if (nextpid < FIRST_AVAIL_PID) {
+ nextpid = FIRST_AVAIL_PID;
+ }
thread->priority = priority % PRIORITIES;
thread->old_priority = -1;
thread->preempt = 0;
// Add Thread* to scheduler's appropriate buffer
struct ThreadQueues* tq = &scheduler.thread_queues[thread->priority];
struct ThreadRotBuffer* trb;
+ // Add to stack error queue if stack was not obtained
if (thread->status == THREAD_SERROR) {
trb = &tq->serror;
- } else {
+ }
+ else {
trb = &tq->ready;
}
trb->queue[trb->woffset++] = thread;
trb->woffset %= TQUEUE_MAX;
+ // Schedule if this was called in usermode
unsigned long mode = getmode() & 0x1F;
if (mode == 0x10) {
sys0(SYS_YIELD_HIGH);
@@ -154,12 +147,14 @@ void uart_scheduler(void)
struct Thread* next_thread(void)
{
struct Thread* next = &usrloopthread;
+ // Recurse through all priorities to try to find a ready thread
for (int p = 0; p < PRIORITIES; p++) {
struct ThreadRotBuffer* rb = &scheduler.thread_queues[p].ready;
if (rb->roffset == rb->woffset)
continue;
return rb->queue[rb->roffset];
}
+ // No thread found, use basic usrloopthread while waiting for new thread
return next;
}
@@ -171,8 +166,11 @@ void* get_rthread_roffset(void)
void yield(void)
{
struct Thread* rthread = scheduler.rthread;
+ // usrloopthread should not be yielded
if (rthread == &usrloopthread)
return;
+ // Put current thread at the end of its ready queue,
+ // thus any threads of the same priority can be run first
unsigned char priority = rthread->priority;
struct ThreadRotBuffer* trb = &scheduler.thread_queues[priority].ready;
trb->roffset += 1;
@@ -184,40 +182,51 @@ void yield(void)
void sched_mutex_yield(void* m)
{
struct Thread* rthread = scheduler.rthread;
+ // usrloopthread should not be yielded
if (rthread == &usrloopthread)
return;
unsigned char priority = rthread->priority;
+ // Signify which lock this thread is waiting for
rthread->mptr = m;
struct ThreadRotBuffer* trbb = &scheduler.thread_queues[priority].ready;
struct ThreadRotBuffer* trbm = &scheduler.thread_queues[priority].mwait;
+ // Move to next thread in the current thread priority's ready queue
trbb->roffset += 1;
trbb->roffset %= TQUEUE_MAX;
+ // Add thread to waiting queue
trbm->queue[trbm->woffset++] = rthread;
trbm->woffset %= TQUEUE_MAX;
// Find the thread with the mutex
struct ThreadQueues* tq;
+ // Search through each priority
for (int i = 0; i < PRIORITIES; i++) {
tq = &scheduler.thread_queues[i];
struct ThreadRotBuffer* trb = &tq->ready;
+ // Search through each queue at the current priority
for (int i = 0; i < TQUEUE_CNT; i++) {
unsigned long roffset = trb->roffset;
unsigned long woffset = trb->woffset;
+ // Search through the threads
while(roffset != woffset) {
// Found thread
if (trb->queue[roffset]->pid == ((struct Mutex*)m)->pid) {
// Promote the thread to the new priority
if (trb->queue[roffset]->priority > priority) {
trbb->queue[trbb->woffset++] = trb->queue[roffset];
+ // Set the old priority if not set
if(trb->queue[roffset]->old_priority == 0xFF)
trb->queue[roffset]->old_priority = trb->queue[roffset]->priority;
+ // Promote the priority
trb->queue[roffset]->priority = priority;
trbb->woffset %= TQUEUE_MAX;
unsigned long coffset = roffset;
+ // Fill gap where the thread was removed
while (coffset != woffset) {
trb->queue[coffset] = trb->queue[(coffset+1)%TQUEUE_MAX];
coffset++;
coffset %= TQUEUE_MAX;
}
+ // Move the woffset back since the gap was filled in
if (trb->woffset == 0)
trb->woffset = TQUEUE_MAX-1;
else
@@ -228,6 +237,7 @@ void sched_mutex_yield(void* m)
roffset++;
roffset %= TQUEUE_MAX;
}
+ // Check next queue in given priority
trb += 1;
}
}
@@ -235,11 +245,15 @@ void sched_mutex_yield(void* m)
void sched_mutex_resurrect(void* m)
{
+ // Look through each priority
for (int p = 0; p < PRIORITIES; p++) {
struct ThreadRotBuffer* trbm = &scheduler.thread_queues[p].mwait;
unsigned long roffset = trbm->roffset;
+ // Look through the lock wait queue
while (roffset != trbm->woffset) {
+ // Check if the thread is waiting for the released mutex
if (trbm->queue[roffset]->mptr == m) {
+ // Ressurect the thread
trbm->queue[roffset]->mptr = 0;
struct ThreadRotBuffer* trb = &scheduler.thread_queues[trbm->queue[roffset]->priority].ready;
trb->queue[trb->woffset++] = trbm->queue[roffset];
@@ -251,12 +265,14 @@ void sched_mutex_resurrect(void* m)
coffset++;
coffset %= TQUEUE_MAX;
}
+ // Move the woffset back since the space was filled
if(trbm->woffset == 0)
trbm->woffset = TQUEUE_MAX-1;
else
trbm->woffset--;
// Move the read pointer ahead
struct Thread* rthread = scheduler.rthread;
+ // Move the current thread to its old priority if it was promoted earlier
if (rthread->old_priority != 0xFF) {
struct ThreadRotBuffer* rtrb = &scheduler.thread_queues[rthread->priority].ready;
struct ThreadRotBuffer* ntrb = &scheduler.thread_queues[rthread->old_priority].ready;