Previous Section  < Day Day Up >  Next Section

1.5. Processes and the Shell

A process is a program in execution and can be identified by its unique PID number. The kernel controls and manages processes. A process consists of the executable program, its data and stack, program and stack pointer, registers, and all the information needed for the program to run. The shell is a special program that starts when you have completed the login process. Once started, the shell is a process. The shell belongs to a process group identified by the group's PID. Only one process group has control of the terminal at a time and is said to be running in the foreground. When you log on, your shell is in control of the terminal and waits for you to type a command at the prompt.

When you log on, your system may go directly into a graphical user interface (GUI) or start up in a terminal with a shell prompt. If you are using Linux, the shell normally starts up another process to launch the X Window System. After X Windows starts, a window manager process (twm, fvwm, etc.) is executed, providing a virtual desktop.[5] Then, from a pop-up menu, you can start up a number of other processes, such as xterm (gets a terminal), xman (provides manual pages), or emacs (starts a text editor). If you are using UNIX, the GUI may be CDE, KDE, or OpenWindows. Once started, you will have a virtual desktop consisting of a number of smaller windows, including a console and a number of terminals, each displaying a shell prompt.

[5] A number of desktop environments come with Linux, including Gnome, KDE, X, and so on.

Multiple processes are running and monitored by the Linux/UNIX kernel, allocating each of the processes a little slice of the CPU in a way that is unnoticeable to the user.

1.5.1 What Processes Are Running?

The ps Command

The ps command with its many options displays a list of the processes currently running in a number of formats. Example 1.2 shows all processes that are running by users on a Linux system. (See Appendix A for ps and its options.)

Example 1.2.

$ ps aux  (BSD/Linux ps)  (use ps -ef for SVR4)

USER   PID  %CPU  %MEM   SIZE   RSS TTY STAT   START  TIME  COMMAND

ellie  456   0.0   1.3   1268   840   1    S   13:23  0:00  -bash

ellie  476   0.0   1.0   1200   648   1    S   13:23  0:00  sh /usr/X11R6/bin/sta

ellie  478   0.0   1.0   2028   676   1    S   13:23  0:00  xinit /home/ellie/.xi

ellie  480   0.0   1.6   1852  1068   1    S   13:23  0:00  fvwm2

ellie  483   0.0   1.3   1660   856   1    S   13:23  0:00  /usr/X11R6/lib/X11/fv

ellie  484   0.0   1.3   1696   868   1    S   13:23  0:00  /usr/X11R6/lib/X11/fv

ellie  487   0.0   2.0   2348  1304   1    S   13:23  0:00  xclock -bg #c0c0c0 -p

ellie  488   0.0   1.1   1620   724   1    S   13:23  0:00  /usr/X11R6/lib/X11/fv

ellie  489   0.0   2.0   2364  1344   1    S   13:23  0:00  xload -nolabel -bg gr

ellie  495   0.0   1.3   1272   848  p0    S   13:24  0:00  -bash

ellie  797   0.0   0.7    852   484  p0    R   14:03  0:00  ps au

root   457   0.0   0.4    724   296   2    S   13:23  0:00  /sbin/mingetty tty2

root   458   0.0   0.4    724   296   3    S   13:23  0:00  /sbin/mingetty tty3

root   459   0.0   0.4    724   296   4    S   13:23  0:00  /sbin/mingetty tty4

root   460   0.0   0.4    724   296   5    S   13:23  0:00  /sbin/mingetty tty5

root   461   0.0   0.4    724   296   6    S   13:23  0:00  /sbin/mingetty tty6

root   479   0.0   4.5  12092  2896   1    S   13:23  0:01  X :0

root   494   0.0   2.5   2768  1632   1    S   13:24  0:00  nxterm -ls -sb -fn


The pstree/ptree Command

Another way to see what processes are running and what processes are child processes is to use the pstree (Linux) or ptree (Solaris) command. The pstree command displays all processes as a tree with its root being the first process that runs, called init. If a user name is specified, then that user's processes are at the root of the tree. If a process spawns more than one process of the same name, pstree visually merges the identical branches by putting them in square brackets and prefixing them with the number of times the processes are repeated. To illustrate, in Example 1.3 the httpd server process has started up 10 child processes. (See Appendix A for a list of pstree options.)

Example 1.3.

pstree

init---4*[getty]

init-+-atd

     |-bash---startx---xinit-+-X

     |                       `-fvwm2-+-FvwmButtons

     |                               |-FvwmPager

     |                               `-FvwmTaskBar

     |-cardmgr

     |-crond

     |-gpm

     |-httpd---10*[httpd]

     |-ifup-ppp---pppd---chat

     |-inetd

     |-kerneld

     |-kflushd

     |-klogd

     |-kswapd

     |-lpd

     |-2*[md_thread]

     |-5*[mingetty]

               |-nmbd

     |-nxterm---bash---tcsh---pstree

     |-portmap

     |-sendmail

     |-smbd

     |-syslogd

     |-update

     |-xclock

     `-xload


1.5.2 What Are System Calls?

The shell can spawn other processes. In fact, when you enter a command at the prompt or from a shell script, the shell has the responsibility of finding the command either in its internal code (built-in) or on the disk and then arranging for the command to be executed. This is done with calls to the kernel, called system calls. A system call is a request for kernel services and is the only way a process can access the system's hardware. There are a number of system calls that allow processes to be created, executed, and terminated. (The shell provides other services from the kernel when it performs redirection and piping, command substitution, and the execution of user commands.)

The system calls used by the shell to cause new processes to run are discussed in the following sections. See Figure 1.4 on page 17.

Figure 1.4. The fork, exec, wait, and exit system calls. See following Explanation.


1.5.3 Creating Processes

The fork System Call

A process is created in UNIX with the fork system call. The fork system call creates a duplicate of the calling process. The new process is called the child and the process that created it is called the parent. The child process starts running right after the call to fork, and both processes initially share the CPU. The child process has a copy of the parent's environment, open files, real and user identifications, umask, current working directory, and signals.

When you type a command, the shell parses the command line and determines whether the first word is a built-in command or an executable command that resides out on the disk. If the command is built-in, the shell handles it, but if on the disk, the shell invokes the fork system call to make a copy of itself (Figure 1.3). Its child will search the path to find the command, as well as set up the file descriptors for redirection, pipes, command substitution, and background processing. While the child shell works, the parent normally sleeps. (See "The wait System Call" below.)

Figure 1.3. The fork system call.


The wait System Call

The parent shell is programmed to go to sleep (wait) while the child takes care of details such as handling redirection, pipes, and background processing. The wait system call causes the parent process to suspend until one of its children terminates. If wait is successful, it returns the PID of the child that died and the child's exit status. If the parent does not wait and the child exits, the child is put in a zombie state (suspended animation) and will stay in that state until either the parent calls wait or the parent dies.[6] If the parent dies before the child, the init process adopts any orphaned zombie process. The wait system call, then, is not just used to put a parent to sleep, but also to ensure that the process terminates properly.

[6] To remove zombie processes, the system must be rebooted.

The exec System Call

After you enter a command at the terminal, the shell normally forks off a new shell process: the child process. As mentioned earlier, the child shell is responsible for causing the command you typed to be executed. It does this by calling the exec system call. Remember, the user command is really just an executable program. The shell searches the path for the new program. If it is found, the shell calls the exec system call with the name of the command as its argument. The kernel loads this new program into memory in place of the shell that called it. The child shell, then, is overlaid with the new program. The new program becomes the child process and starts executing. Although the new process has its own local variables, all environment variables, open files, signals, and the current working directory are passed to the new process. This process exits when it has finished, and the parent shell wakes up.

The exit System Call

A new program can terminate at any time by executing the exit call. When a child process terminates, it sends a signal (sigchild) and waits for the parent to accept its exit status. The exit status is a number between 0 and 255. An exit status of zero indicates that the program executed successfully, and a nonzero exit status means that the program failed in some way.

For example, if the command ls had been typed at the command line, the parent shell would fork a child process and go to sleep. The child shell would then exec (overlay) the ls program in its place. The ls program would run in place of the child, inheriting all the environment variables, open files, user information, and state information. When the new process finished execution, it would exit and the parent shell would wake up. A prompt would appear on the screen, and the shell would wait for another command. If you are interested in knowing how a command exited, each shell has a special built-in variable that contains the exit status of the last command that terminated. (All of this will be explained in detail in the individual shell chapters.) See Example 1.4 for an example of exit status.

Example 1.4.

(C/TC Shell)

1   % cp filex filey

    % echo $status

    0

2   % cp xyz

    Usage: cp [-ip] f1 f2; or: cp [-ipr] f1 ... fn d2

    % echo $status

    1



(Bourne, Bash, Korn Shells)

3   $ cp filex filey

    $ echo $?

    0

    $ cp xyz

    Usage: cp [-ip] f1 f2; or: cp [-ipr] f1 ... fn d2

    $ echo $?

    1


EXPLANATION

  1. The cp (copy) command is entered at the C shell command-line prompt. After the command has made a copy of filex called filey, the program exits and the prompt appears. The csh status variable contains the exit status of the last command that was executed. If the status is zero, the cp program exited with success. If the exit status is nonzero, the cp program failed in some way.

  2. When entering the cp command, the user failed to provide two filenames: the source and destination files. The cp program sent an error message to the screen and exited with a status of 1. That number is stored in the csh status variable. Any number other than zero indicates that the program failed.

  3. The Bourne, Bash, and Korn shells process the cp command as the C shell did in the first two examples. The only difference is that the Bourne and Korn shells store the exit status in the ? variable, rather than the status variable.

EXPLANATION

  1. The parent shell creates a copy of itself with the fork system call. The copy is called the child shell.

  2. The child shell has a new PID and is a copy of its parent. It will share the CPU with the parent.

  3. The kernel loads the grep program into memory and executes (exec) it in place of the child shell. The grep program inherits the open files and environment from the child.

  4. The grep program exits, the kernel cleans up, and the parent is awakened.

Killing Processes

A process can be terminated by using keystroke-generated signals like Ctrl-C or Ctrl-\, or by using the kill command. This command may be used for killing background jobs or, if your terminal is in a frozen, unresponsive state, to kill the process that is causing the problem. The kill command is a built-in shell command that terminates a process by its PID or, if using job control, by the number of the job. To find the PID number, the ps command is used. See Example 1.5.

Example 1.5.

1   $ sleep 60&

2   $ ps

    PID   TTY      TIME CMD

    27628 pts/7    0:00 sleep

    27619 pts/7    0:00 bash

    27629 pts/7    0:00 ps

3   $ kill 27628

4   $ ps

    PID   TTY      TIME CMD

    27631 pts/7    0:00 ps

    27619 pts/7    0:00 bash

    [1]+  Terminated              sleep 60


EXPLANATION

  1. The sleep command does nothing, just pauses for 60 seconds, and is running in the background due to the ampersand at the end of the command

  2. The ps command displays the currently running processes for this user.

  3. The kill command is a built-in shell command. It takes, as an argument, the PID of the process it will kill. The PID for the sleep command is entered.

  4. The ps command demonstrates that the sleep command has been terminated.

    Previous Section  < Day Day Up >  Next Section