示例#1
0
static void yield_running_thread()
{
  minithread_t *first_runnable = NULL;
  minithread_t *temp = running_thread;
  int res = multilevel_queue_dequeue(runnable_queue, curr_level, (void **)(&first_runnable));
  if (running_thread != scheduler_thread) {
    multilevel_queue_enqueue(runnable_queue, running_thread->level, running_thread);
  }
  if (res != -1) {
    // if the level of dequeued thread is different from current running, update the curr_level
    // and also the curr_level_quanta is reset to 0, since we are switching to the next level
    if (curr_level != first_runnable->level) {
      curr_level = first_runnable->level;
      curr_level_quanta = 0;
    }
    if (running_thread != first_runnable) {
      running_thread = first_runnable;
      minithread_switch(&temp->top, &running_thread->top);
    }
  }
  else {
    running_thread = scheduler_thread;
    minithread_switch(&temp->top, &running_thread->top);
  }
}
示例#2
0
/*
 * Initialization.
 * Initializes reaper and idle threads, starts and initializes main thread.
 * Also creates the scheduler and other data 
 *
 */
void minithread_system_initialize(proc_t mainproc, arg_t mainarg) {
  //allocate room for schedule data (global)
  schedule_data = (scheduler *) malloc(sizeof(scheduler));
  if (schedule_data == NULL) {
    exit(1); //OOM
  }
  schedule_data->cleanup_queue = queue_new();
  schedule_data->multi_run_queue = multilevel_queue_new(num_levels);

  reaper_sema = semaphore_create();
  semaphore_initialize(reaper_sema, 0);

  // create main thread
  minithread_t* main_thread = minithread_fork(mainproc, mainarg);

  // initialize idle thread
  idle_thread = (minithread_t *) malloc(sizeof(minithread_t));
  idle_thread->stacktop = NULL;
  idle_thread->thread_id = -1;

  //initialize alarm bookeeping data structure (priority queue)
  alarm_init();

  //remove from run queue and run it
  schedule_data->running_thread = main_thread;
  main_thread->status = RUNNING;
  multilevel_queue_dequeue(schedule_data->multi_run_queue, 0, (void *) main_thread);

  //reaper thread init
  reaper_thread = minithread_create(reaper_queue_cleanup, NULL);
  minithread_start(reaper_thread);

  //Start clock
  minithread_clock_init(clock_period, clock_handler);

  //Initialize network
  network_initialize(network_handler);

  //START MAIN PROC
  //minithread_switch also enables clock interrupts
  minithread_switch(&idle_thread->stacktop, &main_thread->stacktop);
  //always comes back here to idle in the kernel level (allows freeing resources)
  while (1) {
    minithread_t* next = next_runnable();

    set_interrupt_level(DISABLED);
    next->status = RUNNING;
    schedule_data->running_thread = next;
    minithread_switch(&idle_thread->stacktop, &next->stacktop);
  }
}
示例#3
0
/*
 * Initialization.
 *
 *      minithread_system_initialize:
 *       This procedure should be called from your C main procedure
 *       to turn a single threaded UNIX process into a multithreaded
 *       program.
 *
 *       Initialize any private data structures.
 *       Create the idle thread.
 *       Fork the thread which should call mainproc(mainarg)
 *       Start scheduling.
 *
 */
void
minithread_system_initialize(proc_t mainproc, arg_t mainarg) {
  minithread_t clean_up_thread = NULL;
  int a = 0;
  void* dummy_ptr = NULL;
  minithread_t tmp = NULL;
  tmp = NULL;
  dummy_ptr = (void*)&a;
  current_id = 0; // the next thread id to be assigned
  id_lock = semaphore_create();
  semaphore_initialize(id_lock,1); 
  runnable_q = multilevel_queue_new(4);
  blocked_q = queue_new();
  blocked_q_lock = semaphore_create();
  semaphore_initialize(blocked_q_lock,1);
  dead_q = queue_new();
  dead_q_lock = semaphore_create();
  semaphore_initialize(dead_q_lock,1);
  dead_sem = semaphore_create();
  semaphore_initialize(dead_sem,0);    
  runnable_q_lock = semaphore_create();
  semaphore_initialize(runnable_q_lock,1);
  clean_up_thread = minithread_create(clean_up, NULL);
  multilevel_queue_enqueue(runnable_q,
    clean_up_thread->priority,clean_up_thread);
  runnable_count++;
  minithread_clock_init(TIME_QUANTA, (interrupt_handler_t)clock_handler);
  init_alarm();
  current_thread = minithread_create(mainproc, mainarg);
  minithread_switch(&dummy_ptr, &(current_thread->stacktop));
  return;
}
示例#4
0
int scheduler() {
  int next_priority = 0;
  minithread_t next = NULL;
  minithread_t temp = NULL;
   
  while (1) {
    while (runnable_count == 0) {
      set_interrupt_level(ENABLED);
    };
    
    set_interrupt_level(DISABLED);
    //dequeue from runnable threads
    next_priority = choose_priority_level();
    if (multilevel_queue_dequeue(runnable_q,
        next_priority,(void**)(&next)) != -1) {
      runnable_count--;
      temp = current_thread;
      current_thread = next;
      minithread_switch(&(temp->stacktop),&(next->stacktop));
      return 0;
    }
    //if dead/runnable queue is empty, do nothing (idle thread)
  }
  return 0;
}
示例#5
0
/* stops execution of current minithread, and then proceeds to get next RUNNABLE minithread
 * and begin execution from where that minithread left off. */
void minithread_stop() {
  set_interrupt_level(DISABLED);

  minithread_t* curr = schedule_data->running_thread;
  curr->status = WAITING;
  schedule_data->running_thread = idle_thread;

  if (multilevel_queue_total_elements(schedule_data->multi_run_queue) > 0) {
    minithread_t* next = next_runnable();
    next->status = RUNNING;
    schedule_data->running_thread = next;

    //switch to new RUNNING mini thread
    minithread_switch(&curr->stacktop, &next->stacktop);
  }
  else {
    //idle in the kernel level
    minithread_switch(&curr->stacktop, &idle_thread->stacktop);
  }
}
示例#6
0
int minithread_context_switch(int add_to_ready, int switch_to_idle)
{
	minithread_t tcb;
	stack_pointer_t* old_stack_top;

	interrupt_level_t prev_level = set_interrupt_level(DISABLED);

	// Add it to the ready queue if needed
	if (add_to_ready == 1 && running != idle)
	{
		minithread_add_to_ready_queue(running, 0);
	}

	// get the new thread
	tcb = minithread_get_from_ready_queue(0);

	// why context switch to the running thread, we can just let it continue...
	if (tcb == running)
	{
		set_interrupt_level(prev_level);
		return -1;		
	}

	// if there's no thread to switch to and we don't want the idle thread...
	if (tcb == NULL && switch_to_idle == 0)
	{
		set_interrupt_level(prev_level);
		return -2;
	}
	 else if (tcb == NULL)
	{
		tcb = idle;
	}


	// Otherwise, set the running thread variable
	old_stack_top = running->stack_top;
	running = tcb;

	// Update the number of ticks until the next switch
	ticks_until_switch = minithread_get_priority_quanta(tcb->priority);

	// Perform the context switch
	minithread_switch(old_stack_top, tcb->stack_top);

	// Context switch threads will handle re-enabling interrupts, but still...
	set_interrupt_level(prev_level);
	
	return 1;
}
/*
 * Scheduler
 */
int minithread_schedule() {
	minithread_t old = current;
	if ( alarm_has_ready() && old != idle ) {
		current = idle;
	} else if(multilevel_queue_length(ready_queue)>0) {
		minithread_age(ready_queue);
		multilevel_queue_dequeue(ready_queue, PRIORITY_SHORT, &current);
	} else {
		current = idle;
	}

	if ( current->priority == PRIORITY_SHORT ) {
		current_quanta_end = ticks + SHORT_QUANTA;
	} else {
		current_quanta_end = ticks + LONG_QUANTA;
	}
	minithread_switch(&(old->sp), &(current->sp));
	return 0;
}
示例#8
0
static int final_proc(int *arg) {
  interrupt_level_t old_level = set_interrupt_level(DISABLED);
  // switch to the reaper thread after completion of a thread
  // if the running thread is already reaper, switch to the next runnable thread
  // reaper thread will free the elements of stopped queue which contains all finished threads.
  if (running_thread != reaper_thread) {
    queue_append(stopped_queue, running_thread);
  }
  if (queue_length(stopped_queue)) {
    minithread_t *temp = running_thread;
    running_thread = reaper_thread;
    minithread_switch(&temp->top, &reaper_thread->top);
  }
  else {
    stop_running_thread();
  }
  set_interrupt_level(old_level);
  return 0;  
}
示例#9
0
void minithread_yield() {
  interrupt_level_t old_level = set_interrupt_level(DISABLED); 
  if (multilevel_queue_total_elements(schedule_data->multi_run_queue) == 0) {
    set_interrupt_level(old_level);
    return;
  }

  minithread_t* old = schedule_data->running_thread;
  old->status = RUNNABLE;

  //adds itself to the end of the run queue
  multilevel_queue_enqueue(schedule_data->multi_run_queue, old->level, old);

  //yields to the next minithread in the run_queue
  minithread_t* next = next_runnable();
  next->status = RUNNING;
  schedule_data->running_thread = next;
  minithread_switch(&old->stacktop, &next->stacktop);
}