#include #include #include #include #include "schedule.h" #include "mem_alloc.h" /* This file contains a bare bones skeleton for the scheduler function for the second assignment for the OSN course of the 2005 fall semester. Author: G.D. van Albada Section Computational Science Universiteit van Amsterdam Date: October 23, 2003 Modified: September 29, 2005 */ /* This variable will simulate the allocatable memory */ static long memory[MEM_SIZE]; /* Data used by the scheduler */ struct sched_data { unsigned char priority; }; static struct student_pcb *last_scheduled_process = NULL; bool queue_contains(struct student_pcb* queue_head, struct student_pcb *proc) { if (!queue_head) return false; do { if (queue_head == proc) return true; } while ((queue_head = queue_head->next)); return false; } struct sched_data* get_or_create_userdata(struct student_pcb* proc) { if (proc->userdata) return proc->userdata; proc->userdata = calloc(1, sizeof(struct sched_data)); return proc->userdata; } /* The actual CPU scheduler is implemented here */ static void cpu_scheduler() { /* As a priority-based scheduler, we implement a variant of the * multilevel feedback queue described at * https://en.wikipedia.org/wiki/Multilevel_feedback_queue * * Differences are mostly in intra-queue ordering, and there are * potentially small differences when it comes to priority reduction. */ struct student_pcb *proc = ready_proc; /* If there are no processes to schedule, don't schedule any. */ if (!proc) return; struct sched_data* userdata; /* If we've scheduled a process in the past, check whether it is finished. * If not, reduce its priority. */ if (last_scheduled_process) { if (queue_contains(ready_proc, last_scheduled_process)) { userdata = get_or_create_userdata(last_scheduled_process); if (userdata->priority < 255) userdata->priority++; } if (queue_contains(io_proc, last_scheduled_process)) { userdata = get_or_create_userdata(last_scheduled_process); // Promote IO-bound processes. if (userdata->priority > 0) userdata->priority--; } } int max_priority = 255; struct student_pcb *max_priority_process; do { userdata = get_or_create_userdata(proc); if (userdata->priority < max_priority) { max_priority = userdata->priority; max_priority_process = proc; } } while ((proc = proc->next)); /* This remove-and-prepend behavior automatically causes queue rotation. */ queue_remove(&ready_proc, max_priority_process); queue_prepend(&ready_proc, max_priority_process); set_slice(pow(2, max_priority)); last_scheduled_process = max_priority_process; } /* The high-level memory allocation scheduler is implemented here */ /* Defined in simul2018.c */ extern int N_TRY; static void give_memory() { int index; student_pcb *proc = new_proc; bool try_counter_started = false; int tries_left = N_TRY; if (!proc->userdata) { proc->userdata = calloc(1, sizeof (struct sched_data)); } while ((proc = proc->next)) { index = mem_get(proc->mem_need); if (index >= 0) { // Allocation succeeded. Set the base address, and put the // process in the ready queue. proc->mem_base = index; queue_remove(&new_proc, proc); queue_append(&ready_proc, proc); } else { // Allocation failed. Try N_try more processes before exiting. try_counter_started = true; } if (try_counter_started && tries_left--) break; } } /* Here we reclaim the memory of a process after it has finished */ static void reclaim_memory() { student_pcb *proc; proc = defunct_proc; while (proc) { /* Free your own administrative structure if it exists */ if (proc->userdata) { free(proc->userdata); } /* Free the simulated allocated memory */ mem_free(proc->mem_base); proc->mem_base = -1; /* Call the function that cleans up the simulated process */ rm_process(&proc); /* See if there are more processes to be removed */ proc = defunct_proc; } } /* You may want to have the last word... */ static void my_finale() { /* Your very own code goes here */ } /* The main scheduling routine */ void schedule(event_type event) { static int first = 1; if (first) { mem_init(memory); finale = my_finale; first = 0; /* Add your own initialisation code here */ } switch (event) { /* You may want to do this differently */ case NEW_PROCESS_EVENT: give_memory(); break; case TIME_EVENT: case IO_EVENT: cpu_scheduler(); break; case READY_EVENT: break; case FINISH_EVENT: reclaim_memory(); give_memory(); cpu_scheduler(); break; default: printf("I cannot handle event nr. %d\n", event); break; } }