You are on page 1of 10

UNIX Processes

Last modified Tuesday, 04-Apr-2006 14:33:20 EDT.

Process creation o Unless the system is being bootstrapped a process can only come into existance as the child of another process. This done by the fork system call. o The first process created is "hand tooled" by the boot process. This is the swapper process. o The swapper process creates the init process, which is the ancestor of all further processes. In particular, init forks off a process getty, which monitors terminal lines and allows users to log in. o Upon login, the command shell is run as the first process. The command shell for a given user is specified in the /etc/passwd file. From thereon, any process may fork to produce new processes, considered to be children of the forking process. The process table and uarea o Information about processes is described in two data structures, the kernel process table and a "uarea" associated with each process. o The process table holds information required by the kernel o The uarea holds information required by the process itself. o The process table entry for a process holds (amongst other things): Process state Several process IDs Several user IDs for determining process priviledges Pointer to text structure for shared text areas Pointer to page table for memory management Scheduling parameters, including the "nice" value which determines priority Timers for resource usage A pointer to the process uarea o The uarea of a process contains (amongst other things): Real and effective user IDs Current working directory Timer fields to hold accumulated user and kernel mode time Information an how to react to signals Identification of any associated control terminal Identification of data areas relevant to IO activity Return values and error conditions from system calls Information on the file system environment of the process The user file descriptor table Process IDs

o o o o

There are three IDs associated with every process, the ID of the process itself (the PID), its parent process's ID (the PPID) and its process group ID (the PGID). Every UNIX process has a unique PID in the range 0 to 30000. The PID 0 is reserved for the swapper process, and 1 for the init process. A process can get hold of its PID and PPID with the getpid and getppid calls.
int getpid(void) int getppid(void)

Process group IDs UNIX provides a PGID that is used to group processes together. The PGID of a process may be obtained with
int getpgrp(void)

A process initially belongs to its parent's group, but new groups may be established with
int setpgid(pid_t pid, pid_t pgid)

Sets the process group ID of the process with ID pid to pgid. If pid is equal to 0, the process ID of the calling process is used. Groups may have a control terminal which is the first tty device opened by the group leader. Initially the group leader is the shell, and the login device is the control terminal. A new group that is started is not attached to the previous control terminal (if any). Interupt, quit and hangup signals from a terminal go to all process associated with that terminal. For example all processes that start from one given terminal belong to the same group. Then if the terminal goes down it's possible to find all its processes. o ProcessIDs.c - Program to play with PIDs User IDs o Every process has a real user ID (the UID), an effective user ID (the EUID), a real user group ID (the GID), and an effective user group ID (the EGID). The user group ID is distinct from the process group ID. o The real IDs are used for accounting and user-user communication, while the effective IDs are used to control access to files and control signal sending. o A user ID is associated with each user login name in the password file /etc/passwd. This is assigned to the user's shell as its UID and EUID, and is inherited by processes spawned from the shell. o The user IDs can be accessed with the system calls:
int getuid(void)

which gets the UID of the process, and


int geteuid(void) o o

which gets the EUID of the process. Each entry in /etc/passwd also has a group ID which is given to the shell as its initial GID and EGID. The group IDs can be accessed with the system calls: int getgid(void) which gets the GID of the process and
int getegid()

which gets the EGID of the process. Only the superuser may change the user IDs of a process, using the system calls:
int setuid(int uid)

which sets the UID and EUID, and

int setgid(int gid)

which sets the GID and EGID. Both calls return 0 on success, or -1 on error. Ordinary users may change effective IDs to real IDs, by using these calls with the arguments equal to the real IDs. o UserIDs.c - Program to play with user IDs The environment of a process o The environment of a process includes details of the home directory, path names to be searched for the program, the type of terminal being used, the user name, the shell being run, etc. o The environment of a program is held in strings which have the format <keyword>=<value>, e.g.
o HOME=/usr/spg/geoff TERM=/tvi950 PATH=/usr/bin:/usr/spg/geoff/bin o

The environment of a program can be examined by looking at the system external variable environ, which is an array of char pointers: extern char *environ[]; A NULL pointer signifies the last such string. The program may explicitly receive the environment strings as a third parameter to main. This parameter is an array of char pointers.
int main(int argc,char *argv[],char *env[])

o o

The value of a environment keyword can be examined with the getenv call: char *getenv(char keyword[]); getenv returns a pointer to the string value, or NULL if no value is specified. The value of a environment keyword can be set with the setenv call:

int setenv(char *name,char *value,int overwrite); An environmeent variable can be deleted using the unsetenv call: unsetenv(char *name); o Environment.c - Program to examine environment strings The fork system call o int fork(void) o The fork call creates an (almost exact) copy of the parent. In particular

they share all open files. o The fork call returns the new PID to the parent and 0 to the child, or -ve to the parent if it fails. o The PID of the new process is different, the open file descriptors of the parent process are copied, and accumulated execution times are reset. o Fork.c - Program that forks Execution of programs o The fork call merely duplicates the parent process. To switch to a different program a process uses one of the exec system calls. o The exec calls replace the code and data areas of the current program and jumps to the start of the new program. o Open files, current directory, inter-process relationships are not affected by the exec calls.
o void execl(char *program_path,char *arg0,...,char *argn,NULL); The program_path is the name of the file to execute. The program_path must be absolute, i.e. start with /.

o o

are the arguments to the program, which in C are accessible through the parameters to main. Conventionally arg0 is the name of the program. A NULL argument ends the list. Exec.c - Programs that forks and execs
void execv(char *program_path,char *arguments[]);

argi

o o o o

Here the arguments are stored as an array of pointers, in the same way as they are received by main. The last pointer must be NULL. The execl and execv calls pass on the current environment to new programs. The environment of a new program can be changed by using the environment argument to execle and execve. The path can be search using execvp or execlp.
void execle(char *program_path,char *arg0,...,char *argn,NULL, char *environment[]);

The environment is an array of pointers to strings that describe the environment to be passed to the new program.
o void execve(char *program_path,char *arguments[],char *environment[]); This is the true exec, the others end up calling this one.

o ExecWithArgs.c - Program that forks a child with arguments Process termination o void exit(int status) A process may terminate by explicit use of the exit system call. This call is used implicitly when a process terminates normally.

o o o o o o

A process may terminate when another process sends an appropriate signal (see later). The parent process is notified by sending it a SIGCHLD signal. If the parent terminates before any child, then the PPID of the child process is set to 1, i.e. the init process adopts all orphan processes. Terminated processes become zombie processes, which are removed by the parent process. If the parent does not remove zombies, they hang around. The wait system call allows parents to wait for their children to terminate.
int wait(int *status_pointer); wait suspends the process until a child process terminates and sends SIGCHLD signal. wait returns the id of that process, or -1 immediately if there are no

o o

children. Exit status information (see below) is returned to the parent in *status_pointer. To run a process in background (& in C and Bourne shells) the parent does not execute wait. Wait.c - Program that forks, execs, and waits
int waitpid(pid_t pid, int *status_pointer, int options); Can wait for a specified pid. If pid is -1 then waits for any process. Various options, including

- Does not suspend execution of the calling process if status is not immediately available for one of the child processes specified by pid. WUNTRACED - The status of any child processes specified by pid that are stopped, and whose status has not yet been reported since they stopped, is also reported to the calling process. The reason for the wait to have returned can be detected from the *status_pointer using WIFEXITED, WIFSIGNALED, and WIFSTOPPED. If WIFEXITED, the lower 8 bits of the exit parameter in the child can be obtained from the *status_pointer using WEXITSTATUS. If WIFSIGNALED, the signal that caused the termination can be obtained from the *status_pointer using WIFSIGNALED. If WIFSTOPPED, the signal that caused the stop can be obtained from the *status_pointer using WSTOPSIG. ExecWithArgsAndWait.c - Program that forks a child with arguments and waits A signal interrupts a process. Signals are defined in signal.h. Basic ones are: SIGHUP: #1 - hangup (modem) SIGINT: #2 - interrupt (rubout key) SIGQUIT: #3 - quit (FS control \ key) SIGILL: #4 - illegal instruction SIGTRAP: #5 - trace or breakpoint SIGABRT: #6 - abort() SIGEMT: #7 - emulator trap instruction SIGFPE: #8 - floating point exception SIGKILL: #9 - kill, uncatchable quit SIGBUS: #10 - bus error SIGSEGV: #11 - segmentation violation SIGSYS: #12 - bad system call SIGPIPE: #13 - end of pipe SIGALRM: #14 - alarm clock SIGTERM: #15 - catchable termination SIGURG: #16 - urgent condition on IO channel SIGSTOP: #17 - sendable stop signal not from tty SIGTSTP: #18 - stop signal from tty SIGCONT: #19 - continue a stopped process SIGCHLD: #20 - child death (or stopped under Linux) SIGTTIN: #21 - to readers pgrp upon background tty read SIGTTOU: #22 - like TTIN for output SIGIO: #23 - input/output possible signal SIGXCPU: #24 - exceeded CPU time limit SIGXFSZ: #25 - exceeded file size limit SIGVTALRM: #26 - virtual time alarm SIGPROF: #27 - profiling time alarm

WNOHANG

Signals
o o

SIGWINCH: #28 - window size changes SIGINFO: #29 - information request SIGUSR1: #30 - user defined signal 1 SIGUSR2: #31 - user defined signal 2

o o

Signals have 6 basic sources User typing control characters at the keyboard. These signals are sent to all processes in the group associated with the terminal - SIGHUP, SIGINT, SIGQUIT. Software errors - SIGILL, SIGTRAP, SIGABRT, SIGFPE, SIGSYS, SIGPIPE. Hardware errors - SIGEMT, SIGBUS, SIGSEGV. The alarm system call - SIGALRM The kill system call (see below) - All signals External events - SIGCHLD, SIGURG, SIGIO, SIGXCPU, SIGXFSZ, SIGWINCH, SIGINFO. Signals either caught, ignored or terminate the process. The signal system call The signal system call can be used to instruct receiving processes on how to deal with a signal. This associates a function with a given signal.
void (*signal(int TheSignal,void (*Function)(int)))(int); This is a function that returns a pointer to a function that returns an int.

The second argument is the same. signal associates TheSignal with the Function. Function may be supplied by the user or one of SIG_DFL, which resets to the default, and SIG_IGN, which ignores the signal. When the signal occurs execution is transferred to the function. When a function set up to handle interrupts ends it returns to the point where the interruption occured. External variables have to be used to pass data into and out of signal handlers. signal returns the previous function. The pause system call The pause system call
void pause(void);

causes the calling process to suspend until a non-ignored signal is received. Signal.c - Program that catches keyboard interrupts The SIGKILL and SIGSTOP signals cannot be caught or ignored Child processes inherit signal handling The kill system call
int kill(int PID,int Signal); kill sends the Signal to all processes

identified by the PID, where the values are: +ve - process with the ID 0 - processes with group ID equal to process ID of sender. -1 - if the EUID is super user then all processes, otherwise processes whose UID equals the EUID of sender.

< -1 - processes whose GID is the absolute of the PID Returns -1 on error, 0 on success Kill.c - Program that kills its parent The alarm system call
unsigned alarm(unsigned Time) Causes a signal SIGALRM to occur Time

seconds later in the calling

process. It returns the time left until that signal. alarm(0) turns off the alarm Alarm.c - Program that wakes itself up KillAlarm.c - Program that uses alarm and kill With the exception of the SIGCHLD signal, signals are not queued. SIGCHLD signals are generated by child processes when they terminate, and when they are stopped by a SIGTSTP or SIGSTOP ExecManyWithArgs.c - Program that forks many child with arguments, and reaps POSIX signal handling The signal system call is the traditional way of handling signals. POSIX has defined a richer signal handling interface.
int sigaction(int signum,struct sigaction *act,struct sigaction *oldact); - used to install a signal handler signum specified which signal to handle *act specifies what to do *oldact, if not NULL, saves the old action A struct sigaction contains: void (*sa_handler)(int) - the signal handler sigset_t sa_mask - mask of signals which should be blocked

during execution of the signal handler. In addition, the signal which triggered the handler will be blocked, unless the SA_NODEFER or SA_NOMASK flags are used. int sa_flags - flags which modify the behaviour of the signal handling process. Useful flags include SA_NOCLDSTOP, SA_ONESHOT, and SA_NOMASK int sigprocmask(int how,sigset_t *set,sigset_t *oldset); Used to change the list of currently blocked signals int siginterrupt(int sig,int flag); - Changes the restart behaviour when a system call is interrupted by the signal InterruptSystem.c - Program that times out read attempts Process priority o The priority of a process is an integer in the range -20 to 20, with -20 being the highest priority. o Processes start with a priority of 0. o getpriority(int which, int who); - Gets the priority of a process (or user, or group) which is PRIO_PROCESS for process priorities who is the PID, or 0 for the current process (user, group)

setpriority(int which, int who, int prio);

- Sets the priority of a

process (or user, or group) prio is the new priority value. o Priority.c - Program that changes its priority Process resource usage o Need to include sys/time.h, sys/resource.h, and unistd.h. o int getrlimit(int resource, struct rlimit *rlim); - Get the processes resource limits. resource is one of: RLIMIT_CPU - CPU time in seconds RLIMIT_FSIZE - Maximum filesize RLIMIT_DATA - max data size RLIMIT_STACK - max stack size RLIMIT_CORE - max core file size RLIMIT_RSS - max resident set size RLIMIT_NPROC - max number of processes RLIMIT_NOFILE - max number of open files RLIMIT_MEMLOCK - max locked-in-memory address space RLIMIT_AS - address space (virtual memory) limit
struct rlimit

is defined as:

struct rlimit { rlim_t rlim_cur; rlim_t rlim_max; };

If the process exceeds a soft limit it may be sent a signal:


SIGSEGV SIGXFSZ SIGXCPU

for data limits. for file limits. for CPU time.

A process cannot exceed its hardlimit.


o int setrlimit(int resource, const struct rlimit *rlim);

- Set the process resource limits (and that of any children). An inifinite limit is set using RLIM_INFINITY. Only the superuser can increase the hardlimit rlim_max. int getrusage(int who, struct rusage *usage); - Returns the current resource usages, for a who of either RUSAGE_SELF or RUSAGE_CHILDREN. struct rusage is defined as:
struct rusage { struct timeval ru_utime; struct timeval ru_stime; long ru_maxrss; long ru_ixrss; long ru_idrss; long ru_isrss; /* /* /* /* /* /* user time used */ system time used */ maximum resident set size */ integral shared memory size */ integral unshared data size */ integral unshared stack size */

o o o o o o o

o o o o o o o o o o o

long long long long long long long long long long };

ru_minflt; ru_majflt; ru_nswap; ru_inblock; ru_oublock; ru_msgsnd; ru_msgrcv; ru_nsignals; ru_nvcsw; ru_nivcsw;

/* /* /* /* /* /* /* /* /* /*

page reclaims */ page faults */ swaps */ block input operations */ block output operations */ messages sent */ messages received */ signals received */ voluntary context switches */ involuntary context switches */

and a struct timeval is defined as:


struct timeval { long tv_sec; long tv_usec; }; /* seconds */ /* and microseconds */

CPULimitedRun.c

- Program that controls the resource usage of a child.

Exercises

Process management: Write a program that reads a file of commands and executes them all in background mode. This batch process starter must wait for all the programs to finish before it exits. A sample file that may be presented to your program could contain:
date ls -l cat fred.c

Notes: There exist two library functions execlp and execvp that extend the exec calls by searching the current path (as specified in the environment variable PATH) for the file to execute, if it does not have an absolute address. o The lines in the file contain the program name and its parameters. You need to sort out the parameters from the command. Signals: Write an onscreen clock program, that updates its time every five seconds by setting an alarm signal to go off five seconds after each time the time is printed. The program should exit gracefully when it is interrupted.
o

Exam Style Questions

What information is returned by the getpid, getppid, and getpgrp system calls? What is the difference between the return values of the getuid and geteuid system calls? Write a program that creates a second process, and then in both processes outputs the process ID and the owners user ID. What is wrong with the following code segment?
if (fork() == 0) { printf("Here comes the directory listing\n"); execlp("/bin/ls","ls",NULL); printf("That is the end of the listing\n"); } else { ... /*----Some legal stuff here */ }

What advantage do the execlp and execvp calls have over execl and execv? The kill system call sends a signal to a specified process. How can that process be prepared to receive the signal? Which signal cannot be ignored or caught by a receiving process? Name three system calls that cause (directly or indirectly) a signal to be sent to a process. Write a program that does nothing until it receives a signal, then sends a SIGQUIT to its parent process. Write a program that starts a child process for each of its integer command line arguments. The child processes simply sleep for the time specified by the argument, then exit. After starting all the children, the parent process must wait until they have all terminated before terminating itself. Which system call can be used to limit the amount of CPU time a process can use? Which system call can be used to find out home much CPU time the process did use?

You might also like