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 ());

}
Пример #4
0
/*! 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);
}
Пример #5
0
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);
    }
}
Пример #6
0
/* 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();
	  }
  }
}
Пример #7
0
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);
    }
}
Пример #8
0
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++;
    }
}
Пример #9
0
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.");
}
Пример #10
0
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 ());
}
Пример #11
0
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.");
}
Пример #12
0
	 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);
			}
		}
	 }
Пример #13
0
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 ());
}
Пример #14
0
/* 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.");
}
Пример #17
0
/*
 * 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);
}
Пример #18
0
/* Obtain codec thread's current priority */
int codec_thread_get_priority(void)
{
    return thread_get_priority(codec_thread_id);
}