1 00:00:01,010 --> 00:00:07,610 In this lecture, we will learn how to shift the state of a process between sleep and active, 2 00:00:07,610 --> 00:00:08,970 which can be done by the scheduling. 3 00:00:09,680 --> 00:00:10,670 So let's take a look. 4 00:00:11,150 --> 00:00:15,650 Suppose we are at process 1 and the handler is called, 5 00:00:16,760 --> 00:00:24,400 we decide to put the process in sleep state. Then we call the scheduler to select process 2. 6 00:00:24,410 --> 00:00:29,900 And then the process 3. After the time for the process 3 is up, the process 2 is selected again. 7 00:00:29,900 --> 00:00:36,560 Because process 1 is not active, we will not run it until it becomes active again 8 00:00:36,560 --> 00:00:37,430 . 9 00:00:39,170 --> 00:00:43,010 Ok let’s open the project. In the process file, 10 00:00:44,950 --> 00:00:47,200 we add function sleep and wake up. 11 00:00:48,650 --> 00:00:50,090 Notice that we have 12 00:00:51,660 --> 00:00:58,290 parameters in these two functions. So the process can be in sleep state or waken up for various reasons 13 00:00:58,290 --> 00:00:58,880 . 14 00:01:00,300 --> 00:01:01,440 In the header file, 15 00:01:03,260 --> 00:01:09,770 we add wait field to save the info as to why the process is put into sleep and how to wake it up. 16 00:01:12,300 --> 00:01:17,400 The new list wait list is used to save the waiting processes in the list. 17 00:01:18,420 --> 00:01:20,610 Let's go back to the process.c file. 18 00:01:22,550 --> 00:01:28,190 In the sleep function, what we are going to do first is we are going to get the data process control 19 00:01:28,610 --> 00:01:32,350 and retrieve the current process which is the one we will put to sleep. 20 00:01:33,080 --> 00:01:37,280 So we change the state to proc sleep and save the reason in wait field. 21 00:01:38,250 --> 00:01:42,160 Then we append the process in the wait list. If we don’t wake it up, 22 00:01:42,310 --> 00:01:45,310 this process will not be active after we call scheduler. 23 00:01:46,230 --> 00:01:51,630 This is because the process is saved in the wait list now. The scheduler is always selecting the process 24 00:01:51,630 --> 00:01:53,060 in the ready list. 25 00:01:54,100 --> 00:01:58,090 Next we call the scheduler to select other process. 26 00:01:59,110 --> 00:02:00,580 That’s it for sleep function. 27 00:02:01,980 --> 00:02:06,300 After we talk about process sleep. The function wake up is simple. 28 00:02:07,640 --> 00:02:14,420 All we need to do is find the correct process in the wait list and remove it from the list, 29 00:02:14,420 --> 00:02:21,410 then append it to the ready list waiting for scheduling. As you see, we retrieve both ready list and wait list from process control. 30 00:02:21,950 --> 00:02:27,950 Remove the process from the wait list and the wait is passed to the function 31 00:02:27,950 --> 00:02:30,600 so that we can find the correct process. 32 00:02:30,710 --> 00:02:33,880 Generally, we could have multiple processes waiting on the same object. 33 00:02:34,430 --> 00:02:38,570 So here the while loop is used to find all the waiting processes in the list. 34 00:02:39,500 --> 00:02:46,790 If we find one, we will change the state to proc ready and append it to the ready list. 35 00:02:46,790 --> 00:02:53,600 It’s worth mentioning that io requests could be added at the head of the list. Because if these requests 36 00:02:53,600 --> 00:02:57,710 such as key press is pending too long, computer will feel laggy. 37 00:02:58,870 --> 00:03:03,670 For simplicity, we just append it to the tail of the list as we did with other processes. 38 00:03:04,910 --> 00:03:10,610 The remove list is a new function, so let’s see the implementation in the lib.c file. 39 00:03:15,720 --> 00:03:21,780 In this function, we just find the process with wait and remove it from the list. 40 00:03:21,780 --> 00:03:24,840 Here we use two pointers, the current which points to the current element we are at, 41 00:03:24,870 --> 00:03:28,680 the previous which points to the previous element. 42 00:03:29,610 --> 00:03:34,620 At first, we assign the first element to the current, and the headlist to the previous. 43 00:03:35,650 --> 00:03:40,090 The item saves the process being returned. We initialized it with null. 44 00:03:41,320 --> 00:03:44,620 Then we use while loop to loop through each of the elements in the list. 45 00:03:46,030 --> 00:03:49,760 Remember the first element in the process structure is structure list. 46 00:03:50,320 --> 00:03:53,050 So we can retrieve the wait from the list, 47 00:03:54,140 --> 00:03:57,860 if it is not the one we want, we will go to next item. 48 00:03:58,890 --> 00:04:04,500 We move the previous to the next one by saving current to it and current is assigned with 49 00:04:04,950 --> 00:04:07,560 the address of next element. Then we continue the loop. 50 00:04:09,000 --> 00:04:15,180 If the wait is the one we want, the next thing we will do is remove it from the list which is simple, 51 00:04:15,780 --> 00:04:22,730 all we need to do is assign the address of next item pointed to by the current to the next field of previous. 52 00:04:23,520 --> 00:04:25,380 Then we save it in the item. 53 00:04:26,390 --> 00:04:33,020 Before we return item to the caller, we also need to check the current list. If the list is empty 54 00:04:33,020 --> 00:04:37,450 which means the head points to null, we just point the tail to null as well. 55 00:04:38,860 --> 00:04:44,830 If there are elements in the list but the item we get is the last one in the list, 56 00:04:44,830 --> 00:04:46,300 we will point the tail to the previous. 57 00:04:47,980 --> 00:04:51,310 After these checks, we can break the loop and return the item. 58 00:04:52,850 --> 00:04:58,110 Ok, in this example, we just test our project based on the user program in the last lecture. 59 00:04:58,520 --> 00:05:03,560 So we add sleep function in the system call module so that we can use it in the user mode. 60 00:05:06,950 --> 00:05:13,550 As you can see, we add function sys sleep for this request. Since we have two functions now, we change the checks 61 00:05:13,550 --> 00:05:17,480 to allow i to have two values 0 and 1. 62 00:05:18,930 --> 00:05:21,330 Now let’s focus on sys sleep function. 63 00:05:23,440 --> 00:05:28,970 The first thing we are going to do in this function is we are going to get current ticks by function get ticks 64 00:05:28,980 --> 00:05:29,700 . 65 00:05:30,630 --> 00:05:33,510 The ticks is incremented since the timer is working. 66 00:05:33,930 --> 00:05:35,360 We will see that in a minute. 67 00:05:35,910 --> 00:05:37,730 Then we copy it to the old ticks. 68 00:05:38,640 --> 00:05:43,640 Ok now we can compare the ticks with old ticks to see how long we have been waiting for. 69 00:05:44,370 --> 00:05:47,940 The sleep ticks is the duration we pass from the user programs. 70 00:05:48,630 --> 00:05:49,830 Then we get to sleep. 71 00:05:50,810 --> 00:05:56,840 You see, we pass -1 to sleep. In this system, -1 represents waiting for ticks. 72 00:05:57,810 --> 00:06:04,380 Right after wakening up from sleep, we call get ticks to get the current ticks and check the sleep ticks again. 73 00:06:04,830 --> 00:06:08,430 If the result is smaller than sleep ticks, we will sleep again. 74 00:06:09,000 --> 00:06:09,390 Alright, 75 00:06:09,390 --> 00:06:10,230 let’s see the function get ticks 76 00:06:10,230 --> 00:06:13,530 which is implemented in the trap.c file. 77 00:06:15,930 --> 00:06:18,120 As you see, ticks is defined here 78 00:06:21,200 --> 00:06:24,170 and get ticks function just return the value of ticks. 79 00:06:25,260 --> 00:06:31,620 In the timer interrupt case, we call timer handler function which increments ticks and wake up the processes waiting for ticks 80 00:06:31,620 --> 00:06:32,530 . 81 00:06:33,330 --> 00:06:39,480 So what it does here is waking up processes every 10ms, since timer interrupt is fired every 10ms 82 00:06:39,480 --> 00:06:40,460 . 83 00:06:41,340 --> 00:06:47,580 The argument is -1 so it will find the processes with member wait being 1 and wake them up. 84 00:06:48,540 --> 00:06:51,900 Also, don’t forget to add get ticks function in the header file. 85 00:06:53,410 --> 00:06:55,010 OK, the kernel part is done. 86 00:06:55,150 --> 00:06:56,410 Let's go to user part. 87 00:06:57,930 --> 00:07:04,860 In this lecture, we will use user2 program to do the test. 88 00:07:04,870 --> 00:07:11,160 Since we add a new system call function sys sleep, we will rebuild the library module to add the system call function 89 00:07:11,160 --> 00:07:12,240 . 90 00:07:13,500 --> 00:07:15,210 So in the syscall file, 91 00:07:17,470 --> 00:07:19,030 we added sleepu function. 92 00:07:20,280 --> 00:07:23,520 This function takes one parameter which is the duration. 93 00:07:24,690 --> 00:07:27,000 So we allocate 8 bytes on the stack. 94 00:07:30,260 --> 00:07:33,110 The index number is 1 for sleep in the kernel. 95 00:07:34,340 --> 00:07:37,670 Next we copy the argument to the allocated space on the stack. 96 00:07:38,890 --> 00:07:40,720 And save the number of arguments, 97 00:07:43,700 --> 00:07:45,440 1 in this case to rdi 98 00:07:46,770 --> 00:07:49,410 and save the address of arguments to rsi. 99 00:07:54,510 --> 00:07:56,660 Then we can int 80. 100 00:07:59,040 --> 00:08:05,130 After we return, we restore the stack by adding 8 to rsp register 101 00:08:06,900 --> 00:08:07,650 and return 102 00:08:11,920 --> 00:08:14,920 Global sleepu and we are done. 103 00:08:16,060 --> 00:08:16,410 Ok 104 00:08:17,480 --> 00:08:21,230 We navigate to the folder user2. 105 00:08:23,320 --> 00:08:25,270 and assemble syscall module 106 00:08:29,600 --> 00:08:31,610 and add it to the library file. 107 00:08:34,150 --> 00:08:38,470 Ok one thing left to do is calling sleepu function in main.c file. 108 00:08:43,280 --> 00:08:46,190 At this point, we can get rid of the if statement 109 00:08:51,600 --> 00:08:53,610 and pause for a while by sleepu. 110 00:08:57,370 --> 00:08:59,990 Remember timer interrupt is fired every 10ms. 111 00:09:00,700 --> 00:09:07,910 So here we pass 100 which is roughly 1 second. Ok we should see it printed on the screen every 1 second. 112 00:09:07,930 --> 00:09:11,980 We add the declaration in the lib.h file. 113 00:09:16,050 --> 00:09:17,200 Let’s build the project. 114 00:09:20,310 --> 00:09:22,230 And copy it in the boot folder. 115 00:09:28,670 --> 00:09:30,110 Then we build the kernel project. 116 00:09:34,640 --> 00:09:35,890 Ok, let’s test it out. 117 00:09:40,520 --> 00:09:44,480 As you can see, the process1 and process2 are printed on screen. 118 00:09:46,220 --> 00:09:47,510 That's it for this lecture. 119 00:09:47,810 --> 00:09:49,100 See you in the next video.