P2 – Process Scheduling Project
Overview
In this project, you will be changing the process scheduler in Bionic Beaver. The new scheduler will implement four Major Levels of queuing for processes. These queues will correspond to the four levels in the tags that you associated with processes in Project 1. Each Major Level L will be allocated some amount of time to run on the CPU. The scheduler will use a Round Robin-like scheduling algorithm to allocate time to each Major Level. When CPU is assigned to a Major Level L, only processes of that Major Level (processes with the tag level L) can compete for CPU time (and only if they are ready). If there are no processes in a Major Level, then the system will run an idle process to use up the time allocated to that major level.
The sum of the allocation times for the four levels determines the round robin cycle time for the user processes, and the time given to a level divided by this total cycle time gives the fraction of CPU time that each level gets.
RRTime = Σ(Allocation Time)
CPUTime = (Level Time)i / RRTime
You will introduce system calls and library wrapper functions to obtain the amount of time allocated to a Major Level (any user can call), and to change the amount of time allocated to a Major Level (restricted to root). These you will document with manual pages. You will then create a short video to demonstrate your code and submit the project via Canvas.
NOTE: Take Snapshots in VirtualBox! You will most likely brick your machine at some point during this or other projects, and you will not want to start from scratch. No, seriously – take snapshots!
Background
In systems that enforce Mandatory Access Control (MAC), access control decisions are not only based on what the owner of a file (or other object) decides but are also based on labels attached to processes and other objects. These labels can only be changed in limited ways by a regular user, and the system typically enforces a policy that limits information to flow in one direction (from less sensitive to more sensitive, but not the other way).
Structure
The project is broken into five main parts:
Change the CPU scheduler to enforce strict allocations per Major Level. The entire time allocated to a Major Level must be consumed by processes at that level or by an idle
Create system calls that allow a process to “get” or “set” an allocation for a Major
Create system library wrapper functions that allow the system calls to be invoked from a C
Add manual page entries for the system calls and the C library
Create a report and a short screencast to explain what you
While exact implementation may vary, the library functions must match the signatures laid out in this document, the system calls must get and set allocation levels properly, and the CPU scheduler must enforce the strict Major Level allocations correctly.
Process Scheduling
Each process in the modified system will have a 32-bit tag from Project 1. Recall that a tag has a structure of two bits of level (the two LSBs, bits 0 and 1) and 29 bits of bitmap (bits 2 through 30). The MSB (bit 31) shall be set to 0 always. Level values range from zero (low) to three (high). Treated as an unsigned integer, tags can take values between 0 and 231-1. Tags for this system behave as specified in Project 1.
The Process Scheduler currently has some means of prioritizing processes and schedules them according to this policy. You may find some of these provided to you below.
You will replicate this mechanism to work for four major levels of processes, corresponding to the four levels a process tag may hold (The Major Level L). Each level L will have an allocation in milliseconds, with an initial allocation of 10ms for each level (always initial value on booting up). You will add another layer onto process scheduling “above” the methods currently used by Bionic Beaver so that:
Each level is allocated the CPU time with the corresponding allocation time for that level.
Only processes whose tag holds a level = to the level that currently has the CPU can compete for the CPU -- and only if that level holds the
Processes within a level are scheduled as before and may be given a quantum of time on the CPU. If the process uses all its quantum, then it may be preempted by another process at the same level. If a process blocks for whatever reason, then only another process at the current level (the level that has the CPU) may replace it. When it unblocks, it can only rejoin the processes at its level to compete with them for the CPU when that level has the CPU. If there are no processes at the current level, then no processes from another level can be run until the time allocated to the current level is exhausted.
When the allocation for a level has been exhausted, the current process (if any) is preempted and the CPU is given to the next level. If a process at the current level was preempted due to the level allocation time ending before its quantum within the level was exhausted, the system remembers the amount of time the preempted process has left of its quantum within its level. When its level obtains the CPU again, and that process is
scheduled (not necessarily first among its competitors at the same major level), it will resume with the amount of time it had left from when it was preempted.
System Call
Each of the four levels in the modified system will have an allocation in milliseconds, which determines the amount of time a level has the CPU when the scheduler runs that level. This allocation can only be changed by a process with root access, but the allocation for any level may be read by any process.
The sum of the allocations determines the cycle time for all the levels to obtain the CPU and cannot be less than 5ms. However, the allocation for a given level may be less than 5ms., including 0ms. (i.e., processes at that level get no CPU time).
You will create kernel system calls named get_level_alloc and set_level_alloc. These will allow the allocation for a given level to be obtained or modified, respectively. Other aspects of their signatures may vary. The system calls are invoked from user space via syscall(call_number, param1, param2). Your system call must be limited to no more than two parameters!
All of your code modifications must include appropriate comments wherever changes are made including your name and the date. Your code as always should adhere to good practices, including no manifest constants, good identifier naming, and modularity.
Static Library
As in Project 1, you will create a static library that provides an API to invoke the system calls in a directory named tags. This will be composed of headers files with name tags.h and harness.h and a static library file named libtags.a. You will also need to provide a Makefile for this library in the tags directory. All other sources must be contained within the tags directory. Please note, the names of these files must match exactly!
You will create a tarred gzip file of the tags directory with name tags.tar.gz. When testing your code, we will decompress the archive, enter the tags directory, and build the library. All functions enumerated below must be made available by including "tags.h" or "harness.h". See Submission for details.
In addition to the standard library functions, you will implement testing harness functions. The testing harness functions are used to verify the system calls from the system library (and are required for full credit on this assignment). We will call these functions to retrieve the information needed to make a system call. We will then call the system call within our own program. This ensures that the implementation is not being done in the user-level library.
Library Functions
These functions provide primary functionality to user programs. They should be made available by including <tags.h>. For both functions, level must be between 0 and 3. Allocation must be non-negative and must not cause the cycle time to be under 5 ms.
int set_alloc(int level, int new_allocation)
invokes system call which attempts to change the allocation of the level identified by level to the new allocation value new_allocation in milliseconds. Returns new_allocation on success, and -1 otherwise, with errno set to an unused value you will document to explain the failure. More information about errno is provided at the end.
int get_alloc(int level)
invokes system call which reads the allocation of the level identified by level. Returns the allocation in milliseconds for that level on success, and -1 otherwise, with errno set to an unused value you will document to explain the failure.
Harness Functions
These functions serve as a testing harness to verify the system calls and are required for full credit on this assignment. They shall be made available by including <harness.h>.
System call parameter retrieval data shall be returned as a pointer to an int array of 2-4 values that can be used to make the system call. The array has this format:
{ call_number, num_parameters [, parameter1] [, parameter2] }
e.g.: { 42, 2, 867, 5309 } → syscall(42, 867, 5309)
int* retrieve_set_alloc_params(int level, int new_alloc)
Returns an int array of 2-4 values that can be used to make the set_level_alloc system call.
int* retrieve_get_alloc_params(int level)
Returns an int array of 2-4 values that can be used to make the get_level_alloc system call.
int interpret_set_alloc_result(int ret_value)
After making the system call, we will pass the syscall return value to this function call. It should return set_alloc’s interpretation of the system call completing with return value ret_value (i.e., the return value of this function is what the library call should return to the user program when the system call returns a value of ret_value).
int interpret_get_alloc_result(int ret_value)
After making the system call, we will pass the syscall return value to this function call. It should return get_alloc’s interpretation of the system call completing with return value ret_value (i.e., the return value of this function is what the library call should return to the user program when the system call returns a value of ret_value).
Manual Pages
You are required to create manual pages detailing the two system calls and the two wrapper library functions, but not the four harness function calls. These manual pages shall be in man page format and in the appropriate manual section; you may copy and modify an existing man page for this purpose.
You should “double up” on the man pages by creating a single man page that handles two or more related calls (i.e., the two kernel system calls and the two library calls for both get_alloc and set_alloc) as before. This can be accomplished by including all calls in the page, saving with the name of one of the calls, then making a hard link for the other call’s man page (e.g., if you created get_alloc.3, then ln get_alloc.3 set_alloc.3 will allow that file to be accessed as either get_alloc.3 or set_alloc.3 – see for example fopen(3)). This way, you can create two manual pages instead of four. This also makes maintenance much easier.
You should place these man pages in your tags directory. Running make from your tags directory should place each new man page in the proper location so that entering the command man <S> set_alloc or man
<S> get_alloc will return the man page for these calls in section <S>. You may check the manual path
using the manpath(1) command to see where the man pages are, and type "man man" to see how the sections are arranged. At a minimum, the man page must have proper header/footer, name, synopsis, description, errors, notes, see also, and author.
Testing
You should test your code for all behavioral cases. You will include this information in your report and demonstrate the tests in your screencast video. We will provide some limited test functions, but you must devise additional tests to completely test your implementation. You must also test that all your man pages display properly.
DescriptionIn this final assignment, the students will demonstrate their ability to apply two ma
Path finding involves finding a path from A to B. Typically we want the path to have certain properties,such as being the shortest or to avoid going t
Develop a program to emulate a purchase transaction at a retail store. Thisprogram will have two classes, a LineItem class and a Transaction class. Th
1 Project 1 Introduction - the SeaPort Project series For this set of projects for the course, we wish to simulate some of the aspects of a number of
1 Project 2 Introduction - the SeaPort Project series For this set of projects for the course, we wish to simulate some of the aspects of a number of