 All righty, welcome back to operating systems. So today review time. So this is what? This is midterm Eve. So on midterm Eve, what do we want to go over today? I am here for your benefit. Any other words I use sound weird so I won't continue with that thought. So what we want to do? Oh, this slowly leave. All right, any special requests? UCLA midterm page table question. Is it the fall one? Is it the fall one? Yeah, it should be the fall one. Midterm, no. Is it this one? So where the offset came from? Yeah. Yeah, so the wording on this was kind of bad. By two megabyte pages, it probably should have been rewritten to instead of saying pages to say page size. Yeah, no, it should have been page size. I should have written it better. But you know, yeah. Yeah, so it's where you are within a page as long as the page size is in bytes. I mean, I could be really weird to you guys and say the page size is in bits. I don't know why I would do that just to make you divide by eight. But if it's in byte, it has to be byte addressable. So just however many bits. Yeah. Yeah, so you always want to multiply by the number of page levels of page tables you have, because it's a separate memory access for each one. And then the original one. So this exam was a closed book exam. So I gave them the equation, but they also said that recall for a single page table, this is the equation. So that's where the two came from. And then I was like, oh, calculate it for your multi-level page table. So you had two levels. So one for each level plus the original one, which is why this was three here. Yeah, yeah. Yeah, the actual memory you were accessing, like that physical memory. So yeah, no, they wouldn't be at the same time. So like, yeah, because they'd all be physical accesses, right? So they'd all take the same amount of time, but you can only access physical memory anyway. So all right. So wait, let me switch so I don't show you anything I shouldn't. So if everyone does not have any preferences, let's see if we can find a good one here. Nope, that was too far. All right, people seem to like doing virtual memory in like a certain sense. What about this? So have we seen this question yet? So you can go and look at the final for 353 as well, and the final for 111 if you want. And some of the questions are going to be valid for you. So this is from 353. So their final exam and there's a virtual memory question which you should be able to do so you might not have seen this yet. So we can do this. So we created a very silly machine. This silly machine has 12-bit virtual addresses, eight-bit physical addresses, page size of 16 bytes. So whenever I see a page size in bytes, I should probably just write it in powers of two because I'll probably need it. What's 16 in powers of two? Four, two of the power four. So without even reading the question, I'll just put two the power four here because I will probably need it later. And then the page table entry size is one byte, which I mean you can just do two the power of zero if you really want, but we're going to be multiplying and dividing by one, which I mean you don't have to do anything, but hey if you want to get in the habit of writing it, go ahead. So it says our page table entry has the following layout. So remember what is in a page table entry. The important things is that it has the physical page number and then it has some permission bits which it would at least need to have a valid bit. Likely it probably also has a read and a write bit and then an execute bit or something. At the very minimum though it would need a valid bit. Here I just created four bits for the permissions. So you might notice here that this system is overly nice to you because you don't actually have to write anything out in binary because it kind of nicely matches with hex numbers. So this is our eight bit physical page table entry. So eight bits because it is one byte. So the last four bits are the permissions here and they are four bits which would be exactly one hex character. So you can actually read it. And then the upper hex character is the ppn which is also four bits here again to make your life easier. So given that information I also give you a giant dump of physical memory. So this is like the base address here and then the columns are like the offset. So if you want to know what the value it the byte is at address something like I don't know zero three. Well you would go in this column and zero plus three is zero three. So the byte there would be AF. If you want to look at what the byte is at address two four well you go here. So it starts off at two and then plus four you would get this byte. So at address two four in hex you would have the byte three F. So any questions about reading just the dump of virtual memory or no sorry this is physical memory physical memory. Yeah yeah yeah so in this like every column is eight eight bytes here because I can only fit eight on a page or on a row. So the ppn is four bits which means it would start like if you have a ppn of zero it means that well all address zero zero in this case so offset zero all the way to the max all of those addresses would be on the same physical page right which would be 16. So if I want to another easier thing to do might be just to take this memory and everything will be page aligned so I'll just divide it into pages. So essentially since my page size is 16 bytes I can just divide it into groups of 16 bytes. So something like this. So everything here would be on physical page zero all these 16 bytes would be ppn one this would be ppn oh two this would be ppn oh three something like that. So if you look at memory like that well there's four physical pages zero one two and three. So any questions about that? All right so first question is how many bytes do we need to store a single page table if we used it? So here we have 12 bit virtual addresses eight bit physical and page size of 16 bytes. So if I have a single large page table I need an entry for every single virtual page number right? How many virtual page numbers do I have in this silly system? So how many virtual page numbers do I have in this silly system? 4,096 how'd you get that? So to the 12 that would be my entire virtual address space so then I have to pick that and then divide by the page size right? No so this is just a single large page table. So if I have a single large page table I need an entry for every single virtual page number yeah so not related to the physical address at all. So in this case yeah so to the power of 12 is like how many bytes I can use for all my virtual addresses then to figure out how many virtual page numbers I actually need to support well I just divide that total by the number or by the page size which is two the four so that means I need two of the eight virtual page numbers in my giant page table if I just use a single page table. So that's how many page table entries I need and then if I need the total size of that well I take this number and then multiply it by the pte size what's the pte size and this in bytes one so I can just leave it alone. So in this case it would be two the eight bytes so I would need a single page table that's two the eight bytes because I need 256 entries. All right any questions about that one? Yeah yeah so you can also think of it that way. So if you want to instead of just thinking about how many virtual page numbers I want and doing the division well you know you have 12 bits for that virtual address in total and then you know that you know because of the page size four those need to be offset so you can also just do this and figure out that at the end of the day it's the same thing so just p2 that number and then times the page table entry size which might be different. Yeah yeah we try and use all the bits here yeah yeah yeah so if it's like a weird number like it might be like the only time you have unused bits typically will be if you have a multi-level page table and they don't quite line up exactly and then you would have some bits that are unused because you don't support that whole virtual address space but that's like the only exception. Yeah oh the tricks yeah so the tricks yeah I can only divide by two and multiply by two like at most two times so the only things you need to remember two the power zero is one and then two the power five is thirty two two the power of ten is one thousand and twenty four and then you can figure it out from that so two the power of eight oh well I only know two the power of ten which is one thousand twenty four to get to the power of eight I just divide by two twice so five twelve two fifty six yeah or put a table on your cheat sheet or I guess you're allowed to bring a calculator if you really want to two but you might be wasting time than just by knowing powers of two so thirty two two the power five is generally the only one we should need all right so yeah then the question shifts to the more fun part because single level page tables are lame so we could do multi-level page tables so next question is what is the minimum levels of page tables we need in our system assuming that each level page table exactly fits on a page so anyone remember how to do that yeah so in general remember the number of levels we need is like the ceiling of virtual bits minus offset divide index and to figure out the number of index bits we need we need to figure out how many page table entries we can fit on the page in this one well because every page table entry is just one byte well I can fit 16 of them on a page so my number of index bits is just four in this case same as the offset bits so in total my virtual bits from the question is 12 offset is four and then my index bits are four which would give me 12 minus four divide by four which is eight four and ceiling luckily that's a nice number because I am so nice and it's just a two so we need two levels of page tables for this any questions how I got that one yep so the index remember the index is essentially depends on the number of PTEs per page if I know that that would be and turn that into to the power of something if I log to that that's how many bits I need so in this case it's always the page size oops it's always the page size divide by the PTE size just like it was just a giant array but in this case my page size is 16 bytes and then my PTE size is just one byte so I don't have to change anything but in general that's the equation you guys because it's just a big big array all right are we good two levels of page tables all good all right so here's where it gets more interesting so we're going to translate virtual address one two three so in this virtual address we have two levels of page tables so I should have an l1 index and an l2 or sorry an l1 index and an l0 index and then an offset so in that virtual address one two three which number is which and luckily you will also note that I was nice to you and you can just leave it in hex you don't even have to translate anything because in general sometimes they don't line up nicely with hex numbers and you have to write it in binary and it's just a complete mess this one is nice because you don't have to translate so which of these hex characters is the l1 index yeah one right so this is our l1 index two is hopefully our l0 index and then three is our offset right any questions about that breakdown so that one two three boom those three questions basically tells you to read it all right any concerns about that okay so then it said for this virtual address we'll try and translate it so either the value of the final pte if it's valid and otherwise the value of the pte that causes a page fault so another part of this question says that the l1 page table is at ppn2 so I will highlight it in cyan that means d16 bytes here that represents my l1 page table so in this l1 page table if I'm translating address one two three what index do I use for my l1 page table well should be index one so where is index one on physical page two one f so that's where index zero is everything is a byte so there should be 16 entries in this page table this would be entry zero one two three da da da da da all the way up to 15 here so if we're translating that address well the l1 index is one so we would look at the byte at one f and then this we know is our pte so since this is our pte is this a valid page table entry given that layout of our page table entry no no it should be right so if we take this one f and then translate it to that over there well zero zero zero one more I could just leave in hex I'll put in binary because sure whatever is the ppn and then the rest are the flags so the execute is one write is one read is one valid is one so all of its flags are valid so it is a valid entry and since this is an entry in our l1 page table what does the ppn tell us is that the ppn of this virtual address no it's the ppn of l zero so that means that let's highlight it in green that these 16 bytes represent our l zero page table right so in our l zero page table what index should we look at while we're translating virtual address one two three so our l zero index is two so if we look at page one this is at index zero this is at index one this is at index two so it should be this byte right any arguments that that is our page table entry in the l zero page table oh why did just erase a bunch of stuff I can't go back that's better so it's yeah so whole procedure again so the question tells us we are translating virtual address one two three so that mean that also translates until we have to use one for the l one index two for the l zero index and then when we're translating it we don't have to touch the offset and the question also tells us where the l one page table is so l one page table is at physical page two so that corresponds to that thing highlighted in the cyan color and since we have to for this virtual address we have to use index one while we look at the index one entry which is this whoa that was a bad tool to use which is this page table entry so since that was a page table entry in our l zero page table we can check why does it keep erasing it whenever I look away so this means if we take this and break it out into the page table entry it means that execute was one right was one read was one valid was one so it's a valid entry so the physical page number is valid and it points to an l zero page table so it should be at physical page one which would be what's highlighted in green now so then I use that's my l zero page table so because I'm translating that address I look at index two and then the physical page or the page table entry there is ff which is valid and it corresponds to physical page f that we haven't used yet but that's the physical page number or page table entry we would use as our final translation because this is l zero we're done right so the answer to this question was be like the final value of the pte if it is valid it was valid in this case and the final value was ff if there is a page fault yeah so if there was a page fault I mean I could just make one by just doing this so in this case if I just change the page table the first page table entry in l zero to just not be valid there'd be a page fault in l one and that would be the failing page table entry I would get one zero because that valid bit would be off so it's a page fault it's not valid the rest of value yeah if valid is zero you don't read the rest of it it just fails immediately all right any other questions about that one all right so what is the final resulting physical address then so we were translating address one two three and then our final page table entry was ff which means it was valid and the ppn was essentially just f so what is our final physical address going to be for one two three yeah yeah zero hex f3 because remember essentially what we're doing all the time no matter how many levels of page tables we have is we're taking the virtual page number whoa that's some good writing so we take the address we divided into the virtual page number and an offset in this case our virtual page number was two one two and our offset was three and then all the time no matter what when you're translating it you're just translating it to an offset and then a physical page number so no matter how many levels of page tables you use it's all the same idea it's just how many steps you need to go through to actually get this physical page number that you actually want that is your translation so after two steps we figured out that the physical page number is just f so one two three would translate to f whoops wow that's a big eraser so we don't touch the offset so we figured out that virtual page number one two corresponded to physical page number f and we don't touch the offset so that means the final physical address is just f3 so any questions with that one and hopefully yep we were correct i still get to teach yeah sorry so why do i have only one f so this right here is the entire page table entry so that ff is the page table entry so given this it's divided into two parts so the first text digit is the ppn and the last one is all the permission bits so in this case the layout of this also doesn't matter i could have flipped it if i really wanted to and could have had the permission bits first if i want as long as you're consistent doesn't matter all right any other questions someone pasted a question that looks real fun yeah so yeah a page fault would just happen if at any stage in the lookup the valid bit was zero or if i was really mean so the first entry we looked at is like one f some of the questions are like fun we're like they'll put an entry here that's like eight f so that's valid but you have no idea what that memory actually is so like the answer could be like oh it's out of range i can't see what it is yeah yes so if i change it to one a or something like that yeah it would correspond to a is just one zero one zero so that means the valid bit would be zero which case nothing else matters no so in this case for real systems the no this is totally possible so your mmu it just checks the valid bit if it's zero it just ignores it so this is actually a way we'll get into later the operating system can actually take advantage of this so that means if it's valid you can store whatever the hell you want in the other remaining bits and you can use it for whatever you want yeah that's just the final physical address i didn't say what the value is or anything yeah that's fine yeah if i ask for the value it's like you know f3 is the address of a character or something like that and then if i asked what's the value of the character the answer would be like i don't know because you didn't tell me all right anything else so there's let me go back so there was a fun question that was posted in the discord that kind of looks like well this one too whoops so if you want we can do this question but it's from it's from the one eleven fall final and this is technically within scope for you guys because it includes threads but not data races or anything like that and processes so we can take a gander at this let me know if you want to go over this one or not and spoiler alert your exam kind of has threads on it but it's not terribly big yeah so this question basically it just says is pretty much just explain everything that happens here how many processes get made for this print statement show me all the results from this print statement so i want to start going over this and let me then stop me if you get bored to tears all right so let's just walk through what this program does so let's assume that we execute this we're executing i don't know process 100 it starts executing main first thing it encounters is a fork oh yeah yeah yeah yeah if it's not stated what the running processes state whatever that state whatever you want as long as it makes sense if you say one i might like be like hey that's kind of weird but it might be okay but generally one's the only one you should really avoid because we kind of know what the knit does so in this yeah i think all the time i just i specify a starting one just because it also makes it easier to grade and more consistent typically i always say just starts with 100 why do i like the number 100 i have no idea so in this case we hit fork immediately so what does fork do everyone remember so we create a new process right probably gets the id i don't know 101 so they're going to be exact clones of each other right now they're both executing main so nothing fairly important happens so we'd have process 100 and 101 and if i draw let's say i draw my family tree up here so i have process 100 101 should be a direct child of process 100 right so this is what my family tree should look like any arguments should it also like do that that's like the royal family tree so we don't want that all right so now we have process 100 and 101 they're exact clones of each other the only difference is going to be the return value of fork in process 100 what would it get returned from fork 101 and then it would create the variable called pid and then assign 101 to it in process 101 it would create pid and it would get assigned zero right so now at this point is any is process 100 guaranteed to run or or is it left to the computer gods so that just creates a new thread and then kernels up to schedule it as much yeah so it could be it could be a queue if you did your own but in general you can't guarantee it's a queue so if it's just a generic kernel you just have to say whatever the hell could happen because well if this is Linux you know it's a completely fair scheduler maybe you ran out of your time slice already and switches you immediately you have no idea so at this point we have no idea what runs say the main thread of process 101 continues executing well it will hit p thread join of thread one and then it will be blocked right so process the main thread of 101 is blocked waiting for thread one thread one to what to finish or terminate exit whatever you want to call it so at this point well also if i wanted to process the main thread of process 100 could run but that would probably make this even uglier than it already is so at this point process the main thread of process 101 is blocked on that p thread join so let's pick do we want process or thread one or thread two to run because it's up to the gods now we have no idea thread one all right so thread one runs oh no it calls fork anyone remember what happens if you call fork and you have multiple threads running yeah so you still create a new process but that new process only has a single thread of it which is a clone of whoever the hell just called fork so in 101 also have variables when i when thread one called fork the new process is a exact clone of that thread yeah no so process 102 exists through run so it is because all these threads like thread one and thread two in this case are running in process 101 so if you wanted to another thread could wait on 102 or something it's still available because it's still your child process just another thread made it yeah so process 102 is just a completely independent process that just keeps on executing so here if we want to write out what threads we have to in 101 we have a main thread we have a thread one thread two in 102 it was kind of like a copy of thread one if we want but it only has a single thread executing in it yeah yeah so in 102 like it clones the entire process all the virtual memory everything but like all the registers in everything are specific to thread one in this case so all of its local variables everything will just be copied so it'll just look like there's only one thread running now but all the other memory is the same if it access global variables or whatever it'd be the same as whatever the values were whenever it was forked so like a mean thing I could do is like create a global and then like essentially have a data race here and then if there's a data race the value of that will be different depending on the order of them before the fork and that's a whole mess so yeah don't worry about that but yeah it'll just be a copy at the time of the fork all the same fork rules apply exact copy all right any other questions all right so now at this point in thread one in process 101 what does it get returned to what does fork return for that one 102 so in thread one and 101 here I'll use a different color PID is equal to 102 and in process 102 PID is equal to zero so now at this point do I know if process 102 is going to run or thread one in 101 is going to run no idea up to the gods so which one do you want to do 102 all right so 102 will execute this print line so what will we see in this print line so it will print thread and then thread ID what is thread ID in process 102 one so thread ID is one and then it would say running and what's its process ID 102 and then in that case well PID is not greater than zero it is zero so it's just going to hit return null if you return from your thread function what is that the same as doing p thread exit right so it's like the exact equivalent for just the main function so if you return from main that's the same as calling exit and for your thread function if you return from your thread function that's the same as calling p thread exit so in this case if 102 goes ahead returns it was exact copy of that thread at the time of the fork so it's just going to call p thread exit and in process 102 there is only a single thread running and it called p thread exit so what happens if you call p thread exit and you're the last thread alive yeah then it just calls exit the process is now done so so 102 I can thankfully delete at this exact moment what is the state of process 102 is it a zombie is it an orphan is it chilling zombie right at this exact moment it is a zombie because it has now terminated but no one has successfully waited on it yet so 102 still exists but I'll just put an X beside it to say that it is terminated hasn't exited yet so now at this point let's say thread one in 101 continues executing it would hit this print statement what would it print so it would print thread what thread one running in process what 101 and then it is going to check is PID greater than zero yes it is currently 102 so it's going to call weight PID on 102 which will wait until it's terminated hey right now it's already terminated great so now we can clean it up it is now a just dead so here I'll just put it in this color so 102 is now just completely deleted we could also reuse the PID if we really wanted but we can keep our lives less complicated and just say it's just gone so thread one would go ahead and then return null so that means thread one in process 101 is now gone so is there other threads executing in process 101 yep so this thread's just gone it's technically a zombie thread right now but if we start executing 101 well it can make it past this join because thread one's now done and we just cleaned it up and we're process the main thread of process 101 is now stuck in join for thread two so any questions about that so let's see can I do this oh geez we're kind of out of time all right if I do this on turbo mode well thread two is going to do the same thing except create another process probably called 103 so we'd get 101 103 thread thread so that would be all them that's derived from process 101 and this entire thing is going to happen again for process 100 so process 100 is going to make two threads and then each of those threads is going to make a process and it probably looks something like this and then we'd get the same thing so thread one would print from process 100 thread two would print from process 100 and then thread one would probably print from process 104 and thread two from 105 but those numbers just come down to lock at that point as long as they're consistent so they'll be always a thread one and two from process 100 and a thread one and two from process 101 aside from that you'll just have different orderings of them as long as your numbering is consistent it doesn't matter yeah yeah technically if you wanted to you know thread one could run create a process clean it up and then thread two could run and then create another process with the exact same ID because we can reuse it so yeah if you really want to make your graders really happy you could do that technically it would be right they would probably look at it and you'd probably have to get corrected because they'll probably look at it and do like the typical pattern matching thing and be like no wrong and then you'd be like actually that you can do that yeah generally make the graders life easier and they'll be much happier and probably more lenient so like imagine if you're grading something if you're like grading like 10 pages of chicken scratch where it's like two sentences probably like the two sentences a lot more all right any other questions oh we only have a minute damn all right so oh yeah also for the Wednesday practicals I will probably be around in the practicals whenever the hell I get to Toronto so if you want to come ask me questions there I assume it'll be the day of the midterm and people leave things for last minute so you can come swamp me in whatever rooms those are there so with that just remember pulling for you we're all in this together and the midterm won't