In this lecture, we will learn how to shift the state of a process between sleep and active,
which can be done by the scheduling.
So let's take a look.
Suppose we are at process 1 and the handler is called,
we decide to put the process in sleep state. Then we call the scheduler to select process 2.
And then the process 3. After the time for the process 3 is up, the process 2 is selected again.
Because process 1 is not active, we will not run it until it becomes active again
.
Ok let’s open the project. In the process file,
we add function sleep and wake up.
Notice that we have
parameters in these two functions. So the process can be in sleep state or waken up for various reasons
.
In the header file,
we add wait field to save the info as to why the process is put into sleep and how to wake it up.
The new list wait list is used to save the waiting processes in the list.
Let's go back to the process.c file.
In the sleep function, what we are going to do first is we are going to get the data process control
and retrieve the current process which is the one we will put to sleep.
So we change the state to proc sleep and save the reason in wait field.
Then we append the process in the wait list. If we don’t wake it up,
this process will not be active after we call scheduler.
This is because the process is saved in the wait list now. The scheduler is always selecting the process
in the ready list.
Next we call the scheduler to select other process.
That’s it for sleep function.
After we talk about process sleep. The function wake up is simple.
All we need to do is find the correct process in the wait list and remove it from the list,
then append it to the ready list waiting for scheduling. As you see, we retrieve both ready list and wait list from process control.
Remove the process from the wait list and the wait is passed to the function
so that we can find the correct process.
Generally, we could have multiple processes waiting on the same object.
So here the while loop is used to find all the waiting processes in the list.
If we find one, we will change the state to proc ready and append it to the ready list.
It’s worth mentioning that io requests could be added at the head of the list. Because if these requests
such as key press is pending too long, computer will feel laggy.
For simplicity, we just append it to the tail of the list as we did with other processes.
The remove list is a new function, so let’s see the implementation in the lib.c file.
In this function, we just find the process with wait and remove it from the list.
Here we use two pointers, the current which points to the current element we are at,
the previous which points to the previous element.
At first, we assign the first element to the current, and the headlist to the previous.
The item saves the process being returned. We initialized it with null.
Then we use while loop to loop through each of the elements in the list.
Remember the first element in the process structure is structure list.
So we can retrieve the wait from the list,
if it is not the one we want, we will go to next item.
We move the previous to the next one by saving current to it and current is assigned with
the address of next element. Then we continue the loop.
If the wait is the one we want, the next thing we will do is remove it from the list which is simple,
all we need to do is assign the address of next item pointed to by the current to the next field of previous.
Then we save it in the item.
Before we return item to the caller, we also need to check the current list. If the list is empty
which means the head points to null, we just point the tail to null as well.
If there are elements in the list but the item we get is the last one in the list,
we will point the tail to the previous.
After these checks, we can break the loop and return the item.
Ok, in this example, we just test our project based on the user program in the last lecture.
So we add sleep function in the system call module so that we can use it in the user mode.
As you can see, we add function sys sleep for this request. Since we have two functions now, we change the checks
to allow i to have two values 0 and 1.
Now let’s focus on sys sleep function.
The first thing we are going to do in this function is we are going to get current ticks by function get ticks
.
The ticks is incremented since the timer is working.
We will see that in a minute.
Then we copy it to the old ticks.
Ok now we can compare the ticks with old ticks to see how long we have been waiting for.
The sleep ticks is the duration we pass from the user programs.
Then we get to sleep.
You see, we pass -1 to sleep. In this system, -1 represents waiting for ticks.
Right after wakening up from sleep, we call get ticks to get the current ticks and check the sleep ticks again.
If the result is smaller than sleep ticks, we will sleep again.
Alright,
let’s see the function get ticks
which is implemented in the trap.c file.
As you see, ticks is defined here
and get ticks function just return the value of ticks.
In the timer interrupt case, we call timer handler function which increments ticks and wake up the processes waiting for ticks
.
So what it does here is waking up processes every 10ms, since timer interrupt is fired every 10ms
.
The argument is -1 so it will find the processes with member wait being 1 and wake them up.
Also, don’t forget to add get ticks function in the header file.
OK, the kernel part is done.
Let's go to user part.
In this lecture, we will use user2 program to do the test.
Since we add a new system call function sys sleep, we will rebuild the library module to add the system call function
.
So in the syscall file,
we added sleepu function.
This function takes one parameter which is the duration.
So we allocate 8 bytes on the stack.
The index number is 1 for sleep in the kernel.
Next we copy the argument to the allocated space on the stack.
And save the number of arguments,
1 in this case to rdi
and save the address of arguments to rsi.
Then we can int 80.
After we return, we restore the stack by adding 8 to rsp register
and return
Global sleepu and we are done.
Ok
We navigate to the folder user2.
and assemble syscall module
and add it to the library file.
Ok one thing left to do is calling sleepu function in main.c file.
At this point, we can get rid of the if statement
and pause for a while by sleepu.
Remember timer interrupt is fired every 10ms.
So here we pass 100 which is roughly 1 second. Ok we should see it printed on the screen every 1 second.
We add the declaration in the lib.h file.
Let’s build the project.
And copy it in the boot folder.
Then we build the kernel project.
Ok, let’s test it out.
As you can see, the process1 and process2 are printed on screen.
That's it for this lecture.
See you in the next video.