void test_length() { multilevel_queue_t q1; void *p; int i1 = 0; int i2 = 0; // Test null queue assert(multilevel_queue_length(NULL) == -1); // Test queues q1 = multilevel_queue_new(2); assert(multilevel_queue_length(q1) == 0); assert(multilevel_queue_enqueue(q1, 1, &i1) == 0); assert(multilevel_queue_length(q1) == 1); assert(multilevel_queue_enqueue(q1, 1, &i2) == 0); assert(multilevel_queue_length(q1) == 2); assert(multilevel_queue_enqueue(q1, 0, &i1) == 0); assert(multilevel_queue_length(q1) == 3); assert(multilevel_queue_enqueue(q1, 0, &i2) == 0); assert(multilevel_queue_length(q1) == 4); assert(multilevel_queue_dequeue(q1, 0, &p) == 0); assert(multilevel_queue_length(q1) == 3); assert(multilevel_queue_dequeue(q1, 0, &p) == 0); assert(multilevel_queue_length(q1) == 2); assert(multilevel_queue_dequeue(q1, 1, &p) == 1); assert(multilevel_queue_dequeue(q1, 1, &p) == 1); assert(multilevel_queue_length(q1) == 0); assert(multilevel_queue_free(q1) == 0); }
void test_enqueue() { multilevel_queue_t q; int x1 = 5; int x2 = 6; int x3 = 7; void *value = NULL; // Testing null queue assert(multilevel_queue_enqueue(NULL, 0, &x1) == -1); // Testing queue q = multilevel_queue_new(4); assert(multilevel_queue_enqueue(q, 6, &x2) == -1); assert(multilevel_queue_enqueue(q, 2, &x1) == 0); assert(multilevel_queue_length(q) == 1); assert(multilevel_queue_enqueue(q, 1, &x2) == 0); assert(multilevel_queue_length(q) == 2); assert(multilevel_queue_enqueue(q, 3, &x3) == 0); assert(multilevel_queue_length(q) == 3); assert(multilevel_queue_dequeue(q, 2, (&value)) == 2); assert(*((int*) value) == x1); assert(multilevel_queue_dequeue(q, 3, (&value)) == 3); assert(*((int*) value) == x3); assert(multilevel_queue_dequeue(q, 1, (&value)) == 1); assert(*((int*) value) == x2); assert(multilevel_queue_length(q) == 0); assert(multilevel_queue_free(q) == 0); }
minithread_t minithread_get_from_ready_queue(int disable_interrupts) { // ISO C90... minithread_t tcb; interrupt_level_t prev_level; int ret; // Disable interrupts as we're going to access the ready queue / ready_threads if (disable_interrupts == 1) { prev_level = set_interrupt_level(DISABLED); } // If there are threads, get the next one ret = multilevel_queue_dequeue(ready_queue, current_level, (void**) &tcb); // If there was an error, ensure the tcb we return is NULL if (ret == -1) { tcb = NULL; } else { // Otherwise tcb stays as the new thread; decrement ready_threads ready_threads--; } // Restore the interrupt level if (disable_interrupts == 1) set_interrupt_level(prev_level); return tcb; }
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; }
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); } }
// Store NUM_TOTAL_ELEMENTS in level 0, // dequeue and make sure level is always 0 // and proper elements returned. void test1() { printf("Beginning test 1.\n"); multilevel_queue_t ml_q = multilevel_queue_new(NUM_LEVELS); int i; for (i = 0; i < NUM_TOTAL_ELEMENTS; i++) { int *int_ptr = (int *)malloc(sizeof(int)); *int_ptr = i; multilevel_queue_enqueue(ml_q, 0, int_ptr); } int **int_ptr_ptr = (int **)malloc(sizeof(int *)); int level_found_on; for (i = 0; i < NUM_TOTAL_ELEMENTS; i++) { level_found_on = multilevel_queue_dequeue(ml_q, 0, (void **)int_ptr_ptr); assert(level_found_on == 0); assert(**int_ptr_ptr == i); free(*int_ptr_ptr); } free(int_ptr_ptr); multilevel_queue_free(ml_q); printf("Test 1 passed.\n"); }
/* * Thread Age - function that is used to promote threads * of a certain age to the next priority level, which * ensures that lower priority threads still get a chance * to use the CPU even when there are many high priority * threads */ int minithread_age(multilevel_queue_t queue) { minithread_t thread = NULL; multilevel_queue_peak(queue, PRIORITY_LONG, (any_t*)&thread); while( thread && ((ticks - thread->age) >= PROMOTE_AGE) ) { multilevel_queue_dequeue(queue, PRIORITY_LONG, (any_t*)&thread); // reset priority but age stays the same thread->priority = PRIORITY_SHORT; multilevel_queue_enqueue(queue, PRIORITY_SHORT, thread); multilevel_queue_peak(queue, PRIORITY_LONG, (any_t*)&thread); } return 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); } }
/* get the next RUNNABLE minithread from the run_queue. Waits otherwise. */ minithread_t* next_runnable() { void* temp; int count = 0; while(1) { if (multilevel_queue_size(schedule_data->multi_run_queue, (queue_level + count) % 4) > 0) { interrupt_level_t old_level = set_interrupt_level(DISABLED); int response = multilevel_queue_dequeue(schedule_data->multi_run_queue, (queue_level + count) % 4, &temp); set_interrupt_level(old_level); if (response == 0) { return temp; } } else { count = (count + 1) % 4; //looks into the next queue } } }
/* * 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, ¤t); } 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; }
// Store NUM_TOTAL_ELEMENTS evenly dispersed // across levels 0-4. Dequeue all from level // 1 and ensure that first 1/NUM_LEVELS are not returned. void test3() { printf("Beginning test 3.\n"); multilevel_queue_t ml_q = multilevel_queue_new(NUM_LEVELS); int i; int j; int level_fraction = NUM_TOTAL_ELEMENTS / NUM_LEVELS; for (i = 1; i <= NUM_LEVELS; i++) { for (j = i * level_fraction; j < (i+1) * level_fraction; j++) { int *int_ptr = (int *)malloc(sizeof(int)); *int_ptr = j; multilevel_queue_enqueue(ml_q, i, int_ptr); } } int **int_ptr_ptr = (int **)malloc(sizeof(int *)); int level_found_on; for (i = 0; i<= NUM_LEVELS; i++) { for (j = i * level_fraction; j < (i-1) * level_fraction; j++) { level_found_on = multilevel_queue_dequeue(ml_q, 1, (void **)int_ptr_ptr); if (j > level_fraction * (NUM_LEVELS - 1)/NUM_LEVELS) { assert(level_found_on == -1); } else { assert(level_found_on == i+1); assert(**int_ptr_ptr == j + level_fraction); free(*int_ptr_ptr); } } } free(int_ptr_ptr); multilevel_queue_free(ml_q); printf("Test 3 passed.\n"); }