Page 415 - DCAP103_Principle of operating system
P. 415

Principles of Operating Systems



                   Notes         every year on October 31 to stock up on trick-or-treat goodies for Halloween. Other daemons
                                 handle incoming and outgoing electronic mail, manage the line printer queue, check if there
                                 are enough free pages in memory, and so forth. Daemons are straightforward to implement in
                                 Linux because each one is a separate process, independent of all other processes. Processes are
                                 created in Linux in an especially simple manner. The fork system call creates an exact copy of
                                 the original process. The forking process is called the parent process and the new process is
                                 called the child process. The parent and child each have their own, private memory images. If
                                 the parent subsequently changes any of its variables, the changes are not visible to the child,
                                 and vice versa.
                                 Open files are shared between parent and child. That is, if a certain file was open in the parent
                                 before the fork, it will continue to be open in both the parent and the child afterward. Changes
                                 made to the file by either one will be visible to the other. This behavior is only reasonable,
                                 because these changes are also visible to any unrelated process that opens the file as well. The
                                 fact that the memory images, variables, registers, and everything else are identical in the parent
                                 and child leads to a small difficulty— How do the processes know which one should run the
                                 parent code and which one should run the child code? The secret is that the fork system call
                                 returns a 0 to the child and a nonzero value, the child’s PID (Process Identifier) to the parent.
                                 Both processes normally check the return value, and act accordingly. As shown in Figure 14.4,
                                 processes are named by their PIDs. When a process is created, the parent is given the child’s
                                 PID, as mentioned above.

                                                        Figure 14.4: Process Creation in Linux

                                                           mechanical, photocopying, recording, or likewise

                                     pid= fork();             /* if the fork succeeds, pid>0in the parent */
                                     if (pid<0){
                                         handle_error()      /* fork failed (e.g., memory or some table is full) */
                                     } else if (pid>0){
                                                              /* parent code goes here. /*/
                                     } else {
                                                              /* child code goes here. /*/
                                     }

                                 If the child wants to know its own PID, there is a system call, getpid, that provides it. PIDs are
                                 used in a variety of ways. For example, when a child terminates, the parent is given the PID of
                                 the child that just finished. This can be important because a parent may have many children.
                                 Since children may also have children, an original process can build up an entire tree of children,
                                 grandchildren, and further descendants. Processes in Linux can communicate with each other
                                 using a form of message passing. It is possible to create a channel between two processes into
                                 which one process can write a stream of bytes for the other to read. These channels are called
                                 pipes. Synchronization is possible because when a process tries to read from an empty pipe it
                                 is blocked until data are available. Shell pipelines are implemented with pipes. When the shell
                                 sees a line like sort <f | head it creates two processes, sort and head, and sets up a pipe between
                                 them in such a way that sort’s standard output is connected to head’s standard input. In this
                                 way, all the data that sort writes go directly to head, instead of going to a file. If the pipe fills
                                 up, the system stops running sort until head has removed some data from the pipe.
                                 Processes can also communicate in another way—software interrupts. A process can send what
                                 is called a signal to another process. Processes can tell the system what they want to happen
                                 when a signal arrives. The choices are to ignore it, to catch it, or to let the signal kill the process
                                 (the default for most signals). If a process elects to catch signals sent to it, it must specify a
                                 signal handling procedure. When a signal arrives, control will abruptly switch to the handler.
                                 When the handler is finished and returns, control goes back to where it came from, analogous
                                 to hardware I/O interrupts. A process can only send signals to members of its process group,



        408                               LOVELY PROFESSIONAL UNIVERSITY
   410   411   412   413   414   415   416   417   418   419   420