void test_priority_donate_multiple (void) { struct lock a, b; /* This test does not work with the MLFQS. */ ASSERT (!thread_mlfqs); /* Make sure our priority is the default. */ ASSERT (thread_get_priority () == PRI_DEFAULT); lock_init (&a); lock_init (&b); lock_acquire (&a); lock_acquire (&b); thread_create ("a", PRI_DEFAULT + 1, a_thread_func, &a); msg ("Main thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 1, thread_get_priority ()); thread_create ("b", PRI_DEFAULT + 2, b_thread_func, &b); msg ("Main thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 2, thread_get_priority ()); lock_release (&b); msg ("Thread b should have just finished."); msg ("Main thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 1, thread_get_priority ()); lock_release (&a); msg ("Thread a should have just finished."); msg ("Main thread should have priority %d. Actual priority: %d.", PRI_DEFAULT, thread_get_priority ()); }
void test_priority_donate_nest (void) { struct lock a, b; struct locks locks; /* This test does not work with the MLFQS. */ ASSERT (!thread_mlfqs); /* Make sure our priority is the default. */ ASSERT (thread_get_priority () == PRI_DEFAULT); lock_init (&a); lock_init (&b); lock_acquire (&a); locks.a = &a; locks.b = &b; thread_create ("medium", PRI_DEFAULT + 1, medium_thread_func, &locks); thread_yield (); msg ("Low thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 1, thread_get_priority ()); thread_create ("high", PRI_DEFAULT + 2, high_thread_func, &b); thread_yield (); msg ("Low thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 2, thread_get_priority ()); lock_release (&a); thread_yield (); msg ("Medium thread should just have finished."); msg ("Low thread should have priority %d. Actual priority: %d.", PRI_DEFAULT, thread_get_priority ()); }
void test_priority_donate_lower(void) { struct lock lock; /* This test does not work with the MLFQS. */ ASSERT(!thread_mlfqs); /* Make sure our priority is the default. */ ASSERT(thread_get_priority () == PRI_DEFAULT); lock_init(&lock); lock_acquire(&lock); thread_create("acquire", PRI_DEFAULT + 10, acquire_thread_func, &lock); msg("Main thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 10, thread_get_priority ()); msg("Lowering base priority..."); thread_set_priority(PRI_DEFAULT - 10); msg("Main thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 10, thread_get_priority ()); lock_release(&lock); msg("acquire must already have finished."); msg("Main thread should have priority %d. Actual priority: %d.", PRI_DEFAULT - 10, thread_get_priority ()); }
/*! Up or "V" operation on a semaphore. Increments SEMA's value and wakes up one thread of those waiting for SEMA, if any. This function may be called from an interrupt handler. */ void sema_up(struct semaphore *sema) { enum intr_level old_level; ASSERT(sema != NULL); old_level = intr_disable(); sema->value++; if (!list_empty(&sema->waiters)) { struct list_elem *e = list_begin(&sema->waiters); struct thread *wake_thread = list_entry(e, struct thread, elem); int max_priority = compute_priority(wake_thread); for (e = list_next(e); e != list_end(&sema->waiters); e = list_next(e)) { struct thread *t = list_entry(e, struct thread, elem); int priority = compute_priority(t); if (priority > max_priority) { max_priority = priority; wake_thread = t; } } list_remove(&wake_thread->elem); thread_unblock(wake_thread); if (max_priority >= thread_get_priority()) { thread_yield(); } } intr_set_level(old_level); }
static void priceil_set(mtx_t * mtx) { if (MTX_OPT(mtx, MTX_OPT_PRICEIL)) { mtx->pri.p_saved = thread_get_priority(current_thread->id); thread_set_priority(current_thread->id, mtx->pri.p_lock); } }
/* Up or "V" operation on a semaphore. Increments SEMA's value and wakes up one thread of those waiting for SEMA, if any. This function may be called from an interrupt handler. */ void sema_up (struct semaphore *sema) { enum intr_level old_level; struct thread * tmp_t = thread_current(); ASSERT (sema != NULL); old_level = intr_disable (); //unblock the higherst pri on the waiter list if (!list_empty (&sema->waiters)) { //printf("\nsema->waiters list size: %d\n", list_size(&sema->waiters)); struct list_elem *tmp_e = list_max((&sema->waiters), find_less_pri, NULL); list_remove(tmp_e); tmp_t = list_entry(tmp_e, struct thread, elem); thread_unblock(tmp_t); } sema->value++; intr_set_level (old_level); //if the curr thread doesnt have the highest anymore, yield if(thread_current() != tmp_t){ if (thread_get_priority() < get_pri(tmp_t)) { thread_yield(); } } }
static void priceil_restore(mtx_t * mtx) { if (MTX_OPT(mtx, MTX_OPT_PRICEIL)) { /* * RFE There is a very rare race condition if some other thread tries to * set a new priority for this thread just after this if clause. */ if (thread_get_priority(current_thread->id) == mtx->pri.p_lock) thread_set_priority(current_thread->id, mtx->pri.p_saved); } }
void test_priority_fifo (void) { struct simple_thread_data data[THREAD_CNT]; struct lock lock; int *output, *op; int i, cnt; /* This test does not work with the MLFQS. */ ASSERT (selected_scheduler != SCH_MLFQS); /* Make sure our priority is the default. */ ASSERT (thread_get_priority () == PRI_DEFAULT); msg ("%d threads will iterate %d times in the same order each time.", THREAD_CNT, ITER_CNT); msg ("If the order varies then there is a bug."); output = op = malloc (sizeof *output * THREAD_CNT * ITER_CNT * 2); ASSERT (output != NULL); lock_init (&lock); thread_set_priority (PRI_DEFAULT + 2); for (i = 0; i < THREAD_CNT; i++) { char name[16]; struct simple_thread_data *d = data + i; snprintf (name, sizeof name, "%d", i); d->id = i; d->iterations = 0; d->lock = &lock; d->op = &op; thread_create (name, PRI_DEFAULT + 1, simple_thread_func, d); } thread_set_priority (PRI_DEFAULT); /* All the other threads now run to termination here. */ ASSERT (lock.holder == NULL); cnt = 0; for (; output < op; output++) { struct simple_thread_data *d; ASSERT (*output >= 0 && *output < THREAD_CNT); d = data + *output; if (cnt % THREAD_CNT == 0) printf ("(priority-fifo) iteration:"); printf (" %d", d->id); if (++cnt % THREAD_CNT == 0) printf ("\n"); d->iterations++; } }
void test_priority_preempt (void) { /* This test does not work with the MLFQS. */ ASSERT (selected_scheduler != SCH_MLFQS); /* Make sure our priority is the default. */ ASSERT (thread_get_priority () == PRI_DEFAULT); thread_create ("high-priority", PRI_DEFAULT + 1, simple_thread_func, NULL); msg ("The high-priority thread should have already completed."); }
void test_priority_donate_chain (void) { int i; struct lock locks[NESTING_DEPTH - 1]; struct lock_pair lock_pairs[NESTING_DEPTH]; /* This test does not work with the MLFQS. */ ASSERT (!thread_mlfqs); thread_set_priority (PRI_MIN); for (i = 0; i < NESTING_DEPTH - 1; i++) lock_init (&locks[i]); lock_acquire (&locks[0]); msg ("%s got lock.", thread_name ()); for (i = 1; i < NESTING_DEPTH; i++) { char name[16]; int thread_priority; snprintf (name, sizeof name, "thread %d", i); thread_priority = PRI_MIN + i * 3; lock_pairs[i].first = i < NESTING_DEPTH - 1 ? locks + i: NULL; lock_pairs[i].second = locks + i - 1; thread_create (name, thread_priority, donor_thread_func, lock_pairs + i); msg ("%s should have priority %d. Actual priority: %d.", thread_name (), thread_priority, thread_get_priority ()); snprintf (name, sizeof name, "interloper %d", i); thread_create (name, thread_priority - 1, interloper_thread_func, NULL); } lock_release (&locks[0]); msg ("%s finishing with priority %d.", thread_name (), thread_get_priority ()); }
void test_priority_donate_one (void) { struct lock lock; /* This test does not work with the MLFQS. */ ASSERT (!thread_mlfqs); /* Make sure our priority is the default. */ ASSERT (thread_get_priority () == PRI_DEFAULT); lock_init (&lock); lock_acquire (&lock); thread_create ("acquire1", PRI_DEFAULT + 1, acquire1_thread_func, &lock); msg ("This thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 1, thread_get_priority ()); thread_create ("acquire2", PRI_DEFAULT + 2, acquire2_thread_func, &lock); msg ("This thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 2, thread_get_priority ()); lock_release (&lock); msg ("acquire2, acquire1 must already have finished, in that order."); msg ("This should be the last line before finishing this test."); }
void check_for_donation(struct lock *lock) { if(lock->holder !=NULL) { int get_p=thread_highest_priority(lock->holder); int cur_thd_p=thread_get_priority(); if(cur_thd_p > get_p) { struct thread *cur_t=thread_current(); donation_of_priority(cur_t,lock->holder,lock); } } }
static void donor_thread_func (void *locks_) { struct lock_pair *locks = locks_; if (locks->first) lock_acquire (locks->first); lock_acquire (locks->second); msg ("%s got lock", thread_name ()); lock_release (locks->second); msg ("%s should have priority %d. Actual priority: %d", thread_name (), (NESTING_DEPTH - 1) * 3, thread_get_priority ()); if (locks->first) lock_release (locks->first); msg ("%s finishing with priority %d.", thread_name (), thread_get_priority ()); }
/* Up or "V" operation on a semaphore. Increments SEMA's value and wakes up one thread of those waiting for SEMA, if any. This function may be called from an interrupt handler. */ void sema_up (struct semaphore *sema) { enum intr_level old_level; ASSERT (sema != NULL); bool should_yield = false; old_level = intr_disable (); sema->value++; if (!list_empty (&sema->waiters)) { list_sort (&sema->waiters, &priority_ordering, NULL); //MAYBE THIS'll DO? struct thread *t = list_entry (list_pop_front (&sema->waiters), struct thread, elem); thread_unblock (t); if (t->priority >= thread_get_priority()) { should_yield = true; } }
void test_priority_donate_sema (void) { struct lock_and_sema ls; /* This test does not work with the MLFQS. */ ASSERT (!thread_mlfqs); /* Make sure our priority is the default. */ ASSERT (thread_get_priority () == PRI_DEFAULT); lock_init (&ls.lock); sema_init (&ls.sema, 0); thread_create ("low", PRI_DEFAULT + 1, l_thread_func, &ls); thread_create ("med", PRI_DEFAULT + 3, m_thread_func, &ls); thread_create ("high", PRI_DEFAULT + 5, h_thread_func, &ls); sema_up (&ls.sema); msg ("Main thread finished."); }
static void medium_thread_func (void *locks_) { struct locks *locks = locks_; lock_acquire (locks->b); lock_acquire (locks->a); msg ("Medium thread should have priority %d. Actual priority: %d.", PRI_DEFAULT + 2, thread_get_priority ()); msg ("Medium thread got the lock."); lock_release (locks->a); thread_yield (); lock_release (locks->b); thread_yield (); msg ("High thread should have just finished."); msg ("Middle thread finished."); }
/* * Actual scheduler. Returns the next thread to run. Calls cpu_idle() * if there's nothing ready. (Note: cpu_idle must be called in a loop * until something's ready - it doesn't know whether the things that * wake it up are going to make a thread runnable or not.) */ struct thread * scheduler(void) { // meant to be called with interrupts off assert(curspl>0); while (q_empty(runqueue)) { cpu_idle(); } // You can actually uncomment this to see what the scheduler's // doing - even this deep inside thread code, the console // still works. However, the amount of text printed is // prohibitive. // //print_run_queue(); /* We will have a defined variable in scheduler.h that will control the type of scheduling */ if(scheduler_type == SCHEDULER_RANDOM) { /* Random queue method */ // We could manipulate q->next_read, an integer that indexes the next in line // i.e. pick an index based on the size of the queue (q->size), and change // runqueue->next_read to that index // We might also be able to just jump in and get a random index from the queue // queue size is 32 by default int queue_size = q_getsize(runqueue); int random_index; struct thread * temp_thread; // We will have to get the thread number from within the active part // of the queue int start = q_getstart(runqueue); int end = q_getend(runqueue); int random_range = (end - start); // We have a problem if the start and end are the same assert(random_range != 0); // The startup code seems to have issues if you pick it right off the bat if (random_range < 0) random_range = random_range + queue_size; // No need to pick a random thread if there is only 1 in the queue if (random_range == 1) return q_remhead(runqueue); DEBUG(DB_THREADS, "Number of active threads: %u.\n", random_range); DEBUG(DB_THREADS, "Start: %u.\n", start); DEBUG(DB_THREADS, "End: %u.\n", end); random_index = (random() % random_range + start) % queue_size; DEBUG(DB_THREADS, "%u index chosen.\n", random_index); // Now, we have to move our chosen thread to the front of the line // There is probably some other way to do this that is more efficient, but // I had no success with q_getguy() // We start with the next thread in the queue, and work our way to the chosen one while(q_getstart(runqueue) != random_index) { temp_thread = q_remhead(runqueue); q_addtail(runqueue, temp_thread); } DEBUG(DB_THREADS, "New start: %u.\n", q_getstart(runqueue)); DEBUG(DB_THREADS, "New end: %u.\n", q_getend(runqueue)); return q_remhead(runqueue); } else if (scheduler_type == SCHEDULER_MLFQ) { /* MLFQ method */ // We will go through all of our queue, looking for the highest priority thread // By starting at the next read and working up, on a tie we are taking the first in // queue size is 32 by default int queue_size = q_getsize(runqueue); int i; int chosen_index; int priority; int random_choice; struct thread * temp_thread; // We will have to get the thread number from within the active part // of the queue int start = q_getstart(runqueue); int end = q_getend(runqueue); cycles++; if (cycles > 2000) { // reset priorities //kprintf("Resetting priorities"); i = start; while( i != end) { temp_thread = q_getguy(runqueue, i); DEBUG(DB_THREADS, "Setting priority\n"); thread_set_priority(temp_thread, 50); i = (i+1) % queue_size; } cycles = 0; // A bit of randomness to prevent immediate restarving return q_remhead(runqueue); } int highest_priority = -1; // 100 is maximum priority i = start; while( i != end) { temp_thread = q_getguy(runqueue, i); DEBUG(DB_THREADS, "Getting priority\n"); priority = thread_get_priority(temp_thread); DEBUG(DB_THREADS, "Priority: %u.\n", priority); if (priority > highest_priority) { chosen_index = i; highest_priority = priority; } // In the event of a tie, random pick else if (priority == highest_priority) { random_choice == random() % 3; if (random_choice == 0) chosen_index = i; } i = (i+1) % queue_size; } DEBUG(DB_THREADS, "Start: %u.\n", start); DEBUG(DB_THREADS, "End: %u.\n", end); DEBUG(DB_THREADS, "%u index chosen with priority %u.\n", chosen_index, highest_priority); //kprintf("%u index chosen with priority %u.\n", chosen_index, highest_priority); // Now, we have to move our chosen thread to the front of the line // There is probably some other way to do this that is more efficient, but // I had no success with q_getguy() // We start with the next thread in the queue, and work our way to the chosen one while(q_getstart(runqueue) != chosen_index) { temp_thread = q_remhead(runqueue); q_addtail(runqueue, temp_thread); } DEBUG(DB_THREADS, "New start: %u.\n", q_getstart(runqueue)); DEBUG(DB_THREADS, "New end: %u.\n", q_getend(runqueue)); return q_remhead(runqueue); } // Fall through to default FIFO scheduler return q_remhead(runqueue); }
/* Obtain codec thread's current priority */ int codec_thread_get_priority(void) { return thread_get_priority(codec_thread_id); }