 Hello. My name is Jerry Cooperstein. I'm the Director of Training at the Linux Foundation. Today, I'm going to give you a sense of what we do in one of our popular classes, LF312, which is developing applications for Linux. And I'm going to do a section briefly from the middle of the class on how to create and destroy processes. This would normally be reached on the end of the second day or the beginning of the third day of a five-day class, which has 30 some odd sessions. This is session number 15. And before we get to this point, we will have already discussed things like how to compile integrated environments to use in Linux, how to make debugging memory allocation and extensive discussion of file, input, output, writing, reading, and other more advanced IO commands, as well as earlier session on processes which explain what they are and how they work in a Linux and Unix context. So here we're going to talk about how to create them, how to destroy them, etc. So let's get started. And I'm going to begin by showing section 15, which has several sections first about different methods of creating processes. In particular, it talks about system fork and exec. And then also a system called clone, which is unique to Linux, does not exist in other Unixes, which creates a processes with some very special properties. And then we'll talk about different methods of exiting or destroying processes. And we'll talk about waiting, how to wait for a process to be completed. And then we'll talk about daemon processes, which you kind of start in background with a limited set of commands. In subsequent sections during the week, we'll go into great detail on things like inter-process communication, talking about all the different methods of doing that. We'll talk a lot about networking and sockets. We'll talk about multi-threaded processes. We have several sections on how to create multi-threaded programs and write them in an intelligent way. So this is just sort of giving you the setting of how that fits into all that. The first function we discuss for creating a process in Linux is the system command. The system command is very simple. You simply call system and give it as an argument. The program or command that you would like to create a new process such as in this little example down here in the middle of a print statement. And that simply starts a new process and does whatever you put as the argument for the system function. Now, the problem with system, while it's very easy to use, it's expensive because it creates a whole new fork, which we'll talk about next to do something in a pipe in order to get access to the output. It's very sensitive to things in your environment such as various environmental variables. So it's easy for somebody to do an exploit where they make your command do something very different. All they have to do is reset your path in your environment, for instance, so it's very insecure. And it certainly should never be used for anything which is run with super user or administrator privilege. I often tell people it's okay to use system when you're doing a quick hack and trying to figure out how to do something, but I would never put it in a program that I'm delivering to somebody who's paying for me to do it. It's insecure and it's kind of expensive, but this is simplest and quickest way to do something. The fork system call creates what's known as a child process. This is an extremely common thing to do throughout the history of UNIX and certainly Linux for decades. Once the child process is created, it's a full peer to the parent. It has complete access to all the memory, file descriptors, environmental variables and everything associated with the parent. So it's a very, very common way to create new processes. In fact, the way most of them are created in Linux or any kind of UNIX type of operating system. When the child is created while it receives a complete copy of memory, etc., from the parent, it uses what's called a copy-on-write technique, which means the child shares these resources with the parent until one of them makes a change. So for instance, if there's a memory region, they both share the same memory region until the child or the parent writes to it in which case they get their own copy. And this is done on a page-by-page basis rather than the whole memory region. So like most architectures in page of memory is 4 kilobytes. So if you have like a 4 megabyte buffer and you only change a few bytes in it in the child compared to the parent, you only allocate the memory for one page rather than the whole 4 megabytes. So it's a far superior way to do things than to simply give the child a complete copy of everything to begin with. So copy-on-write is important and Linux has very advanced methods for doing copy-on-write. We mentioned in the class a little bit about Vfork, which is an older UNIX command, which is like fork, but the parent is blocked from running until the child is done and has a true share of memory. But these days it's kind of obsolete, but you'll find that in old programs, so Linux knows how to implement it properly. So when you run the fork command, you get something like this where in your main program you call fork. And then after that, there are two processes running through your code. That's why it's called fork. You can think of a left fork and a right fork. In this first branch here is the child process, and the second one is the parent process. So you have two different things running through your code from then on. Later I'll talk about how to wait. You can have the parent wait for the child to finish before going to do something else, for instance, and that's very normal. The next way to create a new process is with the exec function. Actually there's a family of exec functions, exec ve, exec le, etc., as itemized in the text here. Each one of them is the same except they specify the arguments in different ways. The arguments include the arguments to the program you want to run as a process and various environmental variables that should be set if you need to do that for the program that runs. Once the new process starts, the exec function never returns and the old process that called exec is over, and the new process obtains the process ID of the original process. So it's like create, replace, kind of method. It's extremely common to do this in Linux or any kind of Unix operating system. And in the text we give various examples of how to launch it to do various things, and I recommend you look at that, but I won't get into the details here today. The other way to create processes or threads in Linux is with the clone command, clone function. The clone function is unique to Linux. It's not used in other Unixes. It's not a POSIX command. It's the underlying method in which all new processes are made in Linux in our kernel. Internals class we talk about how clone really works inside the Linux kernel. What makes it different than an exec or a simple trial process is that you can control exactly what resources are shared between the parent and the child created process. You can decide to share only memory. You can decide to share memory and signal handlers. You can decide to share memory and environmental variables, etc. There are several different flags that you can control, that control exactly which resources are shared and which are kept independent. If you keep things basically independent subject to copy and write techniques, you get a traditional Unix fork command, and inside the kernel in Linux the clone, the fork command is cloned with certain kinds of arguments that include things are only shared until resource changes such as a memory region. If you want to do a multi-threaded program, for instance using the P-threads library, the posix threads library, which we talk about in a later session, then you call the clone command with the flags specified that everything should be shared. So that, for instance, memory is shared means that if the child process makes a change in memory, the parent sees it immediately. So that's all done through one command with different flags on the user side. And on the next page in the text we go through these different flags and talk about what happens if they're set or not set, etc., and talk about the arguments to the clone function. The one argument to the clone function that's a little tricky is the second argument, which is the child stack pointer. And we discuss in detail how you set that when you're doing a fork, how you set that when you're doing a multi-threaded program, etc. And we have a lab that experiments with this so people learn how to do it more thoroughly. The next section, the fifth section in this chapter is on exiting. And it just talks about what happens when a process terminates either normally or abnormally, how exit codes are handled, etc., and various kinds of exit handlers you can put in so that you can deal in different ways with successful terminations, unsuccessful terminations for different reasons and how your program can be informed about what the reason for termination is so it can take an appropriate response to that. The next section is on constructors and destructors. Using the GNU-Live-C, G-Live-C, it's possible to have certain operations happen every time you create a new process. Those are constructor functions. And other things happen every time the process terminates. Those are destructor functions. And we teach people how to do that and once again we have some labs in which people experiment with that. So this is code that's not directly part of your application but gets called whenever things start up or finish. And then the next section here is on waiting. We talk about what happens when a process waits for another one to terminate. Typically parent processes wait for child. Processes to terminate either normally or abnormally. And so we go into detail into the wait function, how to check the return value to see why a process is terminated, etc. We also talk about what are called zombie functions, zombie processes. A zombie process is a process which has terminated but nobody has asked why or whether it has terminated. So in that sense it's a zombie because it gives up all resources so it's really kind of dead but it's the walking dead. It's still persistent until somebody asks what happened to it. And then we have a lab that plays around with zombie processes and tries to see what happens to them. Linux does not tend to generate a lot of these zombie or so-called defunct processes unlike some other operating systems. Because when the parent dies, child processes are adopted by process number one, the init process. And the init process periodically checks on the status of the children and waits for them. There's generally somebody always waiting to see what happens to you if you happen to die. And then I guess the last section in this section is on what are called daemon or daemon processes. It's a variation on fork and exec where you create a child process which has rather limited set of privileges. This is often done for background services, etc. Because you never want them to have more privilege than they absolutely need for security and stability reasons. And so we show people how to set up daemon processes, etc. And we also have labs that do that. So typical of our training sessions, each session has a bunch of different laboratory exercises. In this case, in this chapter, they're all C programs that you have to write. And they demonstrate many different features. The first one has to do with forking and the second one has to do with zombies and how to kill them, which is always fun. The third is more about waiting, how to successfully wait for a process to be finished and reap its exit code. The next one is on cloning and it teaches you that unique Linux function clone and how to create a variety of different kinds of child processes with variations on how many resources they share. And then the next one is on exiting, playing around with exit handlers. There's another exercise here on memory mapping, which ties into earlier sections. And we talk about how to use anonymous memory mapping to share memory between a parent and a child, instead of having them have independent memory. So it doesn't stand on its own with this chapter, but we've already talked about memory mapping. And so this flushes that out some more. And then the last exercise is on creating a daemon process and showing you how to do that. So that's a fuel for what we do. You know, obviously we would take much longer in the class and we would give people a long time to do the laboratories. There's too many to do in the normal class time, so people will pick a few of them that interest them the most and maybe play with some of the others. I'd like to thank you for viewing this brief introduction to LF312, Developing Applications for Linux. On our website we have detailed information and outlines for the class showing all the different sessions and what we discuss in them. I recommend highly you look at that and consider signing up for the class. People really enjoy it and they learn a lot. So we look forward to you getting in touch with us about it.