1 00:00:06,000 --> 00:00:10,800 Next up, lesson 3 on processes. So we're going to 2 00:00:10,800 --> 00:00:14,800 start drilling down and looking at some of the structure and infrastructure 3 00:00:14,800 --> 00:00:18,900 that surrounds processes. Let's start with the process 4 00:00:18,900 --> 00:00:22,800 resources. We already looked at this in the previous lesson, but we're 5 00:00:22,800 --> 00:00:26,900 now going to fill in some more of the details CPU time. We've 6 00:00:26,900 --> 00:00:30,900 already talked about is basically boils down to scheduling, which we 7 00:00:30,900 --> 00:00:32,800 will see more of in this section. 8 00:00:34,000 --> 00:00:38,900 Asynchronous events, which are the external events. These are things like 9 00:00:38,900 --> 00:00:42,700 the timers that are going off, the hardware exceptions that we've gotten, 10 00:00:42,700 --> 00:00:45,800 not that any of your programs would have Hardware exceptions, but it's been known to happen 11 00:00:45,800 --> 00:00:49,600 and external events. These are the events 12 00:00:49,600 --> 00:00:53,600 arrival of data or stop and continue. All those kind of things. 13 00:00:54,000 --> 00:00:58,600 And finally, we have I/O events. This is notification 14 00:00:58,600 --> 00:01:02,100 of completion of I/O or availability of I/O or 15 00:01:02,100 --> 00:01:03,400 exceptional. 16 00:01:04,000 --> 00:01:06,300 Data coming on the network, Etc. 17 00:01:09,600 --> 00:01:13,500 The memory we have again, we describe briefly 18 00:01:13,900 --> 00:01:17,500 what we're going to now drill down and look at how that gets broken up. 19 00:01:17,800 --> 00:01:21,300 We have the text and data that makes up the executable. 20 00:01:21,900 --> 00:01:25,900 So when you run LS, let's say what ends up happening. Is we 21 00:01:25,900 --> 00:01:29,800 go out, we find the file. That is the ls executable 22 00:01:30,300 --> 00:01:34,800 and it has a little header on it. That describes, what kind of, you know, that it is an executable 23 00:01:34,800 --> 00:01:38,600 and things that it needs like libraries and so on. But 24 00:01:38,600 --> 00:01:39,200 primarily 25 00:01:39,300 --> 00:01:43,600 It describes, the three pieces that make up that 26 00:01:43,600 --> 00:01:47,900 executable. So there's what we call the text, which is actually the compiled 27 00:01:47,900 --> 00:01:51,200 code. The thing that is going to actually execute on the machine. 28 00:01:51,200 --> 00:01:55,800 And then there are two data areas uninitialized data area 29 00:01:55,800 --> 00:01:59,500 and an uninitialized data area. So, the initialized data area 30 00:01:59,500 --> 00:02:03,900 is all of your Global variables that you've declared that you gave an 31 00:02:03,900 --> 00:02:07,600 initial value to. So, if you said in Foo, equals one 32 00:02:07,600 --> 00:02:08,600 that says is 33 00:02:09,300 --> 00:02:13,200 Will variable Foo, and when the program starts, it should have the value 1. 34 00:02:13,200 --> 00:02:17,500 If you just said into bar with no initial 35 00:02:17,500 --> 00:02:21,600 value, then that just says, when the program starts up, there's this Global variable bar 36 00:02:21,600 --> 00:02:25,800 and I don't care what its value is, which is really a way of saying 37 00:02:25,800 --> 00:02:29,800 it should start out as 0. Now. It would be possible 38 00:02:29,800 --> 00:02:33,500 to compile code that would simply assign all of the different values 39 00:02:33,500 --> 00:02:37,800 to all the global variables as the program started up. But there's a 40 00:02:37,800 --> 00:02:39,300 much easier way of doing that. 41 00:02:39,700 --> 00:02:43,500 And that is that the loader just sorts them all together. So it knows how they're laid out in 42 00:02:43,500 --> 00:02:47,700 memory, and then it just creates a memory image with all the initial values in 43 00:02:47,700 --> 00:02:51,800 it. So by simply reading that page from the disk into memory, 44 00:02:52,000 --> 00:02:56,900 now, you have all of these variables with their initial values. So 45 00:02:56,900 --> 00:03:00,500 what ends up being stored in the executable then is the compiled 46 00:03:00,500 --> 00:03:04,600 text. And then this image of all the initialized variables. 47 00:03:05,100 --> 00:03:09,100 And then we have also the uninitialized data, and we could just store 48 00:03:09,300 --> 00:03:13,900 Huge block of zeros in the file, but turns out we know how to create those very quickly. And 49 00:03:13,900 --> 00:03:17,900 so instead we just store the size of the uninitialized data area. And 50 00:03:17,900 --> 00:03:21,900 so when it starts up we can just zero out that memory and everything will 51 00:03:21,900 --> 00:03:23,000 have zero values. 52 00:03:24,700 --> 00:03:28,300 So in theory, what would happen is when you started this 53 00:03:28,600 --> 00:03:32,700 program running, then we would bring in the text. 54 00:03:33,300 --> 00:03:37,900 We'd bring in the initialized data area. We'd zero out the uninitialized data area and then we could 55 00:03:37,900 --> 00:03:41,800 start running it but we're very lazy. We 56 00:03:41,800 --> 00:03:45,700 have this attitude of do not do today, what you can put off till tomorrow 57 00:03:45,800 --> 00:03:49,600 and we'll just hope that tomorrow never comes and in fact in the case of 58 00:03:49,600 --> 00:03:53,300 executables that works out extremely well. So what ends up happening 59 00:03:53,400 --> 00:03:57,900 Thing is that instead of actually reading all this stuff in which for a large executable would take a 60 00:03:57,900 --> 00:04:01,300 long time. Instead. We just allocate the virtual memory 61 00:04:01,300 --> 00:04:05,900 areas and then we just say, oh if you need that, it's over here. And if you need that, it's on this place. 62 00:04:05,900 --> 00:04:09,800 And if it's need that, there's erode stuff than well. Just 0 it for you. 63 00:04:10,100 --> 00:04:14,700 And then we just say go. Okay, start running and you jump and wherever you jump won't be 64 00:04:14,700 --> 00:04:18,900 there. So we will take an immediate page fault and we will go off and we'll bring 65 00:04:18,900 --> 00:04:22,900 in the text and we'll try and execute that. And that probably will cause some more 66 00:04:22,900 --> 00:04:23,300 painful. 67 00:04:23,400 --> 00:04:27,800 Will take a few page faults and pretty quickly. We will have at least the stuff that we need to get up and 68 00:04:27,800 --> 00:04:29,900 running and away we go. 69 00:04:31,500 --> 00:04:35,900 Now, in addition to that text and data, we're going to, once we start running, we're going 70 00:04:35,900 --> 00:04:39,100 to be allocating additional space with Malik typically. 71 00:04:39,700 --> 00:04:43,900 And so when we do Malik's, we need to have an area that we can allocate 72 00:04:43,900 --> 00:04:47,300 that from. And that area as we'll see when we talk about the virtual memory 73 00:04:47,300 --> 00:04:51,400 layout, appears following the uninitialized data area. 74 00:04:52,200 --> 00:04:56,900 And then, of course, we need our runtime stack and that's going to start at the top of memory 75 00:04:56,900 --> 00:04:58,300 and grow downward. 76 00:04:59,100 --> 00:05:03,800 Now, why does this whole business of just not allocating any of these 77 00:05:03,800 --> 00:05:07,900 things to start and just letting it be allocated on the Fly work to our advantage? I 78 00:05:07,900 --> 00:05:11,700 mean, instead of reading it all in and one solid read instead. We're going to be killed by a 79 00:05:11,700 --> 00:05:15,700 Thousand Cuts with all these page faults. And that would be true if we actually 80 00:05:15,700 --> 00:05:19,700 ended up bringing all these things into memory, but the fact the matter is that we 81 00:05:19,700 --> 00:05:23,900 don't and in fact, the average executable never even touches half 82 00:05:23,900 --> 00:05:25,100 of its address space. 83 00:05:25,900 --> 00:05:29,400 Now that probably seems odd. I mean, what's what's all that 84 00:05:29,400 --> 00:05:33,800 unused stuff? Well, let's take LS as an example. 85 00:05:34,200 --> 00:05:38,300 How many options does Ls have actually, there was once a trivia 86 00:05:38,900 --> 00:05:42,800 question, which is what are the three letters that are not options? Two Ls. 87 00:05:43,200 --> 00:05:47,700 So basically every letter of the alphabet capital and lowercase along with most of the 88 00:05:47,700 --> 00:05:51,800 numbers are actually options to LS. Every one of those options 89 00:05:51,800 --> 00:05:55,300 has code, that implements it data structures that supported etcetera. 90 00:05:55,900 --> 00:05:59,900 And the typical user, you know, power LS, user might use 2 91 00:05:59,900 --> 00:06:03,800 or 3, l s- l IR some side of 92 00:06:03,800 --> 00:06:07,200 small set of options. And so when we run LS, 93 00:06:07,900 --> 00:06:11,700 we only need to bring in the text and data structures that support those options 94 00:06:11,900 --> 00:06:15,800 and all this stuff text and data, for all the other options. We don't 95 00:06:15,800 --> 00:06:19,500 touch it. We never bring it in the program exits and we're done. 96 00:06:20,200 --> 00:06:24,900 And in fact, is, will see. When we look at the virtual memory. We actually keep track of the pages 97 00:06:24,900 --> 00:06:25,600 that we have brought. 98 00:06:25,700 --> 00:06:29,900 Into memory. So, that the next time you run LS, we don't have to bring those in off 99 00:06:29,900 --> 00:06:33,200 the desk. We already have those in memory. We can just immediately attached to them. 100 00:06:33,200 --> 00:06:37,900 So in fact, if you run Alice with the same options, chances are we won't 101 00:06:37,900 --> 00:06:41,600 do any I/O at all. It'll just all be sitting around in memory and we will simply 102 00:06:41,600 --> 00:06:45,400 grab it. So again, the 103 00:06:45,400 --> 00:06:49,900 importance is, in the details of 104 00:06:49,900 --> 00:06:53,900 how you implement these things, this sort of straightforward and obvious way of implementing a lot of these 105 00:06:53,900 --> 00:06:55,600 things. In fact, would work. 106 00:06:55,700 --> 00:06:59,600 But the system would be much slower if we were doing all this extra 107 00:06:59,600 --> 00:07:03,900 I/O, tying up all this extra memory Etc. Okay. Finally, 108 00:07:03,900 --> 00:07:07,800 we have iodophor scripters. We've already said, we've got file descriptors which 109 00:07:07,800 --> 00:07:11,200 reference files. We've got pipes, which is a primitive form of interprocess 110 00:07:11,200 --> 00:07:15,600 communication sockets, which are sort of a more 111 00:07:15,600 --> 00:07:19,900 advanced form of interprocess communication. The thing with pipes is that the 112 00:07:19,900 --> 00:07:22,900 two processes have to plan in advance that they want to be connected 113 00:07:22,900 --> 00:07:25,400 versus sockets. You can create 114 00:07:25,700 --> 00:07:29,900 Connections after the fact. So one way of looking at it is sockets is 115 00:07:29,900 --> 00:07:33,500 really like pipes but you get to do your own Plumbing after the fact. 116 00:07:34,300 --> 00:07:38,500 And then historically there were streams. This was the AT&T system 117 00:07:38,500 --> 00:07:42,500 5 and later Sun Solaris. Although it was thought in the 118 00:07:42,500 --> 00:07:46,900 80s that this was going to essentially replace sockets. Then suddenly 119 00:07:46,900 --> 00:07:50,700 this large company in the Pacific Northwest of the United 120 00:07:50,700 --> 00:07:54,300 States realized that the internet was a thing that they needed 121 00:07:54,700 --> 00:07:55,600 and they decided 122 00:07:55,700 --> 00:07:59,700 To call their implementation windsock, which was somewhat based on sockets. 123 00:08:00,100 --> 00:08:04,500 And that sort of put the, the death Spike through streams. Because if you wanted portability 124 00:08:04,500 --> 00:08:08,900 between Windows and Unix systems, then you use sockets. So 125 00:08:08,900 --> 00:08:12,900 today streams aren't interesting footnote, but largely sockets is the 126 00:08:12,900 --> 00:08:14,100 interface that people use 127 00:08:15,100 --> 00:08:18,300 This next slide shows the BSD process structure. 128 00:08:19,600 --> 00:08:23,900 And I put BSD in the top title of this slide because this 129 00:08:23,900 --> 00:08:27,200 slide is very particular to 130 00:08:27,300 --> 00:08:31,900 BSD pretty much everything we were talking about so far would be 131 00:08:31,900 --> 00:08:35,700 equally applicable to Linux as it would be to be a Ste as it would be to 132 00:08:35,700 --> 00:08:39,900 Solaris. Pick your favorite Unix flavor, but there are 133 00:08:39,900 --> 00:08:43,800 some places where I'm going to drill down and really talk about things that are BSD 134 00:08:43,800 --> 00:08:47,700 specific and I usually will put BSD in the heading of the 135 00:08:47,700 --> 00:08:49,200 slide to let you know that this is 136 00:08:49,700 --> 00:08:53,600 Something that is more specific to BSD. That being 137 00:08:53,600 --> 00:08:57,500 said, in this particular picture, all the things that we've 138 00:08:57,500 --> 00:09:01,600 shown need to be in every one of those systems. So the difference 139 00:09:01,600 --> 00:09:05,800 between BSD or Linux say is simply where these things get placed. 140 00:09:06,200 --> 00:09:10,900 So in the BSD world, we have a very small process entry and then all of the other 141 00:09:10,900 --> 00:09:14,500 structures are actually separate sub structures, which are 142 00:09:15,300 --> 00:09:19,200 referenced out of the process entry. So, the process entry itself is on the order of 5. 143 00:09:19,300 --> 00:09:23,600 212. Bytes then all the rest of this stuff probably adds up to somewhere around eight 144 00:09:23,600 --> 00:09:27,900 kilobytes, but we push them down into sub 145 00:09:27,900 --> 00:09:31,700 structures so that we can take references to them if we 146 00:09:31,700 --> 00:09:35,900 want to clone copies. So we want to make other threads or 147 00:09:36,200 --> 00:09:40,900 other processes with a lot of sharing going on as we'll talk about shortly. It makes it 148 00:09:40,900 --> 00:09:44,900 much easier to do where we just have to create the process entry and then just take references on most 149 00:09:44,900 --> 00:09:48,900 of the substructures. So, if you were to look at Solaris or Linux, you would see 150 00:09:48,900 --> 00:09:49,000 a 151 00:09:49,300 --> 00:09:53,800 You are the substructures instead. They would be embedded in the process, entry itself. The fact, 152 00:09:53,800 --> 00:09:57,300 the matter is, they're there. It's really just a question of how they end up being 153 00:09:57,300 --> 00:10:01,500 organized. So, I want to just sort of go through and and briefly 154 00:10:01,500 --> 00:10:05,900 talk about these because we're going to come back and look at most of these in a lot more detail. 155 00:10:05,900 --> 00:10:09,400 So, starting at the top. We have the process group in 156 00:10:09,400 --> 00:10:13,600 sessions. This is ways of organizing processes, which we'll see later in this lesson 157 00:10:13,600 --> 00:10:17,300 of the credential, which it keeps track of who we are, 158 00:10:17,300 --> 00:10:18,500 and 159 00:10:19,500 --> 00:10:23,700 It's essentially our user ID and our set of groups that we're working with. 160 00:10:24,100 --> 00:10:28,600 The VM space is the thing that describes our address space, which is actually made up 161 00:10:28,600 --> 00:10:32,400 of a list of regions. Each region has some distinct 162 00:10:32,400 --> 00:10:36,700 property. So there's the text region, the initialized data region, the uninitialized, data 163 00:10:36,700 --> 00:10:40,400 region, the stack region. And so on again, we will see that in the 164 00:10:40,600 --> 00:10:44,700 section when we talked about virtual memory file, descriptors will see this and 165 00:10:44,700 --> 00:10:48,700 actually when we get to the iOS lesson, this is the way we keep track of 166 00:10:48,700 --> 00:10:49,000 the 167 00:10:49,300 --> 00:10:53,900 Descriptors that the process has open which in turn are going to 168 00:10:53,900 --> 00:10:57,900 reference file entries, which is where the kernel tracks the information 169 00:10:57,900 --> 00:11:01,800 about those file. Descriptors. We have resource limits, which allow us to control 170 00:11:01,800 --> 00:11:05,900 the amount of resources that any given process is going to use. 171 00:11:05,900 --> 00:11:09,800 We can control the amount of memory, the amount of I/O, the amount of 172 00:11:09,800 --> 00:11:13,900 CPU time. There's there's many, many different resources, which we 173 00:11:13,900 --> 00:11:17,500 do not detail in this particular class, but is described 174 00:11:17,500 --> 00:11:18,800 quite thoroughly in the 175 00:11:19,300 --> 00:11:23,600 Book, we have a system called Vector. Remember that I told you that 176 00:11:24,100 --> 00:11:28,900 it was possible to run Linux binaries on a FreeBSD system. The problem, of 177 00:11:28,900 --> 00:11:32,400 course, is that Linux uses different numbering schemes, sometimes different 178 00:11:32,400 --> 00:11:35,900 parameter orderings or numbers of parameters for their system calls. 179 00:11:35,900 --> 00:11:39,900 And so the easiest way to do that efficiently 180 00:11:39,900 --> 00:11:43,600 is that we have a system called Vector which is 181 00:11:43,600 --> 00:11:47,500 described the FreeBSD system, call convention. 182 00:11:47,500 --> 00:11:49,100 There's another system called. 183 00:11:49,400 --> 00:11:53,800 Actor that describes the Linux system call convention. And so when a 184 00:11:54,100 --> 00:11:58,900 executable is started up we look in its header to see whether it is a FreeBSD binary 185 00:11:58,900 --> 00:12:02,900 or a Linux binary and then we simply install the appropriate system 186 00:12:02,900 --> 00:12:06,900 call Vector for that binary. So this way you can have some 187 00:12:06,900 --> 00:12:10,800 processes that are running as FreeBSD and others that are running as Linux. And in 188 00:12:10,800 --> 00:12:14,500 fact there have been other system called vectors done. So for example, one for 189 00:12:14,500 --> 00:12:18,500 Solaris, we're in times past system, five single 190 00:12:18,500 --> 00:12:19,100 actions. 191 00:12:19,300 --> 00:12:23,900 Keeps track of what you want to do. For all the possible signals. We've talked about a bunch of them already. 192 00:12:23,900 --> 00:12:27,900 So if you set up a signal Handler for a single arm because you want to 193 00:12:27,900 --> 00:12:31,600 get a real-time event. This is where we store the information about what the 194 00:12:31,600 --> 00:12:35,600 process would like done. We Gather a lot of statistics about what's going 195 00:12:35,600 --> 00:12:39,700 on. These are the statistics that are typically dumped out when the process 196 00:12:39,700 --> 00:12:43,500 exits, and then finally, in the BSD world. We have a 197 00:12:43,500 --> 00:12:47,600 notion of multiple threads running within the same process. 198 00:12:47,600 --> 00:12:49,100 Address space typically. 199 00:12:49,200 --> 00:12:53,600 Process has all of the stuff that we've described so far and then a single 200 00:12:53,600 --> 00:12:57,500 thread that's running around inside the process doing whatever the process is doing, 201 00:12:57,500 --> 00:13:01,600 but it is possible to have multiple threads 202 00:13:01,600 --> 00:13:05,900 running within the same process. It's a slightly different model than that 203 00:13:05,900 --> 00:13:09,600 used by Linux. And in fact, I have a slide that's going to describe the differences between 204 00:13:09,600 --> 00:13:13,800 those, but if you have multiple threads there, you'll have multiple 205 00:13:13,800 --> 00:13:17,600 threads structures at the bottom, and the thread structure keeps track of information 206 00:13:17,600 --> 00:13:18,900 that's specific to 207 00:13:19,200 --> 00:13:23,000 To a thread of control. So how is it being scheduled 208 00:13:23,100 --> 00:13:27,600 information that it's state block, which is where we store our example, all of the 209 00:13:27,600 --> 00:13:31,800 register values if it's going to be put to sleep so that we can restore them when it 210 00:13:31,800 --> 00:13:35,800 wants to run. Again, most importantly it's thread, stack. Every 211 00:13:35,800 --> 00:13:39,800 thread has to have its own stack when it runs inside the kernel because they may run inside the 212 00:13:39,800 --> 00:13:43,900 kernel, concurrently and then an area for any machine 213 00:13:43,900 --> 00:13:47,900 dependent threat information, different architectures, have different sorts of stuff that they 214 00:13:47,900 --> 00:13:49,100 want to keep about. 215 00:13:49,300 --> 00:13:53,800 Ed's, so let's drill down now and look 216 00:13:53,800 --> 00:13:57,800 at the difference between multiple threads running in a process 217 00:13:57,800 --> 00:14:01,900 versus having multiple processes. The notion of having 218 00:14:01,900 --> 00:14:05,200 multiple threads running within the same process 219 00:14:05,700 --> 00:14:09,900 itself. You have one process structure and 220 00:14:10,000 --> 00:14:14,300 then you have, as I said, different threads that are running within that process structure, 221 00:14:15,000 --> 00:14:15,900 Okay, so 222 00:14:17,200 --> 00:14:21,700 The benefit of this, is that switching between threads is very cheap, 223 00:14:22,000 --> 00:14:26,900 because everything is in place. You don't have to change anything. All you have to do is load a new stack pointer, and a 224 00:14:26,900 --> 00:14:30,000 new program counter and a set of registers 225 00:14:30,800 --> 00:14:34,900 general-purpose registers and you're done it. You switch to it. And 226 00:14:34,900 --> 00:14:38,400 so the cost of switching between one and the other is 227 00:14:39,000 --> 00:14:40,200 tens of instructions. 228 00:14:41,600 --> 00:14:45,900 The drawback to the K thread model is that you have only one address 229 00:14:45,900 --> 00:14:49,600 space and so, because you have only one address 230 00:14:49,600 --> 00:14:53,300 space and each thread wants it its own stack. You have to take the 231 00:14:53,300 --> 00:14:57,700 traditional stack that we have for the process and break it up into 232 00:14:57,700 --> 00:15:01,900 pieces, one for each of the threads. And so there's a lot more management of that 233 00:15:01,900 --> 00:15:05,800 and you have to worry about one stack running down into the next stack. And 234 00:15:05,800 --> 00:15:09,700 so it is certainly more complicated. So the 235 00:15:10,500 --> 00:15:14,100 Benefit is that it's very cheap to switch between threads. The 236 00:15:14,100 --> 00:15:18,900 drawback is that you have a more complex set of data structures that you need to 237 00:15:18,900 --> 00:15:22,900 manage at the process level. So the approach that was taken 238 00:15:22,900 --> 00:15:26,600 by Linux is what we call the our Fork model, the resource 239 00:15:26,600 --> 00:15:30,700 fork. And if you recall from the data structure, we had all those various different 240 00:15:30,700 --> 00:15:34,800 substructures. And with with our Fork it allows you to say 241 00:15:34,800 --> 00:15:38,200 what you want to share and what you want to have private. 242 00:15:38,600 --> 00:15:40,400 So in the, in the 243 00:15:40,500 --> 00:15:44,700 A thread model. Everything is shared. The address space is shared. Descriptor shared. The signals are shared 244 00:15:44,700 --> 00:15:48,700 everything in the our Fork model. You can say, well, 245 00:15:48,700 --> 00:15:52,800 we're going to share the descriptors and we're going to share the resources, 246 00:15:52,800 --> 00:15:56,900 but when it comes to the address space, we're going to share the text 247 00:15:56,900 --> 00:16:00,700 and data area of it, but we want everyone to have their own 248 00:16:00,700 --> 00:16:04,800 stack area. So now every single one 249 00:16:04,800 --> 00:16:08,900 of these are forked processes is sharing all of the text 250 00:16:08,900 --> 00:16:10,300 and data, but it has 251 00:16:10,500 --> 00:16:14,900 sewn stack. So we don't have to have the K thread complexity of carving up the stack into 252 00:16:14,900 --> 00:16:15,800 smaller pieces. 253 00:16:16,900 --> 00:16:20,300 But the drawback to this is 254 00:16:20,300 --> 00:16:24,900 that. Now when we want to switch from one thread to another, we no 255 00:16:24,900 --> 00:16:28,900 longer just change a stack pointer and a program counter instead. 256 00:16:28,900 --> 00:16:32,900 Now, we actually have to change address spaces and 257 00:16:32,900 --> 00:16:36,600 as we will see, when we talk about context switching is a very heavy weight 258 00:16:36,600 --> 00:16:40,800 operation, several thousand instructions to do. And 259 00:16:40,900 --> 00:16:44,900 so, although we get the benefit of having each process 260 00:16:44,900 --> 00:16:46,000 having its own stack. 261 00:16:46,100 --> 00:16:50,400 Jack instead though. We pay the cost of switching from one to another. 262 00:16:50,700 --> 00:16:54,900 So you can't have these sort of light weight thread to just sort of float around and do a little bit 263 00:16:54,900 --> 00:16:58,600 on there. Each one instead, you tend to use the our Fork model 264 00:16:58,600 --> 00:17:02,800 for things like an instance of a web server or an instance of a mail 265 00:17:02,800 --> 00:17:06,900 server, something where you're going to do a fair amount of work to amortize 266 00:17:06,900 --> 00:17:10,700 that cost of doing the context switch, that being said, 267 00:17:10,700 --> 00:17:14,400 FreeBSD actually has both the our Fork model and the K thread model, 268 00:17:14,700 --> 00:17:16,000 but because many 269 00:17:16,100 --> 00:17:20,700 Applications have been written for Linux over the years than for FreeBSD. Our Fork model really 270 00:17:20,700 --> 00:17:24,500 sort of needs to be a first-class citizens because that's what they are expecting. 271 00:17:24,600 --> 00:17:28,200 And so the where the rubber meets the road is the thread library. 272 00:17:28,200 --> 00:17:32,900 And because the most of the threaded applications live on top 273 00:17:32,900 --> 00:17:36,900 of the thread library. And if the thread library is, is 274 00:17:36,900 --> 00:17:40,900 targeted to the our Fork model, then it would be much easier for 275 00:17:40,900 --> 00:17:44,900 those applications to be ported. Then if the thread library is pointed 276 00:17:44,900 --> 00:17:45,800 at the K thread, 277 00:17:46,100 --> 00:17:50,900 Do so at a system called level the FreeBSD supports both K threads and 278 00:17:50,900 --> 00:17:54,800 our Fork bought at the threading Library level. It uses the our Fork 279 00:17:54,800 --> 00:17:58,400 model and so, predominantly applications running on 280 00:17:58,400 --> 00:18:02,900 FreeBSD are running in the artwork model. Next up. I want to 281 00:18:02,900 --> 00:18:05,500 talk about process states. There are 282 00:18:05,500 --> 00:18:09,900 four states that process. These may be in. So, this first 283 00:18:09,900 --> 00:18:13,900 slide, we will talk about the two main ones. The first of these two is 284 00:18:13,900 --> 00:18:15,800 the running State. And this is a 285 00:18:16,100 --> 00:18:20,900 Where the process is sitting there with its program counter sitting 286 00:18:20,900 --> 00:18:24,800 in front of an instruction that it would dearly like to execute. If only it could be on a 287 00:18:24,800 --> 00:18:28,900 processor in running. And so, a runnable process is either, hopefully actually 288 00:18:28,900 --> 00:18:32,900 running on a processor or it's sitting on a queue waiting for a 289 00:18:32,900 --> 00:18:36,500 process or to become available so that it can run. So 290 00:18:36,500 --> 00:18:40,500 it's the state of executing the other main 291 00:18:40,500 --> 00:18:44,200 state is the sleeping State. And this is a process that 292 00:18:44,200 --> 00:18:46,000 is sleeping way. 293 00:18:46,100 --> 00:18:50,700 Waiting for typically some event to occur. A sleeping process will 294 00:18:50,700 --> 00:18:54,800 always have a thing called the weight Channel or W. Chan, and that 295 00:18:54,800 --> 00:18:58,700 keeps track of the resource that the process is waiting 296 00:18:58,700 --> 00:19:02,600 for. And so, when a process goes to sleep and house to say, why 297 00:19:02,600 --> 00:19:06,900 it's going to sleep, but can't just decide it wants to take a nap and go to sleep. It has to say, 298 00:19:06,900 --> 00:19:10,800 I'm going to sleep, because I'm waiting for this thing to happen for this thing 299 00:19:10,800 --> 00:19:14,900 to become available. And the reason it has to 300 00:19:14,900 --> 00:19:15,800 say what it's waiting for. 301 00:19:16,100 --> 00:19:20,900 Is because the only way it's ever going to not be sleeping is when it is 302 00:19:20,900 --> 00:19:24,700 issued a wake up and the wake up is going to be because some particular 303 00:19:24,700 --> 00:19:28,700 resource becomes available. So typically a process 304 00:19:28,700 --> 00:19:32,100 comes into existence. It's in the Run state. It runs for a while and then it blocks 305 00:19:32,100 --> 00:19:36,900 sleeping waiting for something like disk IO or network or the user to type something. 306 00:19:36,900 --> 00:19:40,700 At some point, one of those events occurs the wake up 307 00:19:40,700 --> 00:19:44,400 gets issued the sleeping processes. Then move back to the Run state 308 00:19:44,400 --> 00:19:45,900 where will run until 309 00:19:46,100 --> 00:19:50,800 oh, it's finished processing. Whatever that input is typically it will then block waiting for the next import 310 00:19:50,800 --> 00:19:54,700 or waiting for output or whatever. The longer-term event is that it's waiting for, 311 00:19:55,000 --> 00:19:59,400 if you look in a typical system, you'll often see maybe 312 00:19:59,400 --> 00:20:03,300 5000 processes in the system 313 00:20:03,300 --> 00:20:07,900 often with multiple threads inside them. But the number 314 00:20:07,900 --> 00:20:11,900 of running processes typically far far smaller, maybe 10 315 00:20:11,900 --> 00:20:15,700 or 20 or 30 out of the 5,000, the vast majority of processes. 316 00:20:16,100 --> 00:20:20,800 In most systems are sleeping waiting for some particular thing to happen, 317 00:20:20,800 --> 00:20:24,900 so they can proceed. So you think the web server it sitting there waiting for your web 318 00:20:24,900 --> 00:20:28,900 request to come in. You asked for it. It finds it. It sends it, and it goes back waiting for you 319 00:20:28,900 --> 00:20:32,400 to ask for the next thing. So, the 320 00:20:33,000 --> 00:20:37,900 point is that the running processes are usually in the in the 321 00:20:37,900 --> 00:20:41,700 minority and the vast set of things are sleeping. And if you actually look at what they're 322 00:20:41,700 --> 00:20:45,900 doing, if you do a long listing of Pious, it'll actually show you all those. 323 00:20:46,100 --> 00:20:50,800 Wait Channels with a descriptive text. So it'll say it's waiting for network IO or it's 324 00:20:50,800 --> 00:20:54,600 waiting for disk I/O, or it's waiting for terminal I/O or whatever. 325 00:20:54,600 --> 00:20:58,800 The the resource is that it's blocked waiting for. We then have to other 326 00:20:58,800 --> 00:21:02,600 states for processes. The first of these is the stop State 327 00:21:02,600 --> 00:21:06,600 and the this is used when we're doing either job 328 00:21:06,600 --> 00:21:10,600 control or debugging. So, in the case of job control, 329 00:21:10,600 --> 00:21:14,900 you can hit control Z and that says, stop the process and it will 330 00:21:14,900 --> 00:21:16,000 extend be stopped. 331 00:21:16,100 --> 00:21:20,100 Until such time as you send it a continuous signal saying you want it to start running again. 332 00:21:20,800 --> 00:21:24,700 So, a process will move from either the sleeping or the running State into the 333 00:21:24,700 --> 00:21:28,600 Stop State either because of job control, or in the case of the 334 00:21:28,600 --> 00:21:32,700 debugger. It will put in Trace breakpoints. And 335 00:21:32,700 --> 00:21:36,800 when, when you hit one of those trace breakpoints, the program moves into the Stop State, 336 00:21:36,900 --> 00:21:40,800 and then add the bugger can sit there and examine it and decide what it wants to do. And at some point 337 00:21:40,800 --> 00:21:44,700 it in the debugger, you can say, all right, start it running again, which point it will 338 00:21:44,900 --> 00:21:45,900 tend to continue 339 00:21:46,000 --> 00:21:50,400 Which again will take it out of the stop State, and put it into the running, or the sleeping state? 340 00:21:51,300 --> 00:21:55,400 So stop state is one which is only ever entered 341 00:21:55,800 --> 00:21:59,700 due to intervention either by the user directly with job control or indirectly 342 00:21:59,900 --> 00:22:03,900 through a debugger. And once in the stop State, you will stay 343 00:22:03,900 --> 00:22:07,700 in that state until whoever put you in that state, decides that it's time for you to start 344 00:22:07,700 --> 00:22:11,600 again at which point you will then move back into the sleeping running 345 00:22:11,900 --> 00:22:15,900 Continuum again, now, the issue is that you can 346 00:22:15,900 --> 00:22:19,400 come to the stop State either from when you were 347 00:22:19,400 --> 00:22:21,000 running or when you were 348 00:22:21,100 --> 00:22:25,900 Sleeping. And in fact, you might have been sleeping in the event that you are waiting for 349 00:22:25,900 --> 00:22:29,500 may have occurred. And so you may have been issued a wake up, but you will not suddenly 350 00:22:29,500 --> 00:22:33,900 jump from stopped into the running Q because the stop State. As I said is 351 00:22:33,900 --> 00:22:37,900 one where you only exit when told to do so, but we still need to keep track 352 00:22:37,900 --> 00:22:41,900 of that because when you are told to continue, we need to know whether to 353 00:22:41,900 --> 00:22:45,900 put you into the Sleep queue or into the Run queue. So, 354 00:22:45,900 --> 00:22:49,900 if you're running, you're not waiting for anything. So your weight channel will be 0 if 355 00:22:49,900 --> 00:22:50,900 you're sleeping, then, 356 00:22:51,100 --> 00:22:55,600 Your weight channel has to be non zero, indicating what it is you're waiting for. So, in 357 00:22:55,600 --> 00:22:59,900 fact, when we continue a stopped process, all we have to do 358 00:22:59,900 --> 00:23:03,600 is look at the weight Channel. And if it is in 359 00:23:04,200 --> 00:23:08,900 non zero, then we know it's sleeping. And we just say, okay, it's on the Sleep Q now and everything 360 00:23:08,900 --> 00:23:12,800 was fine. And when whatever it's waiting for happens, it'll happen. If on the other 361 00:23:12,800 --> 00:23:16,500 hand, that we see that the weight channel is 0, then we know that was 362 00:23:18,200 --> 00:23:21,000 previously running or had been sleeping but with go 363 00:23:21,100 --> 00:23:25,700 To be made running. And so at that point, we can take it and drop it, directly onto a run queue, which 364 00:23:25,700 --> 00:23:29,800 will hopefully fairly shortly, cause it to be picked up and be run by 365 00:23:29,800 --> 00:23:33,300 one of the CPUs. We then have a couple of minor 366 00:23:33,300 --> 00:23:37,400 States, the new, which is where the process is first being 367 00:23:37,400 --> 00:23:41,600 created. The only way to create a processes in the fork system call. 368 00:23:41,800 --> 00:23:45,900 So your parent has to make a fork which makes a copy of the parent. Typically, that 369 00:23:45,900 --> 00:23:49,600 will be followed fairly quickly by an exact, which will then overlay it with some other 370 00:23:49,600 --> 00:23:50,900 process. So, if your shell, 371 00:23:51,100 --> 00:23:55,600 No Forks, initially, you're running another copy of the shell, but then it overlays itself without 372 00:23:55,600 --> 00:23:59,400 laughs, or emacs, or whatever. It is, that you've decided you want to run. 373 00:23:59,900 --> 00:24:03,100 The main reason for new is just so that the kernel 374 00:24:03,800 --> 00:24:07,900 where it's looking at. All say, all the processes for some reason comes across 375 00:24:07,900 --> 00:24:11,600 one that's marked new. It knows that its embryonic and that 376 00:24:11,700 --> 00:24:15,700 it may not. In fact be fully formed. Therefore. It is not safe 377 00:24:15,700 --> 00:24:19,800 to try and track down some of it substructures because they may not exist yet. 378 00:24:20,300 --> 00:24:21,000 So, as a 379 00:24:21,000 --> 00:24:25,700 And you'll often see places in the kernel where it will switch on the state, you know, if it's 380 00:24:25,700 --> 00:24:29,800 running do this, if it's sleeping, do that, if it stops something else and it sees new, it's almost 381 00:24:29,800 --> 00:24:33,700 always continue, don't do anything because we just don't know what 382 00:24:33,700 --> 00:24:37,700 what state that process is in a new process, doesn't 383 00:24:37,700 --> 00:24:41,900 stay in the new state for very long. As soon as it's got all of its resources pulled 384 00:24:41,900 --> 00:24:45,700 together. It will then be dropped into the Run queue and 385 00:24:45,700 --> 00:24:49,400 begin running and doing whatever it is that it's going to do. 386 00:24:49,400 --> 00:24:50,700 So, it's actually very 387 00:24:51,000 --> 00:24:55,800 Rare to actually see a process marked as new when you do a PS, but 388 00:24:55,800 --> 00:24:59,800 very very occasionally, you will see it. And it's just a process that hasn't been fully 389 00:24:59,800 --> 00:25:03,900 created yet at the other end of the life cycle are the dreaded zombie processes. 390 00:25:03,900 --> 00:25:07,900 These are processes that are in the state of 391 00:25:07,900 --> 00:25:11,700 exiting so they have exited or been forced to 392 00:25:11,700 --> 00:25:15,800 exit due to a signal of some sort that wasn't handled and 393 00:25:15,800 --> 00:25:19,800 they are in this zombie State and there's two things that they need to 394 00:25:19,800 --> 00:25:20,800 do before they can truly. 395 00:25:21,000 --> 00:25:25,000 Away from the system. The first is they have to get rid of all their resources. 396 00:25:25,000 --> 00:25:29,400 And you know, you'd say well that can't be very hard. You know, 397 00:25:29,400 --> 00:25:33,700 you know, here's my memory. You know, here's here's my signal State. Here's this here's that 398 00:25:33,700 --> 00:25:37,600 really the only one that's difficult to get rid of our, the I/O 399 00:25:37,600 --> 00:25:41,800 descriptors because of course, for the I/O descriptors. We have to close any descriptors that 400 00:25:41,800 --> 00:25:45,400 you have that are open. And for the most part, even, that's not too difficult, 401 00:25:45,400 --> 00:25:49,800 the place where we get in trouble is for descriptors that reference 402 00:25:49,800 --> 00:25:50,500 TCP. 403 00:25:51,000 --> 00:25:55,900 Ins TCP connections have the property that they are reliable and 404 00:25:55,900 --> 00:25:59,700 by reliable, we mean that if you have done a right system, call onto a socket 405 00:25:59,700 --> 00:26:03,800 descriptor, then there is a promise that we will get 406 00:26:03,800 --> 00:26:07,500 that data to the other end of the connection if it's at all 407 00:26:07,500 --> 00:26:11,800 possible. And if it's all possible, means The Listener on the other end, 408 00:26:11,900 --> 00:26:15,300 still has the connection open and the network in between is still 409 00:26:15,300 --> 00:26:19,800 connected. And so what can happen is that you might 410 00:26:19,800 --> 00:26:20,700 be output to. 411 00:26:21,100 --> 00:26:25,700 To a remote login session, the user hit Ctrl q' to stop the 412 00:26:25,700 --> 00:26:29,900 output. And then, you know, went to San Francisco for a week 413 00:26:29,900 --> 00:26:33,600 to record a class. And so, until they get back, and they hit the 414 00:26:33,600 --> 00:26:37,700 control. Yeah, control us to start it going. 415 00:26:38,000 --> 00:26:42,700 Then it's just going to sit there. And so, it's going to sit on the Queue, 416 00:26:42,700 --> 00:26:46,300 because it's already full of stuff at the destination of stuff to print. 417 00:26:46,400 --> 00:26:50,900 And so, any extra that we've already accepted is sitting here on our socket that 418 00:26:51,000 --> 00:26:55,100 We're trying to close if we close the socket and release the resources then 419 00:26:56,100 --> 00:27:00,900 not going to drain, and it's going to get lost. It's not going to get pushed through. And 420 00:27:00,900 --> 00:27:04,800 so we would not be reliable. So, we have to sit there 421 00:27:04,800 --> 00:27:08,900 and keep that descriptor open until such time as we get it to the other end, which may be a 422 00:27:08,900 --> 00:27:12,800 long time. So one of the reasons that you 423 00:27:12,800 --> 00:27:16,300 see zombies is that they're unable to close their connection. 424 00:27:17,700 --> 00:27:20,900 Once they got rid of all their resources, they can then return their 425 00:27:21,100 --> 00:27:25,800 It's status to their parent. And so there's the weight system call, 426 00:27:25,800 --> 00:27:29,700 which is what allows the parent to get the exit status 427 00:27:29,700 --> 00:27:33,800 for its children. And so it reads in that information 428 00:27:33,800 --> 00:27:37,000 and, you know, gets how much time it ran and resources that used and so on. 429 00:27:39,100 --> 00:27:43,500 The other reason that you can not, you can stay as a zombie is if your 430 00:27:43,500 --> 00:27:47,800 parent hasn't collected, your exit status, so you've managed to get rid of all your resources, but 431 00:27:47,800 --> 00:27:51,400 now you just need your parent to do a weight system call. Well, 432 00:27:52,400 --> 00:27:56,600 any application that's been written by people that know the 433 00:27:56,600 --> 00:28:00,500 system will know that they need to collect the exit status of all their children. 434 00:28:00,800 --> 00:28:04,500 So things like I netd or sshd, Etc, are 435 00:28:05,200 --> 00:28:08,600 not going to make that mistake. So if you see one of those programs that 436 00:28:08,800 --> 00:28:12,600 Sitting there with something in a zombie State it's because it's presumably 437 00:28:12,600 --> 00:28:16,900 unable to close one of its connections. On the other hand. 438 00:28:17,300 --> 00:28:21,800 If it's a new programmer to the system, they may have read only halfway through the manual. So they know about 439 00:28:21,800 --> 00:28:25,900 fork and exec, but they haven't gotten to the W's yet to learn about weight. And so they just 440 00:28:25,900 --> 00:28:29,900 keep creating new processes, but they never collect the exit status. And some of 441 00:28:29,900 --> 00:28:33,400 them are such awful parents that they just up and 442 00:28:33,800 --> 00:28:37,700 exit themselves, without ever collecting the exit, status of their parent, of their children. 443 00:28:38,100 --> 00:28:38,600 And so, 444 00:28:38,700 --> 00:28:42,600 So now you would have these zombie processes, wandering through the system forever more. 445 00:28:42,800 --> 00:28:46,900 But luckily we actually have an orphanage process, which is processed one or 446 00:28:46,900 --> 00:28:50,900 in it and it's in its role in life to sit around and wait 447 00:28:50,900 --> 00:28:54,600 for these orphaned children. So, when a parent 448 00:28:54,600 --> 00:28:58,800 exits without collecting its children's exit status, those children, all become 449 00:28:58,800 --> 00:29:02,900 children of a net and now and it will sit there and collect the exit 450 00:29:02,900 --> 00:29:06,800 status. Pat them on the head, throw it away. Collect the next exit status, Pat 451 00:29:06,800 --> 00:29:08,500 them on the head, throw it away. What the 452 00:29:08,800 --> 00:29:12,900 Is that all those children will then all those zombies will now go out of the system. 453 00:29:13,600 --> 00:29:17,300 So in fact, if you're trying to figure out which kind of zombie, you have there, 454 00:29:17,900 --> 00:29:21,300 if you do a long listing of PS, it'll show for every child, the 455 00:29:21,300 --> 00:29:25,700 parent process ID. And so, if you see a whole bunch of zombies, and they all have a 456 00:29:25,700 --> 00:29:29,900 common parent, that's not something like sshd, or I netd. You 457 00:29:29,900 --> 00:29:33,700 know, it's a DOT out being owned by some new programmer. 458 00:29:34,100 --> 00:29:38,600 You can test the theory by killing the parent killing the, a DOT out and now all of its children. 459 00:29:38,700 --> 00:29:42,900 Children will suddenly be inherited by an it. And if they all go away, then you know, that was the 460 00:29:42,900 --> 00:29:46,500 problem on the other hand, if they all become children of a net and they 461 00:29:46,700 --> 00:29:50,900 all have, you know, they continue to just be zombies hanging there. Then, you 462 00:29:50,900 --> 00:29:54,900 know, their problem is not that they didn't have their exit status collected, but rather 463 00:29:54,900 --> 00:29:57,400 that they're having trouble getting rid of their resources.