Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
BrickOS Scheduling Solving The Low-Priority Starvation Problem Introduction Jon Rogers Robbie Edwards Melanie Sparks Project Description Investigate the way the scheduling algorithm is currently implemented. Change it so that higher priority processes cannot starve the low priority processes. Project Facets 1 Researching the problem 2 Defining a solution 3 Building a development environment 4 Modifying the source code 5 Testing and verification Researching The Problem Research the operating system scheduler Identify the relevant source code Determine the current scheduling implementation Researching The Problem Results BrickOS employs a preemptive scheduler with a prioritized round-robin algorithm for choosing the next process to run. Researching The Problem Detailed Results Each process is given a default time slice of 20ms to run before being interrupted by the OS and another process is allowed to run In choosing the next process to run, the OS searches through each process queue, beginning with the highest priority queue, and runs the first READY process Hence The Problem If there are always processes of higher priority that are ready to run, lower priority processes will be starved out Defining A Solution The Challenge: to prevent starvation while preserving process priority The Solution: Chain Wait, another selection parameter Chain Wait will numerically represent the maximum number of scheduler executions for which a particular priority chain will be exempt (e.g. no processes from this priority chain will be chosen: waiting) The Algorithm Initialization: All chain wait values will be set to zero Scheduler will do a linear search through the priority chains for runnable processes Upon running a process, the chain wait for its priority queue will be set to 20-P+1, where P is the numeric priority and scheduler will resume its linear search The Algorithm For each priority queue with a chain wait greater than zero, decrement the chain wait and move to the next queue ignoring ready processes from this queue If the linear search is complete and no runnable processes are found, all chain waits are reset to 0 Building A Development Environment Installation of Cygwin on the target Windows machine Building the Hitachi-H8 cross-compiler : a trivial initialization followed by a very long compile process Installing BrickOS Installing the USB tower and drivers Testing the environment : Hello World and Play Song Testing the environment, part II : creating a test program that counts down and plays a song Changing The Source Code – Additions To tm.h Implementation begins with adding a new function, "tm_clear_waits()", that will (as advertised) clear the chain waits, resetting them to zero. void tm_clear_waits() { pchain_t* priority; priority = priority_head; while((int) priority->priority >= PRIO_LOWEST) { priority->chain_wait = 0; priority = priority->next; } } Changing The Source Code – Additions To tm.c Implementation of the solution continues with the introduction of a new field, an integer "chain_wait", to the existing data structure struct _pchain_t, in the tm.h header file struct _pchain_t { priority_t priority; // numeric priority level struct _pchain_t *next; // lower priority chain struct _pchain_t *prev; // higher priority chain struct _tdata_t *ctid; // current task in chain int chain_wait; // # of times to be ignored by scheduler }; Changing The Source Code Changes To tm.c We modified tm.c inside the function "size_t *tm_scheduler(size_t *old_sp)" at the point where the next process must be chosen This scheduler function is called by the process switcher which in turn is called by a yield function Yield is called by an function that becomes a zombie [through "exit(..)"], when a process has used its timeslice [through systime_handler(..)], or when a process sleeps [through wait_event(..)]. Original Code The original code, in which we will choose the next process.. while(1) { if(next->tstate==T_SLEEPING) break; if(next->tstate==T_WAITING) { ... break; } } if(next == priority->ctid) { ... priority = priority->next; ... next=priority->ctid->next; } else next=next->next; } // if the next task is SLEEPING // we just run it // if it's WAITING, wake it and run it // if done searching this priority queue // search the next priority queue // move to the next one in line in that priority // otherwise we're still searching this queue New Code Inside the while loop that searches for the next process, the code is modified as follows: while(1) { // If there is a chain wait for this priority level // then decrement the wait. if(priority->chain_wait > 0) { --(priority->chain_wait); if(priority->next != NULL) { if((int) priority->next->priority < PRIO_LOWEST) { } // If we have ignored the lowest priority level tm_clear_waits(); // then clear all chain waits and begin the priority=priority_head; // search for a process again at the highest next=priority->ctid->next; // priority level. New Code else { priority = priority->next; // Otherwise, next = priority->ctid->next; } //search the next priority level. } ... ... } // debugging code omitted else priority = priority_head; New Code else { // if the next task is SLEEPING, break; // we just run it if(next->tstate==T_WAITING) { // if it's WAITING if(next->tstate==T_SLEEPING) ... break; // wake it and run it } // sound familiar? ... // the remainder of the code // inside the while loop is unmodified } } Changing The Source Code Upon exiting the while loop that selects the next process to run, set the process' priority level's chain wait. priority->chain_wait = ((int) PRIO_HIGHEST - (int) priority->priority) + 1; For example, if PRIO_HIGHEST is 20 and the process to be executed is of priority 10, then the chain wait for priority level 10 will be set to (2010)+1 = 11. Changing The Source Code And the last bit of code added, within the process "tid_t execi(..)" upon initializing a new priority queue the chain_wait must also be set ... newpchain->priority=priority; newpchain->chain_wait = 0; // initialize chain_wait to 0 newpchain->ctid=td; ... Testing And Verification Loading the new operating system Documenting the lack of starvation Showing that all threads run no matter the priority Testing And Verification - Code The test program: gizmo.c pid2=execi(&motor_driver, 0, NULL, 20, DEFAULT_STACK_SIZE); pid3=execi(&foo1, 0, NULL, 20, DEFAULT_STACK_SIZE); pid4=execi(&foo2, 0, NULL, 20, DEFAULT_STACK_SIZE); pid5=execi(&foo3, 0, NULL, 10, DEFAULT_STACK_SIZE); Testing And Verification - Code In the old brickOS, this process would have been starved out. But not in ours. pid6=execi(&playSong, 0, NULL, 1, DEFAULT_STACK_SIZE); You know the scheduler is working correctly when you hear the song playing. Testing And Verification Results The song played repeatedly, indicating that the forked process with priority zero was not starved out by the higher priority processes. All processes were shown to have been scheduled. Thank You And Good Night