diff options
-rw-r--r-- | include/sys/schedule.h | 1 | ||||
-rw-r--r-- | src/sys/schedule.c | 54 | ||||
-rw-r--r-- | src/util/mutex.c | 74 |
3 files changed, 72 insertions, 57 deletions
diff --git a/include/sys/schedule.h b/include/sys/schedule.h index aa0e4c3..3c86d22 100644 --- a/include/sys/schedule.h +++ b/include/sys/schedule.h @@ -57,7 +57,6 @@ struct Scheduler { void init_scheduler(void); void add_thread(void* pc, void* arg, unsigned char priority); -void draw_stacks(void); void uart_scheduler(void); struct Thread* next_thread(void); /// TODO: ENSURE IRQ/ FIQ entry switches 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; diff --git a/src/util/mutex.c b/src/util/mutex.c index 5583d09..995ef62 100644 --- a/src/util/mutex.c +++ b/src/util/mutex.c @@ -4,43 +4,43 @@ #include <sys/schedule.h> #include <util/mutex.h> -unsigned char lock_mutex(struct Mutex* m, unsigned long pid) -{ - if (m->pid == NULL_PID) { - // Use currently running thread's PID if no pid given - if (pid == 0) { - struct Thread* thread = scheduler.rthread; - atm_lock(thread->pid, &m->pid); - } else { - atm_lock(pid, &m->pid); - } - return 0; - } - struct Thread* thread = scheduler.rthread; - thread->status = THREAD_MWAIT; - thread->mptr = m; - return 1; -} - -// Eventually, there will need to be a hook into the scheduling mechanism -// that checks the currently running process and check that against the -// mutex's pid lock -unsigned char release_mutex(struct Mutex* m, unsigned long pid) -{ - // Use current thread's PID if no pid - if (pid == 0) { - struct Thread* thread = scheduler.rthread; - if (m->pid == thread->pid) { - atm_release(&m->pid); - return 0; - } - } - else if (m->pid == pid) { - atm_release(&m->pid); - return 0; - } - return 1; -} +///unsigned char lock_mutex(struct Mutex* m, unsigned long pid) +///{ +/// if (m->pid == NULL_PID) { +/// // Use currently running thread's PID if no pid given +/// if (pid == 0) { +/// struct Thread* thread = scheduler.rthread; +/// atm_lock(thread->pid, &m->pid); +/// } else { +/// atm_lock(pid, &m->pid); +/// } +/// return 0; +/// } +/// struct Thread* thread = scheduler.rthread; +/// thread->status = THREAD_MWAIT; +/// thread->mptr = m; +/// return 1; +///} +/// +///// Eventually, there will need to be a hook into the scheduling mechanism +///// that checks the currently running process and check that against the +///// mutex's pid lock +///unsigned char release_mutex(struct Mutex* m, unsigned long pid) +///{ +/// // Use current thread's PID if no pid +/// if (pid == 0) { +/// struct Thread* thread = scheduler.rthread; +/// if (m->pid == thread->pid) { +/// atm_release(&m->pid); +/// return 0; +/// } +/// } +/// else if (m->pid == pid) { +/// atm_release(&m->pid); +/// return 0; +/// } +/// return 1; +///} struct Mutex* create_mutex(void* addr) { |