 All right, good morning everyone. So quick note about quiz one that is coming up what soon next week So you'll see that the other section is kind of behind us in some ways and we're behind them in other ways Don't worry about it We'll look at the quiz stuff together and anything that both sections haven't covered. We'll just throw out So we're all good and like for example, the other section doesn't know how to make processes yet. They haven't gotten to that fun fork orphan zombie discussion yet, so That and that's the hardest part of the course. So we essentially front-loaded everything the hardest part of the course is already over not really and Then Yeah, I guess that's it So quiz one two will be mostly like multiple choice true false like 80% of it And then the other 20% of it will be like here explain something Right, so they should not it shouldn't be too bad. It's only going to be an hour. So For better or worse, it'll all be over soon All right, so today we're going to be talking about IPC we can kind of relax and just learn for a little bit None of this will be on quiz one because the other section won't cover it But it's just kind of important just to help us understand what's going on There's some things at the end of this lecture that they have covered that I'll point out that is valid for quiz one But for like the first half of this course we can just kind of relax and enjoy the ride That is IPC or inter-process communication because remember if we have processes, they're completely Independent from each other one doesn't affect the other even if we change what looks like the same memory address They're completely independent. It doesn't affect the other one While in a lot of scenarios if we want to do something useful We actually have to communicate between two processes and the mechanism for that is called IPC Which stands for inter-process communication just a fancy way of saying communicating between two processes So any communication between two processes since by default everything is isolated. It has to be explicit and then therefore Explicitly allowed by the kernel right you want to make sure Processes are talking to other processes that they should be talking to So you can think of IPC at the most basic level as just transferring bytes between two processes and I mean in computing We're just transferring numbers between each other and just giving meaning to them Just because we want to right the the at the most basic level. That's all computing is So reading and writing files is even a form of IPC, which you've all done before Right, so if you have a process that opens a file writes to it that would create a process that process writes to a file and then later on if another Process reads from the file that's actually communicating between two processes that aren't even alive at the same time So another process comes reads from that file and that's how you get bytes from process a to process b Right, and that's all done through the read and write system calls And they just allow any bytes. They don't care So the simplest thing we could write Or one of the things we could write is a process that writes everything it reads Because remember we have these standard file descriptors. So standard input is file descriptor zero Standard output is file descriptor one so we could read from standard input, which is just By convention file descriptor zero and then we could write to standard output, which is again by convention file descriptor one and Let's go ahead and just see that and we'll see if it reminds of of any program. We've seen before So here is our program read rate So in our program we just declare a buffer of size 4096 this number will be important to you later on when we get to memory management, but for now we can just say hey It's a kind of big buffer So the read system call Takes a file descriptor a pointer to a bunch of bytes that you want to that can store some Bites that the kernel writes for you and then you have to say the size of it so we give them a pointer of Approximately 4,000 bytes and say hey you can write up to 4,000 bytes So this is in a while loop that just continuously calls it while it has some bytes read So the return value of read it returns a number of bytes read so if it's greater than zero it's read some bytes and We'll have to read more if we want to get all the bytes of that file descriptor So after we read some bytes we go ahead and write to File descriptor zero using that same buffer and just writing out the number of bytes we have read in and There it will also return the number of bytes written because the kernel Doesn't really care about you too much your write system calls merely a suggestion It can write zero bytes if it wants to and tells and asks you to retry Or it just might do partial writes and then you have to deal with the consequences at the end of that But it's a standard C function. So if there is an error it returns negative one sets error No, so we just print out our error and In this case I said that it might not write everything So I want to be lazy, but also be kind of defensive So I'm just going to assume that it always writes out the number of bytes I've read in before so it just outputs the whole buffer And I don't want to be caught by surprise So I just put an assert there that if it doesn't if it does partial reads or anything weird I'm just notified of it instead of like doing what Java likes to do and kind of failing silently and being possible to debug and Then at the end this right so the while loop will go through again while read is greater than zero Then there's two options to break out of this while loop One being if there is a error in read in which case, you know, it would return negative one and We assert that the only other value at this point if it's not an error and it breaks out that loop This is just a sandy check mostly for documentation because this should never Trigger is that the bytes read is zero and you'll notice that there's no like end of file or anything We could read an end of file. There's no end of file character or anything special The only way you know you've reached the end of the file is if read returns zero like I've out of bytes It's done. I don't have to read anymore So let's go ahead and execute that so it's just sitting here, right? the first thing it needs to do is Read and reading from standard input which by default if I just type something on my terminal It's just waiting for terminal input So I could do something like this and then if I hit enter, what does anyone expect to happen here? Yeah Yeah, so it should output hi hi hi back and anything I type here Should just echo it over and over again Until I hit on Unix if you want to like close the open file descriptor in your terminal You hit control D and that means end of file. So read would have returned zero and then it goes ahead and exits the process Does that remind us of anything? We've seen before might have used if we've used a bunch of Linux stuff before yeah Echo wait is that what echo does? No, nope any other little programs we've used if you want to display the contents of the file on your Terminal what? Sorry See yeah, so we could use cat. That's a that's another way to do it But that's like a full-blown text editor, but I could use cat right if I use cat And do it it looks exactly the same and I hit control D and it ends so What we just wrote is actually cat so cats not that complicated It's like but we'll see soon. It's actually kind of powerful to have that you've been using it And I mean how many lines did it take us to write it like even error checking it took us like 19 lines If that there's like header files up there, so it didn't even take 19 lines So that's the entire implementation of cat cat would do something smarter if there's like a partial right there, right? It would retry the right, but that's just another while loop. Oh We've written cat that's kind of cool Yeah, sorry So right will just always just keep on appending stuff By default Yeah, so the question is with the right does it just always append if it if the file descriptor happened to represent a file Or can we go backwards and overwrites things the answer to that is we can go backwards to overwrite stuff But we won't see that till later, but the default behavior is just to keep on appending bytes to the end Yeah Yeah, so the question is is If inner buffer there happens to be a null byte somewhere Does that stop writing and the answer to that is no the kernel doesn't care It's just a bunch of bytes if it stopped at the null bytes You suddenly wouldn't be able to write zero to any file, which would be really really weird The kernel doesn't care a null term name string is just a C convention. The kernel does not care whatsoever about it So you can write anything including the null character. It'll just keep on going it'll write as many bytes as you ask it to No matter what the byte is okay So let's extend this a bit. So here's just just for your Reference read just reads from a file descriptor and if it returns zero it means There's no more data to read from there that that file descriptor is essentially done with and you could go ahead and Close it or just ignore it. Whatever you want to do but always you should always check for errors to like Especially for Right, it's kind of weird because we now know printf calls, right? And it might not ever write the bytes at printf actually has the same return type where it tells you the number of bytes It's written but who's ever checked the return value of printf? Right one person Alright one person's checked the return value printf but we just kind of assume it works because For the most part if it's under four thousand that four thousand ninety six bytes, it'll always work For the most part Yeah, the right just returns the number of bytes written you shouldn't assume it's always successful. We'll see Actually, we won't see that but you shouldn't assume it's always successful But I guess for the purposes of this course if they're small you can assume it's successful But always programmed defensively put some asserts that So if you're not right, you actually know what happens and can actually fix the problem so and of course Communication to two-way channel right in our process we read from standard in and then write to standard out well Some something was communicating all the bytes. I you know, I Typed in to my process So there had to be some corresponding thing on the other side of that file descriptor So whatever file descriptor zero was in my process Someone called write to write some bytes to it that I could read in my program and then consequently When I wrote some bytes out another process had to read the bytes out so it could display what I just wrote Right and that's kind of a powerful concept. We'll see as we go on So, yeah, and there's a reason for doing the standard file descriptors as opposed to just confusing you relentlessly So what we could do as a little trick is we could close standard input, right? There's a close system call that just takes a file descriptor that closes up a file descriptor So we don't can't use it anymore We could close file descriptor zero that would free it up and open a file instead right in lab one You had to do that open system call that returned the file descriptor So Linux and other unique systems just will use the lowest available free file descriptor for new ones So by default you'll have like zero one Sorry zero one and two open so if you open just a new file you'd get it get file descriptor three But if you close file descriptor one and then open a file that file will be file descriptor zero So let's see what happens when we change that So we're going to keep the exact same core loop we had before and we're only going to add a open call so here we just checked that there are at least two arguments and if there is Yeah, if there are exactly two arguments if there are exactly two arguments we take the Argument as a file we open it as read only and then open will give us a file descriptor And this case since we close zero it would get assigned file descriptor zero and then otherwise We'd have the exact same program as before So without changing anything it's now going to Read from a file instead of read from my terminal right if I execute if I be meta and do open example and open example C read now instead of reading from the terminal should be reading from that file and again We didn't change where it's writing to so it should just appear on my terminal right, so does he so That's the contents of the file. It's now on my terminal and that's the exact same thing that would happen if we catted that so We were missing some functionality of cat, but now we have it so we've written a full cat program now Right, and we didn't actually have to change the core logic here, right? We just we just read from descriptor zero and we wrote to file descriptor one and By changing what file descriptor zero was we can support lots of different things and now we can support a terminal We can support files and all that great stuff Any questions about that? kind of cool well, I Didn't actually have to I could have just kept my read write example if you're using like bash or something like that bash allows you to change Where file descriptors go and will open files for you So you can support files without ever having to write any open system calls or any file handler code whatsoever So in this example, this could be read write example because I don't give it any arguments You can use this character on your terminal and It will essentially replace file descriptor zero Which is why it points into the process so you can think of as changing standard input with Open example dot C so your terminal itself will open that file for you and then feed it into that program So even if I do the read write example that doesn't have an open system call whatsoever and I feed that file into it I Get that file right back out right Okay, we don't want to do that. So I get that file right back out. So The way standard file descriptors work is hey your programs can even if your program doesn't support files Through kind of just modifying what file descriptors point to you can have it support files Without the process itself actually having to support files So you didn't actually have to write that system or that open. We just kind of wasted our time other fun things you can do is there is this pipe character that essentially takes a process on the left and Connects its standard output to the process on the right So anything that comes out of cat open example, which would normally go to file descriptor zero right standard output Which would just dump the contents of a file instead of going to your terminal it would go to this process as standard input So let's see that So if we just cat open example dot C we get the normal file Otherwise we could We could cat it to open example or we could just pipe it to open example dot C and it should just pass into our program and Then we would write it back out again. So this is kind of a roundabout way to do that. I And you could also link them together So our program was essentially cat without argument So I could do this as many times as I want because cat just you know reads in everything. I it Right so everything it reads in so I could connect This just connects the two processes on either side so I could connect them as long as I want and I'll get the same output again So you could of course do something much better than that So the other way so if there's an arrow going to the left you can also have an arrow going to the right so What you could also do if I cat you know open example dot C by default they'll just go on to My terminal because that's what standard out is connected to But if I use this arrow So if the left arrow goes to standard in the right arrow goes to standard out So I can make it right to files without having any file handler code So I could say output dot txt and then that would Take that open example dot C redirect it to a file called output dot txt now if I look at output dot txt It's going to have the exact same contents right and also What does this? Actually remind you of Yeah Yeah, so Because of the Unix philosophy of having all these file descriptors you actually don't need a CP command You can just use cat and redirect stuff. So copy is mostly just for your convenience Otherwise you can all you really need is cat Which is a dead simple program just writes out everything it reads in and hey you can copy files You can do all sorts of fun stuff That pipe character. Yeah, so it just connects This process is standard output to this process is standard input Yeah, so if I just run this example dot C It'll just show that contents of the file on my terminal if I Instead do that pipe character. It'll feed that contents to this process Which unfortunately just does the exact same thing but instead of going directly from This process to the terminal it goes from this process To this process and then this process that puts it to the terminal Yeah, yeah, yeah, that's just error checking code. Yeah, so it's like a standard C wrapper. So if it returns negative one, there's an error and it sets error. No Yeah, so that's just a standard thing that C sets for you for now until we learn about threads It's think of it as a global variable. So it's a global variable that C controls for you Yeah, yeah that and that's just the convention. That's just the Unix convention Yeah, so the question is is it always guaranteed that zero is like valid and can read and No, it's just a convention. Thankfully everyone follows it because your programs work But it doesn't have to be it's literally just a convention that everyone agrees to follow. Yeah. Yeah Yeah scanf just reads it does the same thing it just reads from the standard input so if since we know more about offering systems, you can change the standard input yourself and Similarly, I could close file descriptor zero open a file and then my print f's instead would go that file Yeah, yeah, it just keeps on going So like this so instead of just you know before it just took this output provided it to here and Cat just reads everything it runs in right so this output is going to go into the input of this Which is gonna output the same thing which is gonna go to this Which is gonna output the same thing which is gonna go with this Sorry Here's like the space doesn't mean anything And this is so the output of this would go into this process this cat Yeah, and then the output of this cat would go to this one Then the output of this cat goes to this one Then the output of this we didn't we're not changing file descriptor zero or one on this case And by default still the terminal so this one would actually print to the terminal Which is why I see something at the very end Okay, yeah In the code So file descriptors are unique So if I open two files one's gonna get file descriptor in this case One would get file descriptor zero the other one would get file descriptor three Yeah Yeah, and also So the question about the conventions of files. Hey, well is file descriptor zero always valid Well now it's not so someone else could do this to you just close zero and then start your process so if I do that and was If I do open example Give it an argument and I try and read it says bad file descriptor. So a good thing. I checked my errors So someone could have done this to you and then suddenly your process runs your file descriptor zero is not valid And you can't do anything because it's not valid So this could actually happen to you so always good to check your errors But if that happens someone someone not you is has a not followed conventions and something horrible has happened Okay, so this is kind of the more important thing it signals which you can think of as Interrupts, but they're interrupts for user mode. So everyone's seen interrupts and kind of used them before So has anyone ever like when they run a program hit control C? We've all hit control C How many times? Has it ever happened when you hit control C that the process doesn't end? Does anyone know why that is? Yeah, okay, so they're free to ignore it. So Signals are form of IPC and again we think of them as you can think of them as interrupts for user level programs So what you saw in your other course when you did interrupts at a hardware level The kernel would have to do that and we'll see some details of what the kernels job of handling those interrupts are Which are valid for quiz one but for now we're going to play in user land and it's essentially interrupts for user processes so if I Try and control C my open example or the read-write example We'll see that it behaves nicely. So if I run it and hit control C whoops If I run if I run it if I run open example and hit control C It stops and I can type back on my terminal again, which is what we expect But now we notice something kind of odd. What is this? Yeah, so that means that the process exited with this as it's like exit code and Nowhere in my program. The only thing I returned from main is a zero. So the question is who called exit 130 Not not you So we're going to see what we can do and answer the question Why some programs don't die when we hit control C? Yeah, so it's basically an error of Tanner. So we're going to see how to do that so control C just sends a signal to your process which is basically an interrupt and a signal is literally just a number and there's just Some numbers that you have to look up in a table or they're given names and you have to just kind of figure them out So control C sends a signal called SIG int so it's supposed to represent an interrupt from keyboard That the kernel passes on to you because usually that would have to be dealt with in hardware and Then there's default handlers that you don't have to write so there's the default handler for interrupt signals that you don't have to write will just exit the process immediately and It will add 128 to the signal number for its exit code So if we do a little bit of math, we got Returned 130 all 130 minus 128 signal interrupt must be signal 2 So let's go ahead and write our own signal handler. So this is basically how you set your own interrupt service routine So let's go ahead and see an example of that and here are a list of some of the signals So 2 is SIG and it which is interrupt from keyboard And there's some signals that are non-standard, but these are the ones you'll probably have to deal with and There's SIG kill which we saw last lecture, which was like the uber kill so that's number 9 and that's terminate immediately and you can't install a signal handler to interrupt or to kind of Handle that signal because it's all done by the kernel and then remember your process is ultra dead at that point Then we see everyone's favorite signal 11 So that is a memory access violation. That is a segfault Which kind of begs the question if it's a signal and I can handle it Yeah So you can actually a segfault is not the end of your program you can catch it and you can keep trucking on if you want and Then the last signal is signal 15. So that's like the nice way to tell a program Hey, you should stop whatever you're doing now clean up your resources Please shut down and that's like the nice way to tell a process to please shut down. So that's the default thing to do All right, let's just see what that looks like. It's a bunch of code that we can gloss over thankfully So in our signal example It's otherwise exactly like our open example and the only thing new is these register signal functions so basically this register signal functions all it does is register a Signal handler to run whenever this process receives the signal So this signal wants to handle sig int so control C basically or sig term Which is like the nice way of saying shut down Then in register signal the system calls called sig action and How that works is you just declare a struct of sig action and then you Would empty it with this to set it to null values and then you can specify a Signal handler, which is just a function, which is something that you can write and then you just call sig action to say Hey, I want to handle the signal and this is the function to call and Register signal this Format is something you'd like only ever write once you'd like look it up on stack overflow and then forget you've ever done it again So in the handle signal it takes the signal number as the argument So we can reuse it to see what signal it came from and Here's my amazing handle signal code, so I'm just gonna print F ignoring it and I'll return so now if we execute this program and I hit control C. I expect it to just keep on trucking but if I press control C it says ignoring signal to and then It would have returned so remember this is like an interrupt So you can't control when it triggers or anything So wherever your process is executing as soon as the signal comes in that signal handler is going to run no matter where your Program was executed, so it just boots it out and then runs the signal handler code to completion So it would print F ignoring signal and then go back to whatever the process was executing before Which in this case before I hit control C. It was just waiting for me to write output and we see good thing we programmed defensively because The read system call gets an error and when it prints out the error it says interrupted system call So you actually have to retry system calls sometimes because they can get interrupted by signals so the fix to that is we can write a Another version of the program that in the while loop It sees if there's an error and if there's an error and its error no is equal to this number that you would have to look up That represents an interrupted system call. We know that Read didn't return anything bad that file descriptor is probably actually fine I just have to retry read so I just say continue so I can go and issue another read system call So if I do that now and run signal example to that actually retries now if I hit control C It just says ignoring but otherwise continues on as normal and I can say hi hi Repeats back to me. I can hit control C again, and this is like your program that just ignored you. Yeah, I Feel like it Code or Terminal for oh this So that's the code for the interrupted system call So I just return that at the end that I return error. No if I see an error That's just the number that means the system call got interrupted No, so this handle signal this gets executed whenever it a signal comes in it's exactly like an interrupt service routine So no matter where your program is executing that handle signal will get called whenever it gets a signal So every time I hit control C. It gets executed in this case. It just straight up ignores me right and because In the other way to send signals to processes, so this is control C sends a signal But the other way is you know because of our violent natures instead of things being called Send signal or something weird the command is called kill to send a signal So I can look up what that process What's the process ID of that example? That's running by running pit of it's called signal example? To so I can get its process ID. Yep Yeah, the kernel would have something that's like an interrupt vector table for your process Yeah No, it's still running it's just Oh, yeah, so I just opened another terminal up there. So it's still running. It's still happily ignoring me because You know, I'm hitting control C. It's not happening. So Whoever had that program you can kill with control C. Did something like this? Yeah, sorry That's just the error code for an interrupted system call Yeah, and I know I can just restart it So here I got the process ID of that what's running in my other terminal And I can send a signal to it and we of course do that with a kill command because we are violent people apparently So kill Essentially all this program does is do a system call kill. So kills a system call that sends a signal to a process So if I kill that like I really want to end my program We can see that by default it'll send signal 15, which is the please shut down. And of course I ignored it, too All right, so my process is still happily running And I ignored it But if you're writing any kind of good program that behaves normally kill should actually like actually Kill it and it should you know clean up all three sources free whatever it needs to do and then carry on well We learned last time what's ultra kill? dash nine right so If I do that it's now dead-dead and it says killed Yeah, if it was still running yet Yeah, yeah, you can kill any process on your machine and Yeah, you guys statistically made me kill my internet process and close out so you can kill whatever you want And just to show that we keep that kill is you know special Hey, what about if I just want to try and ignore kill Right like I don't want to listen to the colonel screw the colonel If you do that It says hey sig action in valid argument. You're not allowed to ignore kill Even though it wouldn't run it anyways it still kind of saves you from shooting yourself in the foot. Yep Register signal here it is so it's basically just declaring a struct and then Setting it to whatever it represents null values as to that function and then it just has a field called SA handler, which is a pointer to a function and that's just the function to run and Then this is this is a system call that registers that action to it So you can do more for an action But for now for the purposes of this course we just say what function we want to run when a signal comes in Okay, so that is Was fun so and This is kind of an example of concurrency too because our process Switches to the interrupt service routine, but it's also not exactly concurrency because it can't switch back and forth again As soon as it starts running that interrupt service routine, it won't stop until it's done and We'll see that Here's just for reference that you have to account for interrupted system calls sometimes because signals will do that to you signals are actually kind of the bane of programming on Linux and You'll have to use signals in lab 3 for stuff So lab 3 is probably going to be hard because you have to deal with this stuff So here's just more reference to send signals to processes using their PID This is just documenting what I showed previously when you got the process ID and tried to kill it Okay, so here is the more Valid stuff so most operations on your computer are like non valid. So think if you're the kernel having to deal with hardware changes Most things would be kind of like the non blocking nature So remember when we called wait before it just blocked until a child died and then it returned and then we handled it so For the most times especially if you're dealing with interacting with hardware There won't be special function calls for hardware that block They'll be non blocking you'll have to check a value or something like that and see if there's a change So just to kind of illustrate that we'll turn wait into a non blocking call We have to use wait PID With this no hang option and then it will make it return immediately. So and that's how Wait PID will return a process ID of zero instead of you know being an error or the child that died because now You know if you just poke it and say hey is a child dead the answer could be no So if you get a zero back from that it means you have a child, but they're not dead yet right So if you want to react to changes to a non blocking call we can either pull it So we just keep on trying it or we could hopefully have install an interrupt And this works at a user level and also at a hardware level. So because we're writing user code We're just writing C code. We'll see the We'll see what it's like at a user level So let's go look at our pull example So just to illustrate that Wait, so in our main program We're gonna immediately fork create two processes who cares about errors if it's the child It's just gonna sleep for two seconds and then exit. So the child process is just gonna sit sit there for two seconds and then you know exit normally in the parent process We'll set Temporary with wait PID to zero which should mean the child's not dead yet So we'll just initialize it to zero and we're gonna count how many times we call wait PID So we just have a while loop that keeps on pulling it So keeps on asking is the child dead is the child dead is the child dead over and over again And we'll go ahead and count the number of times we make this system call So if we go ahead and execute that which is wait pull example, we'll see Yikes so I called wait PID Over 200,000 times that does not seem like a good idea Yeah, anyone want to tell me was that a good idea why I just did or what's the drawback of that approach So I just wasted a bunch of time, right? It's just Pulling over and over again for over 200,000 times There is no change could anyone think of a better way to pull this without wasting so many calls. Yeah Without interrupting while still pulling Yeah, so if I wanted to To bring that number down. I could just you know, if it doesn't work I'll just sleep for a second or something like that Then if I do that Call wait attempt attempt. Oh, okay. Now it eggs it in. So what's the drawback of doing that now? Yeah Yeah, I don't know how big of a gap I choose there's some type of trade-off, right, which is why we're in engineering so If I set a number way too big, it's not gonna be terribly responsive, right? Because here I could wait up to a second Before I actually noticed that the child dies But the smaller I make that weight the more overhead I'm going to have because most of the calls are going to be useless, right? so having that trade-off between how many times I pull verse verse Yeah, how long I wait is one of the trade-offs you have to make But the better option is to just interrupt. So luckily for us Whenever your a child dies you happily the kernel actually sends you a signal So we'll go ahead and combine the two things we did and we'll register the signal called SIG child Please don't ask me why it's missing an eye We're we're programmers. We're trying to be efficient as possible So in this case it forks and to show that you know The signal will actually interrupt us in the child. We're gonna do the same thing fall asleep for two seconds and exit But in the parent, we're just gonna have an infant loop that sleeps for 9,999 seconds So it's the parents not gonna do anything useful. It's just gonna sleep pretty much forever So in our signal handler, we'll check that the We'll check that we're actually getting a SIG child in this case. I only installed that signal handler. So That should never be true. But otherwise I Handle that signal and inside our interrupt service routine I call wait there and I'm doing the same thing with no hang and This is just a shortcut just because I don't want to when you fork You'll know the process ID of your child, but I wanted to be lazy here and not save it as a global variable or something So if I put negative ones the argument wait PID becomes exactly like wait So it'll wait for the first child to return in this case. I only have one child, but So it shouldn't matter what I use And then if there's an error from that, I'll just return that I'll just print that error Otherwise, I will print wait and then I will end this process. So it should die as soon as my child dies So if I do the interrupt I The main process is asleep and now it gets interrupted with SIG child because the kernel nicely Sends it to me and then I call wait on it and it immediately returns and that's probably the better way to go about things All right, let's I'll quickly go over code and then take some questions So that was pulling this was interrupt So on a CPU if you're in kernel LAN So these signals are just like interrupts but for user mode But if you are you know the kernel and have to deal with real interrupts There's kind of three different categories You have to consider if you're the kernel and their name different things annoyingly So a true interrupt is triggered by some external hardware, you know like a keyboard Disks something like that and it's handled directly by the kernel And that's kind of what you did in your computer organization class All right, the kernel needs to respond super quickly because it needs to react immediately So it would just take that interrupt another interrupt is called a trap and that is triggered by users So for example a system call is an example of a trap So it's an interrupt that users are allowed to raise That the kernel handles and that was that SVC instruction or on Sun systems It's just called system call and that's handled by the kernel Which would suspend the calling process then handle that system call And then it would you know resume that process whenever the scheduler feels like it should run Then the last one is called an exception triggered by abnormal control flow so these again are handled or are triggered by user processes There are things like divide by zero illegal memory accesses and by default the handler is the kernel But you are allowed to overwrite this So with signals and that's the only way you can do interrupt like things as a user process So the process can actually handle those kinds of traps themselves so again, if you really wanted to you could handle your own seg faults and you know Magically solve them and then keep on keep on executing and Some programs actually trigger seg faults themselves so they can get interrupted, but it's like a whole weird dumb thing All right, any questions on that or the signal for the child or anything else? So and this stuff is like I've directly pulled this off. So this is like very valid for a quiz No hints or anything, right Yeah Well control C would be The yeah, it's it's more like an exception kind of because you're allowed to intercept it So it's kind of abnormal, but someone's triggering it for you So trap is just like a system call is a trap So you trigger it as well as a user process Yep Yeah, or like any Things the CPU itself has to deal with and then the kernel would have its own interrupt service routine for dealing with Keyboard input or whatever Yeah So that just means an error Yeah, all right. So wrap it up. We explored basic IPC that'll serve as well You even use the open system call in the first lab. So read write all good redirecting file descriptors is pretty cool Signals are not so cool, but we have to learn them They're kind of like interrupts for user process and the kernel has to handle all three different types of error ups So just remember pulling for you. We're all in this together