390 likes | 526 Views
Linux Tutorial Lesson Three. * Process creation and termination More details about processes commands and functions can be found in Chapter 6/Linux & Unix Programming Tools. Program: collection of statements and data Generally stored on a hard disk Marked as "executable" in the i-node
E N D
Linux TutorialLesson Three *Process creation and termination More details about processes commands and functions can be found in Chapter 6/Linux & Unix Programming Tools
Program: collection of statements and data • Generally stored on a hard disk • Marked as "executable" in the i-node • The contents of the file fulfills the requirements of the operating • System for executables (a.out format, elf format, etc.)
Executing a program • The kernel creates a process, i.e. it creates an environment which can be used to run the program • Each process consists of three areas - Instruction segment - User data segment - System data segment • The program will be used to initialize the instructionand user data segment • When the initialization is finished there is no further connection betweenprocessand program • A process can request more resources (memory, files, etc.)
Among others the system data segment contains the following information • Current directory • File descriptor table • Accumulated CPU time • Process and group ID of the parent process
The operating system creates a process if this is requested by another process • The requesting process is called parent process • The new created process is called child process
The child process inherits most of the environment of its parent process (e.g., open files, shared memory segments, etc.) • Each process identifies itself with a unique process ID (PID) • Each process (with the exception of the init process) has a parent (identified by a parent process ID, PPID) • The init process is root of the process hierarchy *Try typing PSTREE to see how the all processes are generated from the init process (If a parent process terminates before its child processes terminate,init becomes parent of theorphanprocesses, i.e. the parent process ID of such processes is 1) • Each process belongs to a process group (identified by a process group ID,PGID)
Understanding fork() • The fork() system call creates a new process called a child. The original process is called the parent, and the child is a near-exact copy of the parent. The child's run time is set to zero and file locks are not inherited. • The child has its own process ID and its own copy of the parent's file descriptors. • A parent process can recover the exit status of a child using the wait() or waitpid() function.
Creating a new process with fork ( ) - 1 • The child process is mainly a copy of the parent process. (look at the manual page if you want to know how the environment for the child process differs from that one of the parent) • fork ( )returns the process ID of the child process to the parent process. • fork ( )returns 0 to the child process. • fork ( )returns -1 to the parent process and no child process is created if an error has occurred (e.g., the limit on the total number of processes under execution by a single user would be exceeded)
Creating a new process with fork ( ) - 2 • Normally the child process overloads itself with another program using one of the exec ( )functions. • The parent process waits until the child process terminates (wait()function) or performs other work. • fork ( )is a very expensive system function because possibly large data segments must be copied.
Waiting for the termination of a child process with wait ( ) • wait ( )returns the process ID of the terminated child process. • wait ( )can store the exit-value of the child process if it is called with a pointer parameter. • If a child process terminates before its parent process has calledwait ( )it becomes a zombieprocess. • The instruction, user data, and system data segmentsare released. • The entry in the process table will be cleared if the parent process calls wait ( ) • The zombiehas left the system (rebooting a system always clears all zombies)
Terminating a process with exit ( ) • Terminate a process and return an exit-value to the parent process • If the process has still active child processes the child’s will not be terminated but they become a new parent process: theinitprocess.
Example to demonstrate the general structure of process creation and termination (fork1.c) #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <errno.h> int eval_wait_stat (int stat); int main (void) { pid_t parent_pid, child_pid, /* process ID's */ fork_pid, wait_pid, parent_grp, child_grp; /* process groups */ int child_stat, /* return status of child */
exit_val; /* "exit"-value for child */ exit_val = 10; /* arbitrary value for testing */ parent_pid = getpid (); parent_grp = getpgrp (); printf ("\nParent process: process ID: %ld group ID: %ld\n", (long) parent_pid, (long) parent_grp); fork_pid = fork (); switch (fork_pid) { case -1: /* error: no process created */ perror ("fork failed"); errno = 0; break; case 0: /* child process */ child_pid = getpid (); child_grp = getpgrp ();
printf ("Child process: process ID: %ld group ID: %ld " "parent process ID: %ld\n", (long) child_pid, (long) child_grp, (long) getppid ()); printf ("Child process: terminate with \"exit\"-value: %d\n", exit_val); exit (exit_val); break; default: /* parent process */ printf ("Parent process: child process with ID %ld created.\n", (long) fork_pid); wait_pid = wait (&child_stat); if (wait_pid == -1) { perror ("wait"); errno = 0; }
else { printf ("Parent process: child process %ld has terminated.\n", (long) wait_pid); eval_wait_stat (child_stat); }; }; return 0; }
int eval_wait_stat (int stat) { if (WIFEXITED (stat) != 0) { printf ("\t\tChild has terminated with status %d.\n", WEXITSTATUS (stat)); return 0; }; if (WIFSIGNALED (stat) != 0) { printf ("\t\tChild has been terminated using signal %d.\n", WTERMSIG (stat)); return 0; }; if (WIFSTOPPED (stat) != 0) { printf ("\t\tChild has been stopped using signal %d.\n", WSTOPSIG (stat)); }; return 1; }
1) create a new process (mainly a copy of the parent process) 2) when the child process overloads itself with a new program it has its individual instruction and data segments • exec ( )functions differ in the following areas: • Searching for the program • Absolute pathname • Searching all directories specified in the environment variable PATH
Passing the environment for the new program • Inheritance (automatically) • Explicitly passing a new one (manually) • Passing the "command line" arguments • Explicit list appearing in the exec ( )call • As a vector (array like argv)
l explicit list of command line arguments • v vector of command line arguments (necessary if the number of arguments is unknown at compile time) • e explicitly passing a new environment • p searching for the program using environment variable PATH
Most often the functions execlp ( )and execvp ( )are used • It's not necessary to fork a program before using an exec ( ) function • (Many large programs execute in sequential steps (e.g., a compiler). If one step has finished the process can overload itself with the program for the next step. Generally the steps must be independent of each other or they have to use temporary files to communicate with each other because the user data segment will be re-initialized with the new program.) • The first argument (arg0) of an explicit list or vector of command line arguments is always the program name • The last argument of an explicit list or vector of command line arguments is always NULL
Example to demonstrate the use of an exec ( ) function (forkexec.c) int main (void) { pid_t fork_pid, wait_pid; /* process ID's */ int child_stat, /* return status of child */ ret_val; /* return value of a function */ fork_pid = fork (); switch (fork_pid) { case -1: /* error: no process created */ perror ("fork failed"); errno = 0; break;
case 0: /* child process */ ret_val = execl ("/bin/ls", "ls", "-al", NULL); if (ret_val == -1) { perror ("execl failed"); errno = 0; }; exit (0); break;
default: /* parent process */ printf ("Parent process: child process with ID %ld created.\n", (long) fork_pid); wait_pid = wait (&child_stat); if (wait_pid == -1) { perror ("wait"); errno = 0; } else { printf ("Parent process: child process %ld has terminated.\n", (long) wait_pid); eval_wait_stat (child_stat); }; }; return 0; }
file descriptor - An integer that identifies an open file within a process. This number is obtained as a result of opening a file. Operations which read, write, or close a file would take the file descriptor as an input parameter.In many operating system implementations, file descriptors are small integers which index a table of open files. In Unix, file descriptors 0, 1 and 2 correspond to the standard input, standard output and standard error files respectively.
dup and dup2 Functions • An existing file descriptor is duplicated by either of the following functions: • #include <unistd.h> • int dup(int filedes); • int dup2(int filedes, int filedes2); • Both return: new file descriptor if OK, -1 on error The new file descriptor returned by dup is guaranteed to be the lowest numbered available file descriptor. With dup 2 we specify the value of the new descriptor with the filedes2 argument. If filedes2 is already open, it is first closed.
Understanding the shell Much of the Unix development environment involves use of shell variables. Some of these are variables which the user makes up himself/herself, but most of them are intrinsic to the shell. • Typing: set x = 2 Would create a new shell variable named x (this would be a user-defined variable).
Here are some examples of important shell variables: 1.1 $cwd • This variable consists of a string which records the current directory. • Typing set cwd = b would have the same effect as cd b • While typing echo $cwd would have the same effect as pwd • (The echo command simply writes the given string or strings to the screen).
1.2 $path • This is an extremely important variable. • When you issue a command to the shell, the shell will search through various directories to find the executable file for that command, so that the command can be run. • A typical value for $path might be (. /usr/local/bin /usr/ucb /usr/bin /usr/etc /etc /bin /usr/bin/X11 ) • Suppose we give the shell the command z. The shell will first search for a file named z in our current directory (`.'); if not found there, the shell will next look for the file in the directory /usr/local/bin; and so on. (Many of the commands you have been using so far-e.g. ls, mail, etc.-are in the directory /usr/ucb. Take a look!)
If you create a new directory in which you put executable files which you use often, you should add this directory to your path, so that you can conveniently execute the programs from any other directory. • Suppose the full directory name is /a/b/c. Then to add it to your the end of your path, add a line : set path = ( $path /a/b/c ) to your .cshrc file. • This means that the directory /a/b/c will be checked last. • If you wish it to be checked first (there may be files of the same name in different portions of the path), add the line: set path = ( /a/b/c $path )
By the way, if you add a new program to your system, or use mv to rename it, you probably will then need to run rehash to let your shell know that the set of executables it found before needs to be updated.