 Alright, welcome back to Operating Systems. Hopefully you do not destroy my computer, although you can in this lecture, because this one will be fun. So, this is where we start getting into the fun land, where what you know about executing a program, it's now no longer true. Alright, this projector is dying. Attempt number two. Fingers crossed this works. Okay, so what we got into at the beginning is we kind of talked about a process. Process being an instance of a running program. That's how we're able to run multiple copies of the same program at that same time. Remember we had that count example where it was running two processes, they were independent of each other. So we know that they have virtual registers. One of the things was a local variable, and we just printed it, probably used a register. So we have virtual registers because one process does not affect the other process when it's executing, otherwise that would be a mess. And then we argued that they probably have something like virtual memory too, because their stack and their heap would need to be different. They each have to have their own independent view of memory. So we added on to it, and we said that, well, global variables are also in memory, so they're probably also in virtual memory. And then we had open file descriptors, which were part of the process as well. Remember by convention there were those three file descriptors that are always open, 0, 1, and 2, 4, standard input, output, and error. Trust me, you will remember which ones are which in time. So what is actually in a process? Well, so when the kernel is keeping track of processes, the information to keep track of all the information about a process is called a process control block or PCB. Unfortunately for you hardware people that does not mean printed circuit board, it means process control block. So specifically in Linux, this corresponds to something called a taskstruck that you can browse on GitHub, so that link will actually bring you to the source code file. So if you want to read it, you can. It doesn't hide anything. That's a great thing about open source. You can see all the information that's in a process as long as you know where to look. So specifically if you go through it, you'll find that contains things like the process state, which we'll get into the next slide. CPU register, so that's it's saving those virtual registers whenever it needs to swap back and forth. Scheduling information, so like what process should run at any given time, which we will get into next week. Memory management information, so how it maintains virtual memory. IO status information, so basically the file descriptors and if it's writing or reading any information from them and all sorts of different type of information that the taskstruck is actually huge. But what we need to know is that each process gets its own unique process ID or PID or PID to keep track of it. So each process gets a unique number that keeps track of it and it doesn't change for the lifetime of the program. So this is the process state diagram and it looks as follows. So we're going to concentrate on how you create processes today. So when you start, they're in this created state where the kernel is initializing everything, setting up the virtual memory, loading it into memory, figuring out what it needs to load, all that fun stuff. So we'll figure out how to do that behind the scenes stuff, but for now we just have to care about actually using a process. So to go from created to waiting, so you could also rename waiting ready if you want. It's going to be waiting or ready whenever it's ready to execute. So we could give it time on a CPU core and it could execute, but it being in this waiting or ready state just means we're not going to give it CPU yet. But if we chose to, we could. So it's able to be scheduled and able to be running. So what your kernel gets to decide is, hey, this process is ready. So I can take this transition here and put it in the running state and then it will actually run on a CPU core and hopefully do something useful. So after time, your program may want to run forever. Well, the kernel is going to decide that's enough of you and then put you back into this waiting state to give someone else a try. And that's like scheduling in a nutshell will have like a week to go over the details of how you decide that because that's a whole another topic. But for now, we just know that the kernel ping pong is back and forth between running and waiting. So eventually when it's running, it might go to this terminated state, which means the process is no more. So we learned before what system call could do this. So anyone remember what system call could you could call that would terminate a process? Anyone remember? Yeah, exit, right? So whenever you make a system call exit or exit group, it means that process is now dead. And because we can S trace stuff and we know every process does that, well, that's how you go from running. You do the system call to exit and then you're terminated. You're done. The kernel can go ahead and delete you. Your process ID gets reused. All your memories gone. All that fun stuff. So you might notice that, oh, well, it can go running from this to this weird block state. What does that mean? So another system call you can make is like write and that could actually write some bytes to a file or something like that, which is really, really, really slow. So most of the system calls will return whenever they're done. So block just means you requested some resources that you have to wait for. And even if you wanted to run and the CPU wasn't doing anything, you couldn't run because you're waiting for something to happen. Or in other words, you're blocked. So I'm blocked. I can't run anymore because I'm waiting for something. So eventually the curl is going to keep track of if you're writing a file, okay, you're done writing that file. And then it could put you back in this waiting state or ready state. And then you could start executing again, and you would have written the information to the file then. Cool, cool. So cool thing about Linux is, and this is directly related to lab one. So lab one is basically you are creating. If you ever looked at task manager and saw everything running on your machine or activity monitor on Mac. Well, that's what you're writing for lab one. So you're going to see every process writing on your machine. So this is very specific to Linux. On Linux, there is a slash pro directory and it represents all sorts of stuff about the kernel. That is the kernel's way of conveying information to you. So it doesn't have that many system calls. And it's not going to create a new system call for any type of or every type of information you want to ask it. So it creates this proc file system and kind of creates fake files there that you can read and write to, but they actually just communicate with the kernel through some magic that the kernel can do because it can do whatever it wants. So one of the things in this proc directory is there's more directories in the proc directory that look like a number. So if the directory looks like a number, it represents a running process. And that's just a number. So in that folder, if you see anything that is just a number, it means it represents a process. And there's all types of files within that directory that represent information specific to that process. So for instance, for lab one, there's a file called status that contains the state that we use for lab one contains the name of the program and everything in it. And basically, if you want to make a process monitor, well, you just go through every directory in the proc file system. If it's a number, that means that's a process. And then you can figure out a way to get its name and you can list every running process that is currently on your machine, which is kind of cool. So you might wonder how you create processes from scratch. Well, or how you create processes. So you might think, well, we just create them from scratch. So you could just load a program into memory, have the kernel do some magic, create a new process control block and just start executing it, put it in the waiting state, let it execute. So that's exactly what Windows does, which kind of makes sense. Windows has a system called create process. But on Unix machine, so again, macOS or Linux, it separates us out into two steps to create some more flexible abstractions, and it will not make sense at first, but we'll get through it. So what does Unix do? Well, instead of creating a brand new process, it clones the current running process. So how this works, and we will see a code example, which will probably take us most of the rest of the class, is it pauses the current running process. It makes a complete copy of its process control block into a new one, and both the processes look identical. So they will have the same virtual addresses, they will be the same values, they will have the same instructions, they will have the same literally everything. The only way to distinguish between the two of them is after this cloning, well, they're going to get a different return value from that system call, and that's going to be the only way to distinguish the two are different. And they will also have a parent-child relationship, which will go into why that is a thing and why that matters in the next lecture. But you can think of it like if I'm making a clone, it's like being a parent. If you have a child, it's basically a little clone of you. So that's why they say that. And you'll also see that they don't call it sibling or something else like that, because the parent has to take care of the child, and that will become a thing. So this name will make sense. And this will also be the source of a lot of very random Google searches. So you might make the Google search that how does parent kill child or something like that? And that will be in your Google searches because that actually means something if you're doing operating systems. But if you're not taking this course, that will get you on a list. So just, yeah, this is where your Google searches become real weird. So just be prepared for it. If your friends coming over, clear your history, they're going to think you're a psychopath. So what is that clone system called? It's not actually called clone. For some historical reasons, it's called fork, and fork is the only way to create a new process on Unix. So again, it creates an exact copy of the current one, and it has this following API. You'll notice that it doesn't take any arguments whatsoever. And how it works is it will return the process ID of the newly created child process. So this can fail, in which case it will return negative one, and you will not have created a new process. Otherwise, if it succeeds after this fork, there will be two processes running, and one will be the parent that called the fork, and one will be the child that is a clone of the parent. And the only way to differentiate between them is the return value. So in the child process, the PID is going to be zero to represent this as the child. And in the parent, it's going to be greater than zero because it's going to get the process ID of the child. So after this point, there's two processes running. They can access the same variables. They're a complete copy from there, but they're going to be separate after the fork because they have virtual memory. And we'll get into the operating system. It does things to essentially do this for free, but we'll get into it later, the actual implementation. So that's a good question. What can cause the fork to fail? I imagine you guys will cause the fork to fail during this lecture if you're anything like the other class. So we'll get into it. So on POSIX systems, you can find documentation using the man command, which is short for manual. Today we're going to use fork execve, which hopefully we'll get time to and wait in the next lecture. And for most of them, you should just be able to do man fork or something like that. So let's just get into the example. So here's the fork example, and it has one process execute each branch, which might hurt your brain initially, but there's going to be two processes after the fork. So let us go to this. So I will start drawing off in actually let's just run it first. Let's just run it. So if I go ahead and run it, I can see that even though my program here, I'll bring this down. You know, those print statements are in two separate else or two separate if branches. They both get executed because I created two processes. So the first thing I did was I forked. So the first process would have started executing main and immediately it would have called fork. So it would have created a new process that is the exact copy of itself. Thankfully, it didn't really do anything. But then after this point, there's going to be two processes running this code at the same time. And one is going to get a return value of zero from fork and then assign it to return PID. And the other is going to get the return value of or the process ID of the child and it will return from fork. So in this case, one process will go through here, print off all the stuff about the parent. So it prints off the return value here. And then there's a system call to get your PID. So there's a system called called get PID. So that will return the PID of this process. And because there's a parent child relationship, I can also print off this processes parent. So the parent parent ID or the grandparent, if you want to call it that with get PID. So that's parent PID. Then in the child, I will print off the return PID, then it's PID and then it's parent PID. So that's the question. If I called fork twice, would I have two processes with PID zero like if I did this? Yeah, so we'll get into that later. So let's make sure we explain this one first. But yeah, that'll get things weird. Yeah. So at the time of the fork, the way to think about it is whenever a process calls fork before it returns, if it's successful, it'll get cloned. It'll look exactly the same. The clone will be exactly the same, like down to literally everything. And after that point, it'll be independent. But at that point, they'll look exactly the same. And then they'll start doing different things. And the first different thing they're going to do is return from fork. And they're both going to get different return values. So whoops, that is the wrong thing. So if we go in here to explain that again with the numbers that I saw. So the original process, this time when I ran it, got process ID 2207. So something that had to create that, we can explore that more in a bit. But this process we've got created and it would start executing main and your world is as it has ever been. Program start executing at main, even though with S Trace, we know that's not really true. It'll load the C standard library and all that. But for now on the purposes of this course, it can start at main. So it would start executing main. Then the first thing it's going to do is call fork. So fork in this case, it was successful. So it will create a new process. In this case, I got the number 2208 for the new process. And right now at this instant, they're exactly the same. Turns out that they didn't really do anything before this point. So it doesn't really matter. But it would have done things like load the C standard library again. So it doesn't have to redo that. And then at this point, they would both be able to execute. And you don't know which one is going to finish returning from fork first. But let's go ahead and say that the original one did first. So the return value for fork for it would be 2208. Because it was the original one that created the child. So in the child, it should have got a return value of zero from fork. And this is where they start being separate. So in the blue process here, it would assign 2204 to its local variable PID. Which just in case this PID type, you might wonder what that is. Well, this is basically just an int because it's just a number. So if you see PID underscore type, that's just the type of a PID. It's a number. It's going to be an int. So in this case, we don't know what would execute next. But let's just go ahead and say that the blue process starts executing. Then it would have assigned 2208 to PID. Then it would just execute like any other program you've ever dealt with in your life. It would check this if statement. Well, 2208 is not negative one. So it would fall over here. It would check this if statement. Process ID is not zero. So it would fall over here. Go into the else branch, then print that PID. Print its PID and then print its parent process ID. Go to return, exit, and it's done. And then at some point, the child process would execute. And it would get zero from fork. And then it would execute like you know and hopefully love. It would check PID. It's zero. It's not negative one. So it would hop over here. Check this condition. PID is equal to zero. So it would print this, print this, print this. And then it wouldn't go into the else branch because it went into the F branch. So we'd go here, return zero, and then that process is also done. And that is what we saw when we executed it, right? So here it happened that the parent executed first and all the numbers kind of make sense. So the parent's process ID is 2207 and it got returned 2208, which means that should be the process ID of the child. And if we look at the process ID of the child, it's 2208. So that makes sense. Its return PID is zero and its parent PID is one, which I didn't want to explain yet. There we go. So now the child's parent PID is 2340, which is the parent's PID. Yeah, so that's a good question. What is this basically, right? What's the parent's parent? Anyone want to guess what the parent's parent is? Yeah, well, there was something that created this process that executed main, right? Yeah. So good guess, kernel itself or a user interface process. Good guess. Any other guesses? Yeah. VS code terminal, warmer. Any other guesses? Very close, though. Very close. Yeah. Sorry? The build. Building it close. So knowing about that proc file system, if I wanted to figure out what process that is, what could I do? I could probably look, right? What about I could look in proc, right? So in proc, there should be a directory for every process. It's probably still running. What number should I put in here? 1600. And then there's a whole bunch of files there. I don't need all of those. I told you before that there's one called status that has information like the name and I can hit enter. And I'll get a whole bunch of information. We do not know what the hell it means yet, but that's kind of cool that we can see what it is. So let's go up. So eventually we'll get to its name. Its name is ZSH, which is my shell, which makes sense because that's what I'm actually typing in. When I typed build fork example, well, I typed it into my shell and it would have had to create a new process to execute that. Right? Kind of makes sense. So if my shell had to create this new process, what did it have to do to itself in order to start executing my process? Yeah. It had the fork, right? So now we kind of know what our shell is doing. And so it would have had the fork, but we're still missing a piece of the puzzle. Like how did it get from forking to starting running my code? That's a bit weird. So we'll get into that at the end. Yeah. Yeah. So there's a good question. If it forks, does it just like copy everything? Well, let's see. So let's see that I am not bsing you. So let's say in X equals 42 like this. So this is before my fork. Start executing my program should start executing main creates a local variable called X and then forks. So if I do something like this, what should I see? Yeah, both the parent and the child should both print 42 because I define it and then I fork. So they should be exactly the same copy at the time of the fork. So before the fork happened, this process had a local variable called X and it was assigned 42. So the new one's going to have a local variable called X assigned 42. And then after the fork, as long as it doesn't fail, there'll be two processes and then each of them will call this line. And hopefully when I run it, that's true. So when I run it, I see that I get X two times. So I get X equals 42 and then X equals 42 two times to show. Yep. So what? Yeah. So that's a good question. What happens if I assign X after the fork? Here? Okay. Anyone want to answer what happens if I do assign X equals one after the fork? Yep. It should print what? Sorry. Yeah, so it will still print twice. What value will it print twice? One. Right. So in this case, it should hopefully print one in both case. So why does this happen? Well, I create it as X equals 42. I fork. They're exactly the same copy. They both have X equals to 42 at the time of the fork. Then they both return from fork with different numbers and then they both do the same thing. They both assign one to their local variable and then they both print. So because they both do that, you still read it top to bottom. They both assign it to one. Yep. Yeah. Whenever the fork executes, it gets copied at that point. So because thankfully our program still run starting at main and go down. We know that this instruction has to execute before the fork. So anything before that will be the same. And to show you that they are actually exactly the same. So knowing what we know about virtual memory, if they're exactly the same, what should the address of X be? Yeah. Oh, we'll get into that later. Yeah. So you might have noticed why does it say that child parent ID is one? That is because, we'll explain it later. Basically the other class broke everything I had. I had to restart my VM and all that so they destroyed my thing. So you guys probably will too. Because I feel like we're going in that direction. Anyways, so this, if I print the address of X, what should I see in both processes? Yeah. Same address, right? They are exact copies, like exact copies. So if I do that, I get a warning. But I can see that if I print the address of X, it's exactly the same in both of them. But if I change the value in one, it doesn't affect the other. So I could go ahead and move this X equals one to here. And I could just put, I guess I have to put it at the end. It's harder to do this. So I could do this. So what should happen in this case? So I'm going to print off the address of X, which should be the same for both of them. And then only in the parent, I assign X equals to one. And in the child, I don't do anything. So what should I see if I execute this? Yeah. Yeah, parent prints one, child prints 42. And it shouldn't matter what order they execute in. Compile. So in this case, I get X equals 42, X equals one. No matter how many times I run it, I'll get the same thing, even though I might get things in different orders. So you notice that the print F's between the processes, within a process, it'll be consistent because it has to execute top to bottom. But between the two processes, you have no idea because the kernel is controlling what's running at any given time. So given this, I know that the parent's going to print parent return PID before parent PID. But I don't know the order between parent and child because they're two separate processes. It's up to my kernel to figure out which one runs at any given time. They could be running in parallel, which I do have more than one CPU core. They could not. They could switch back and forth. It's up to the kernel to decide what runs and which, which we'll get into. So you see, in this execution, it was a little bit different. So you're not guaranteed any order between them. Yep. Where exactly I put the X equal? Okay. Yeah. So only the parent's going to assign X equals to one. And now we know that, hey, well, it's not changing the number in the other process because again, they're independent. So even though they have the same virtual address, they're reading in any order and they always get the same number. So you know that, well, those virtual addresses definitely correspond to different physical addresses on my machine. Otherwise, it's not going to magically go from 42 to one back to 42 without me saying it goes back to 42 again. Yep. Oh. Sorry. One. Yep. Yep. Yeah. So, well, that's a good question. So, hey, if I do, let's say, I won't write it out, but say, you know, I malloc something here. Does that mean I have to free in both the parent and the child? The answer to that is, yeah. But in this case, you malloc before the fork and then I could just, instead of putting two frees in two different branches, I would just put my free like here, right? Because they both will reach this point. I could reach, put my free here and then it'll get freed in both of them because they'll both reach this line. Good question. But yeah, but it'll be exact copy. So if you malloc and then you clone, that will, you can think of it as it malloc too. So it's going to have to free. Yep. Sorry. Oh, so you're wondering if I can do something different than copying the whole process because that seems kind of wasteful? Yeah. So we'll see why they did this because it turns out copying the entire process, you can actually make essentially free. So we'll figure out why that happens. But it's essentially free even though it sounds like copying the entire process, including it. Imagine this was Chrome and that you have all your things open. That's 10 gigabytes. And then you fork it. Does that mean that suddenly I'll have another copy that's independent and then another one that takes 10 gigabytes and now the total is 20? The answer to that is no and there's some magic we will see for that. Yep. So there's a question. If I copy one of the PID folders in PROC, does that move it to a different number? That answer is no. So it would, yeah. If you copy it, I think it would just create real files out of it that actually exist. And then they would just be frozen whenever you copied it. So it wouldn't get deleted or anything like that. All right. Any other fun questions? Yep. Yeah. So that's a good point. So that means that the parent process, the thing that executed this main was at one point an exact copy of the shell. And yeah, that's true. Kind of weird, right? Yep. Too long? Yeah. So the question is, does the process get too large? So aspects of the program can get too large. Like it can use a lot of memory. We could also get into the point where we create too many processes. That's also a thing because they don't have to exit, right? They could all just keep doing stuff forever, which is not good. And we could also do more fun things. So someone said this. What did someone say? Someone said this, right? Oh, that got some faces going. What happens in this case? Oh, yeah. That's be prepared. This is like the questions we'll have to answer now. So what happens in this case? Anyone want to give it a shot? Yep. Yeah. I'll end up with four processes. Is that going to be your comment too? Yeah. Well, what's going to happen here? So let's try and break it down and we can go ahead and, well, we can just run it, right? So if we run it, we know that each process prints three lines, either parent or child. So let's go. We can see that this is one process. This is another process. This is another process. Well, these are two of them fighting. So these are two more processes. So in total, there's four processes just by running it and counting. So what does that look like? So what did we do? So let's erase what is currently here. So we essentially just put a fork after another fork, right? So what's going to happen? Well, our world is the same. I'm going to just make up process IDs to represent processes. So I'll say process one. That's our original process that starts executing main and it would start executing main and then it would go ahead and then call this fork. So assuming that fork is successful, it would create a new process that is a copy of itself. I can go ahead and call it process two, like this, and then I'll just do this to denote that process one is the parent, process two is the child. So it would look something like that. So now there are exact copies of each other at the time of the fork, which it didn't really do anything. So both of them would assign their values to PID in the parent. Anyone want to tell me what would return? Yeah, two, right? Because that is the process ID of the child. So I just called it process ID two. In the child, what would it return? Big zero, right? Because it is the child. So now they're both going to go on their merry ways. This one would... In this one, PID would be equal to two. This one, PID is equal to zero. And then they both fork again. But you don't know which order they are, so let's say process one reached the fork first. So let's make it red, because that's a good color. So process three would get created by process one. So it would look like this. And in the original process, its second fork would return three, because I just created process three. And in process three, its fork would return zero. And because I didn't assign PID to anything new, well, because this is a copy of the parent at the time of the fork, its PID would still be equal to two. Because I didn't change it. I didn't assign it to anything new, I just kind of threw it away. So, at the time of the fork for process three, process one would have already assigned PID to two. So it would return zero from its fork, and then carry on its merry way, make it to the end, do whatever. Eventually process two is going to hit the fork, and it would create a new process called process four. And process four would be an exact copy of process two at the time of the fork, which means that its PID is equal to zero, because that's what it was in process two, and we don't reassign it to anything. And its fork would return zero. And in process two, the second fork would return four. Right, and it would also be the child of process two. So it would look like that. So those are our four processes with its relationships. Any questions about that? Yep. So a question, has this ever resolved as non-deterministic bugs, and the answer to that is, yeah. So this is, if you've ever used thread before, you will use threads in this course. Same problem, you can't tell the order of execution of anything at this point. Yeah. Oh, so there's a question, what's a non-deterministic bug? And it means it's a bug that doesn't happen every time. Because, remember when I ran this, I wasn't guaranteed if the parent or the child run first. Well, I might be in the case if I write my program run that if the parent goes first, everything goes fine. But if the child goes first, I have a bug. And then, if that's your bug, it won't happen all the time. It might happen sometimes. And that's basically the source of the hardest bugs you will ever find. So those bugs exist in the links kernel. And some of them have not been fixed for seven years. So it took seven years for some people to find them, maybe even more. So, these are the types of bugs we get to be introduced to in this course. So, lucky you. Yep. Yeah, so it gets a bit confusing because there's a lot of PIDs going around. Like, I think I updated this thing. If you called this return PID or something, it's more clear that this is a variable I'm talking about as opposed to a return value. So, yeah, sorry. Yeah, these are the actual PIDs that I wrote in the colors there. And they don't change. But the value of that variable because I only assign it once, it doesn't quite follow. Yeah. Yeah, so someone noticed that in my program I have this little sleep thing and that's me trying to make it more deterministic because if the child or if the parent finishes before the child the terminal gets all weird because the shell only cares about the process running. And if it dies, it returns and my terminal gets all messed up. So that's a way to try and prevent things but that doesn't guarantee my terminal won't get messed up. I'm just putting enough time there that whenever I run it, it usually works. So, doing this doing what I did to make things deterministic is not good. You will figure out how to do it the real way and guarantee that it happens in a deterministic way 100% of the time. Instead of this which is like, it might be 99.9 but you might go to like the ECF labs with terrible computers and that might not there might be not enough time so might not work or like when they're running like a DOS 1MHz computer or something, it's not going to work on that or something like that. So, it gets weird. Yep. So, if I said that, the comment was I said that the first process dies, they all die. That is not true. If I said that, I didn't mean to Okay. So, each process is independent so the only way for a process to terminate is it has to call exit. So, even though the parent could die first the child is still alive and we'll get into management in the next lecture. Alright, any other fun questions about FORC? Yep. So, that's just the way it works. So, if you create a new process, the return value of FORC is the process ID of the child and the reason behind that we'll see why the next, in the next lecture it's because we gave them the name of the parent because they'll have to take care of the child so that's why they get the process ID back. They can ignore it and be like, yeah, whatever, I don't need to deal with that but you get the number back for one reason because you need to, for the lack of a better word, manage the child. Alright, so people like FORC, anyone want to explain this? Yeah. What's going to happen if I run that? Yeah, someone just says my computer dies. Why is my computer dying? Yeah. So, essentially well, I'll start off with Maine Maine will start executing right? And then let's assume that this line doesn't exist. So Maine will start executing let's just say we go immediately into this thing then it will create a new process and now there's two. Now they're both going to go to the top of the loop now there's two processes each of those two processes is going to create another process. So we go from two to four through the loop again. What we get next? 1632 64 128 256 512 you can see this gets out of hand quite fast and essentially like the PID number is an int that like only goes up to what like 4 million or something how many times through the loop before we create 4 million processes and run out of PIDs? Probably not too long. I don't run out of memory on my machine first right? And guess what? Fork starts bailing at that point so that's how you cause Fork to fail there's a fun way to essentially do this to someone else's machine by giving them a shell command that doesn't look like anything but it essentially does exactly that and guess what happens if someone tries to run it it creates process after process exponentially until you run out of memory, you run out of process IDs and then your computer dies which isn't great so real quick I assume you want me to run this yeah okay so real quick before you break my machine let's go into real quick in like a minute how to actually start executing another program so it's another system called execve and that replaces the current running process with another program the process ID doesn't get changed or anything like that you just tell it another program to execute and then the kernel reinitializes the process control block and starts executing that program so for instance this is its API you have to give it the whole path of the program itself then argv so that's like what you get in C in main so you actually pass that so that's another thing your shell does is convert what you type into that and then it'll return on error if there's a failure and if it is successful it starts running another program and it never returns we won't have enough time for that so we'll go over that next lecture but oh jeez oh I don't have that whatever what's another fork right so if you guys are right if I compile and run this probably bad things are going to happen so it just looks like it's kind of running that doesn't seem too bad let's open another terminal that don't look good let's start typing help nope nope can't type in this control C that doesn't do anything this disappeared it looks kind of corrupted help hey it recovered there see it's all good so this recovered this recovered I can still use my machine you didn't break it whoops let's see if there's any messages from the kernel aha it was smart my computer was unresponsive for a little bit but essentially the kernel was like well fork rejected and then the kernel saved me and killed everything so if you try and do this on the school machines they probably have a lower limit for the number of processes you're allowed to create specifically to defend against you doing this but yeah don't run this on the school's machine but it should still work alright with that just remember pull before you we're all in this together