Hello, dear friend, you can consult us at any time if you have any questions, add WeChat: daixieit

Lab 3 - EECS 211

Basics of Context Switching and Scheduling

Winter 2024

Implement a Simple Scheduler

In this problem, we are going to implement a simple OS scheduler. This OS scheduler will cycle through available processes, executing or resuming them from their ready or yield states, respec-tively, until all have finished.

To simplify the implementation, we will make the following assumptions. First, the maximum number of processes that can be loaded in the memory is equal to 3. The OS will keep track of the state of each process using the three status variables (state1, state2, state3). These variables can have three different values depending on their status. A value of 0 means that the corresponding process is ready to run, a value of 2 means that this process is in the yield state, and a value of 1 means that the process has terminated.

The scheduler begins by invoking the trap handler, then sequentially checks the state variables mentioned above. Once it finds a process that is ready to execute or in the yield state, it will jump to the corresponding line of code in the process. When the process yields (by using the yield () function), the OS will change the status of this process to 2 (yield) and make another ecall to go back to the entry of the trap handling procedure. Similarly, when the process exits (by using the exit () function, see the template stdlib .h), the OS will change the status of this process to 1 (terminated). If no process needs to run, then the scheduler will enter an infinite loop.

The main body of this simple OS (where the CPU starts executing) needs to initialize the values in the state variables, determine which process should be executed next, and set the starting address of the process to be executed next. If there are both ready state and yield state processes, the ready state processes are prioritized for execution first.

Template Code

The goal of this lab is to implement the yield functionality of the processes. The template code only supports exit functionality, and the process cannot stop its execution in the middle of the task with the current implementation. In order to support it, you need to add the yield () function and some logic to check the process states in the scheduler. Note that when resuming a process from the yield state, you need to start execution at the next line of code that was executed before it yields.

The template code consists of source codes in the mix of C and assembly. As we did in the previous discussion, you can use C functions in assembly and assembly instructions in C. The overall workflow of the template is as follows.

1. main.c initializes some functions and makes a ecall to enter the scheduling

2. trap entry.s stores current register values into the stack and jumps to the trap handler

3. trap.c calls the scheduler (In general, many different procedures are defined here and called depending on the reason for the interrupt)

4. scheduler.c determines which process to execute next and sets the starting address of the process in mepc

5. return to the trap entry.s to load back the register values and jump to the address by mret that is set in the previous step

6. execute the process and then yield/exit it

7. go back to step 2 and repeat the flow until all the processes are terminated

You have TODOs in the following files, so you can implement the yield functionality by simply filling them out.

• scheduler.c

• processes.c

• stdlib .h

Deliverable

The code template is given on Canvas. Implement the scheduler described above to switch between these three processes. You will upload one zip file that contains (1) the code template folder after filling out your implementation, (2) a PDF report that has a brief explanation of your implemen-tation and a screenshot of the terminal output displaying all the process executing messages.

The execution order will be the following.

1. Process1 starts running, prints a message, and then yields

2. Process2 starts running, prints a message, and then yields

3. Process3 starts running, prints a message, and then yields

4. Process1 resumes from the point that is yielded, prints a message, and then exits

5. Process2 resumes from the point that is yielded, prints a message, and then exits

6. Process3 resumes from the point that is yielded, prints a message, and then exits

7. Print a message to tell that all the processes finished the execution