1.unix processes

105
© 2009 Wipro Ltd - Confidential Unix Processes Version 1.2 Unix FCG

Upload: hacktivists2011

Post on 11-Dec-2015

25 views

Category:

Documents


0 download

DESCRIPTION

unix process

TRANSCRIPT

© 2009 Wipro Ltd - Confidential

Unix Processes

Version 1.2

Unix FCG

© 2009 Wipro Ltd - Confidential2 © 2009 Wipro Ltd - Confidential2

Agenda

3

4 Signals

1 Process Environment

2 Process Control

Process Relationships

5 Daemon Processes

© 2009 Wipro Ltd - Confidential3

Process Environment

© 2009 Wipro Ltd - Confidential4 © 2009 Wipro Ltd - Confidential4

Process

• Process is an instance of a program in execution.• Process is uniquely identified by its PID or process id.• Multiple processes can execute simultaneously on a system.

– Single processor executes only one process at a given instance.• Managed by the process control subsystem.

© 2009 Wipro Ltd - Confidential5 © 2009 Wipro Ltd - Confidential5

Process Control è Key Services

• Process scheduling– Allocates processes to CPU using a scheduling algorithm.– Every process is given a time slice for execution.– Context switching when it changes execution context from one process

to another.– Processes run till their time slices elapse and are then swapped out of

CPU.– Alternately, they voluntarily relinquish CPU while awaiting a resource.

• Process synchronization– Between parent-child processes.

• Inter-process communication– Asynchronous signaling of events.– Synchronous transmission of messages between processes.

© 2009 Wipro Ltd - Confidential6 © 2009 Wipro Ltd - Confidential6

Process Control è Key Services

• Memory management– Manages allocation of memory for an executing process.– Protection of private address space of a process.– Memory management by writing process memory temporarily to

secondary memory.• Swapping: Entire process written to swap device.• Paging: Pages of memory written to swap device.

© 2009 Wipro Ltd - Confidential7 © 2009 Wipro Ltd - Confidential7

Process è Attributes

• Key process attributes include:– Process ID (PID)

• Unique per process– Parent process ID (PPID)– Process group ID

• System assigns process group ID to every process• Same as process ID of group leader• Signals propagate to all processes in a group

– User and group ID (real and effective)• Real user and group ID is that of the user who invoked the process• Effective user and group ID is to run the process as its program owner

– Process priority

© 2009 Wipro Ltd - Confidential8 © 2009 Wipro Ltd - Confidential8

Process Creation• Every process except process 0 is created by the fork() system call.

– Process 0 (swapper) is created by system at boot time.– Process 1 (init), created by swapper, is the ancestor of all processes.

• Process that invoked fork is called the parent process; newly created process is called the child process (of this parent).

• With a fork, child process is created with the same text and data segment as parent.

• Using an exec in the child process overlays current process with a new program.

• When a command is executed from the shell, it internally does a fork and exec.

• Parent process needs to “wait” on a child to receive its exit status, and cleanup process table entry for child.

• Any process can have only one parent process.– Indicated by PPID (parent process id) attribute.

• A process can have any number of children.– Well, there is an upper limit.

© 2009 Wipro Ltd - Confidential9 © 2009 Wipro Ltd - Confidential9

Orphan & Zombie Processes

• Orphaned process– Parent dies before child exits.– Child process is adopted by init.

• Child’s parent becomes init à its PPID becomes 1.– init does a wait on the orphaned child process and handles its cleanup

from process table on exit.• Defunct or Zombie process

– Child process exits, but still has an entry in process table.– Parent is notified with a SIGCHLD signal.– Child is in defunct or zombie state till the parent does a wait and reads

the exit status of the child.• Child process does not consume CPU resources, only occupies an entry in

process table.

© 2009 Wipro Ltd - Confidential10 © 2009 Wipro Ltd - Confidential10

Process States

• Common Process StatesProcess State

Description

R Process is running or scheduled to run (runnable ) and is on the run queue.S Process is in an interruptible sleep state (waiting for an event to complete).D Process is in an uninterruptible sleep (usually IO).T Process has been stopped (either by a job control signal or because it is

being traced).Z Zombie (or defunct) process, terminated but not reaped by its parent.

© 2009 Wipro Ltd - Confidential11 © 2009 Wipro Ltd - Confidential11

Process Priority

• Process attribute used by scheduler to decide the execution order.• Lower the priority number, higher the priority.• Each process has a nice value which can be used to influence its

scheduling.– Higher nice values è process wants to be nice (to other processes) è

run at lower priority.– Lower nice values è process wants to be less nice è run at higher

priority.– Typically, a process with a smaller nice value runs to completion more

quickly than an equivalent process with a higher nice value.– Can be changed with nice or renice.– A typical process starts out with 20; it can be as nice as 39 or as not-

nice as 0.

© 2009 Wipro Ltd - Confidential12 © 2009 Wipro Ltd - Confidential12

Process Related Tools

• Shell è command interpreter & job control.– When a user logins in, kernel starts a shell (Eg: sh, bash, ksh).– All processes started by user from shell run as its child processes.

• Shell does a fork and exec to execute the command or process started.– Jobs (or processes)

• Can be run as:– Foreground jobs

» Has control of shell; associated with terminal; can accept user input.– Background jobs

» Invoked with & suffix; independent of user input from terminal.• Foreground job may be suspended by pressing <Ctrl-Z>.

– Shell sends SIGTSTP signal to process.• Suspended job may be resumed in foreground (fg command) or in background (bg

command).– Shell sends SIGCONT signal to process.

• Background job also may be made to run in foreground using fg command.• List of all processes started by shell (and not exited) may be obtained by using jobs

command.• Foreground job may be interrupted by pressing <Ctrl-C>.

– Shell sends SIGINT signal to process.

© 2009 Wipro Ltd - Confidential13 © 2009 Wipro Ltd - Confidential13

Process Related Tools• psè Report a snapshot of processes.• topè Provide a dynamic real-time view of a running system.• killè Send a signal to a process.

– kill <pid> sends default signal (SIGTERM).– kill -9 <pid> sends SIGKILL signal for forceful termination.

• killallè Send a signal to all processes running a specified command.• sleepè Delay/suspend command execution for a specified period of time.• nohupè Run a command immune to hangups.

– On shell exit, it sends a hangup signal (SIGHUP) to all its children, causing them to be killed.

– Can be used when you want the command execution to continue even after shell exits.

– For applying this behaviour to existing jobs not started with nohup, some shells provide the disown command.

• timeè Find system resource usage during command execution.• nice, reniceè Change nice value of processes.• pidofè Find PID of a running program.• ulimitè Get/set user resurce limits.• priocntlè Get/set scheduling parameters of processes.

© 2009 Wipro Ltd - Confidential14 © 2009 Wipro Ltd - Confidential14

• A C program starts execution with a function called main.– int main(int argc, char *argv[]);

• When it is executed by the kernel by one of the exec functions, a special start-up routine is called before main.

• The executable program file specifies this routine as the starting address for the program.– This is set up by the link editor when it is invoked by the C compiler.– This start-up routine takes values from the kernel the command-line

arguments and the environment and sets things up for main.

Process Start-up

© 2009 Wipro Ltd - Confidential15 © 2009 Wipro Ltd - Confidential15

Process Termination

• 8 ways:– Normal termination:

1. Return from main2. Calling exit3. Calling _exit or _Exit4. Return of the last thread from its start routine5. Calling pthread_exit from the last thread

– Abnormal termination:6. Calling abort7. Receipt of a signal8. Response of the last thread to a cancellation request

• Start-up routine is written so that if main returns, exit is called.• Exit handlers can be registered & be automatically called by exit.

– int atexit(void (*func)(void))– An exit handler is called once for each time it is registered.

© 2009 Wipro Ltd - Confidential16 © 2009 Wipro Ltd - Confidential16

Process Life Cycle

© 2009 Wipro Ltd - Confidential17 © 2009 Wipro Ltd - Confidential17

atexitè Examplestatic void my_exit1(void){ printf("first exit handler\n");}

static void my_exit2(void){ printf("second exit handler\n");}

int main(int ac, char *av[]){ if (atexit(my_exit2) != 0) err_sys("can't register my_exit2"); if (atexit(my_exit1) != 0) err_sys("can't register my_exit1"); if (atexit(my_exit1) != 0) err_sys("can't register my_exit1"); printf("main is done\n");

(ac == 2) ? _exit(0) : exit(0);}

© 2009 Wipro Ltd - Confidential18 © 2009 Wipro Ltd - Confidential18

atexitè Example$ ./a.outmain is donefirst exit handlerfirst exit handlersecond exit handler$ ./a.out nmain is done$

© 2009 Wipro Ltd - Confidential19 © 2009 Wipro Ltd - Confidential19

Arguments & Environment

• Command-line arguments to a program can be accessed as argv[1]to argv[argc – 1].– The name with which the process was invoked is argv[0].

• Each program is also passed an environment list.– Accessible via a global variable.

• extern char **environ;

– name=value strings• PATH=:/bin:/usr/bin• HOME=/home/wipro

– Specific environment variables should be accessed using getenv and putenv functions.

• char *getenv(const char *name)• int putenv(char *str)• int setenv(const char *name, const char *value, int rewrite)• int unsetenv(const char *name)

© 2009 Wipro Ltd - Confidential20 © 2009 Wipro Ltd - Confidential20

Memory Layout Of A Program

• Text segment– Machine instructions that the CPU executes.– Read-only.– Sharable so that a single copy in memory can be used by programs.

• Initialized data segment (Data segment)– Global variables that are specifically initialized.

• int answer = 42;

• Uninitialized data segment (BSS)– Initialized by the kernel to arithmetic 0 or null pointers before the program starts

executing.– Not stored in the program file on the disk.

• long days_of_week[7];

• Stack– Temporary data storage.– Automatic variables, along with information that is saved each time a function is

called (parameters to functions, pointer to previous stack frame etc.).• Heap

– Where dynamic memory allocation usually takes place.

© 2009 Wipro Ltd - Confidential21 © 2009 Wipro Ltd - Confidential21

Typical Memory Arrangement

High address Command-line arguments & environment variables

Low address

Initialized Data(read-only)

Text

Initialized to zero by exec

Read from the program file by exec

Stack

Heap

Uninitialized Data(BSS)

Initialized Data(read-write)

© 2009 Wipro Ltd - Confidential22 © 2009 Wipro Ltd - Confidential22

Dynamic Memory Management

• void *malloc(size_t size)• void *calloc(size_t nobj, size_t size)• void *realloc(void *ptr, size_t newsize)• void free(void *ptr)

• Usually implemented with the sbrk system call.– Expands or contracts the heap of the process.

© 2009 Wipro Ltd - Confidential23 © 2009 Wipro Ltd - Confidential23

Resource Limits

• Every process has a set of resource limits.• int getrlimit(int resource, struct rlimit *rlptr)• int setrlimit(int resource, const struct rlimit *rlptr)

• rlimit has a soft limit & a hard limit.– A process can:

• Change its soft limit to a value <= its hard limit.• Lower its hard limit to a value >= its soft limit.

– Only a superuser process can raise a hard limit.• Eg: RLIMIT_AS (maximum size of process’ virtual memory),

RLIMIT_CORE (maximum size of core file), RLIMIT_CPU (CPU time limit in seconds), RLIMIT_FSIZE (maximum size of files that the process may create) etc.

• Inherited by any of its children.– ulimit capability built into most of the shells.

© 2009 Wipro Ltd - Confidential24 © 2009 Wipro Ltd - Confidential24

Exercises

1. Print all the environment variables from a program using environ.2. Find out the resources & the resource limits on your system. Use

getrlimit to find the limits. Compare the values obtained with those obtained via ulimit command. Can you change all the limits as a normal user?

© 2009 Wipro Ltd - Confidential25

Process Control

© 2009 Wipro Ltd - Confidential26 © 2009 Wipro Ltd - Confidential26

• Every process has a unique process ID (PID).– Can be reused.– PID 0

• Usually the scheduler process and is often known as the swapper.• No program on disk corresponds to this process, which is part of the kernel.

– PID 1• Usually the init process.• Invoked by the kernel at the end of the bootstrap procedure.• Never dies though it is a normal user process.• Becomes the parent process of any orphaned child process.

– pid_t getpid(void)– pid_t getppid(void)– uid_t getuid(void)– uid_t geteuid(void)– gid_t getgid(void)– gid_t getegid(void)

Process Identifiers

© 2009 Wipro Ltd - Confidential27 © 2009 Wipro Ltd - Confidential27

Process Creation è fork

• An existing process (parent) can create a new one (child).• pid_t fork(void)

– This function is called once but returns twice.• Return value in the child is 0.• Return value in the parent is the PID of the new child.

– A process can have more than one child.– No function that allows a process to obtain the PIDs of its children.

– Both child and parent continue executing with the instruction that follows the call to fork.

– The child is a copy of the parent.• Child gets a copy of parent’s data space, heap, and stack.• They share the text segment.• Modern implementations don’t perform a complete copy, since a fork is often followed

by an exec.• Copy-on-write (COW)

– Regions are shared by parent and child and have their protection changed by the kernel to read-only.

– If either process tries to modify these regions, the kernel then makes a copy of that piece of memory only.

© 2009 Wipro Ltd - Confidential28 © 2009 Wipro Ltd - Confidential28

fork è Exampleint glob = 6; /* external variable in initialized data */char buf[] = "a write to stdout\n";

int main(void){ int var = 88; /* automatic variable on the stack */ pid_t pid;

write(STDOUT_FILENO, buf, sizeof(buf) - 1); printf("before fork\n"); /* we don't flush stdout */

if ((pid = fork()) < 0) { err_sys("fork error"); } else if (pid == 0) { /* child */ glob++; /* modify variables */ var++; } else { sleep(2); /* parent */ } printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var); exit(0);}

© 2009 Wipro Ltd - Confidential29 © 2009 Wipro Ltd - Confidential29

fork è Example$ ./a.outa write to stdoutbefore forkpid = 430, glob = 7, var = 89 child's variables were changedpid = 429, glob = 6, var = 88 parent's copy was not changed$ ./a.out > temp.out$ cat temp.outa write to stdoutbefore forkpid = 432, glob = 7, var = 89before forkpid = 431, glob = 6, var = 88

• Who runs first?– In general, we never know whether the child starts executing before the

parent or vice versa. – Depends on the scheduling algorithm used by the kernel. – If both need to synchronize, some form of inter-process communication

is required.• In the example, we put the parent to sleep for 2 seconds.

© 2009 Wipro Ltd - Confidential30 © 2009 Wipro Ltd - Confidential30

fork è Example

• Why is the behaviour different between the 2 invocations?– write function is not buffered.– Because write is called before fork, its data is written once to stdout.– Standard I/O library is buffered.

• stdout is line buffered if it is connected to a terminal device.• Else, it is fully buffered.

– [1] When the program is run interactively, we get only a single copy of the printf line, because the stdout buffer is flushed by the newline.

– [2] when we redirect stdout to a file, printf before the fork is called once, but the line remains in the buffer when fork is called.

• This buffer is then copied into child when parent’s data space is copied.• Both parent and child now have a standard I/O buffer with this line in it.• The second printf, right before the exit, just appends its data to the

existing buffer.• When each process terminates, its copy of the buffer is finally flushed.

© 2009 Wipro Ltd - Confidential31 © 2009 Wipro Ltd - Confidential31

fork è Example/* fork.c -- Using multiple forks */

int main(){ fork(); fork(); fork(); fork(); printf("Hello World\n"); return 0;}

$ ./forkHello WorldHello World. . . repeated 16 timesHello World

© 2009 Wipro Ltd - Confidential32 © 2009 Wipro Ltd - Confidential32

fork è Exampleforkforkforkfork

printf

forkforkfork

printf

forkforkfork

printf

forkfork

printf

forkfork

printf

forkfork

printf

forkfork

printf

forkprintf

forkprintf

forkprintf

forkprintf

forkprintf

forkprintf

forkprintf

forkprintf

printf printf printf printf printf printf printf printf printf printf printf printf printf printf printf printf

© 2009 Wipro Ltd - Confidential33 © 2009 Wipro Ltd - Confidential33

fork è File Sharing

• All file descriptors that are open in parent are duplicated in child.– As if dup had been called for each descriptor.– Parent and child share a file table entry for every open descriptor.

• Eg: Consider a process that has three different files opened for stdin, stdout and stderr. On return from fork, open files are shared.

• It is important that parent and child share the same file offset.– A process forks a child, then waits for child to complete.– Both processes write to stdout as part of their normal processing.– If parent has its stdout redirected (Eg: by a shell), it is essential that

parent’s file offset be updated by child when child writes to stdout.– Child can write to stdout while parent is waiting for it.– On completion of child, parent can continue writing to stdout, knowing

that its output will be appended to whatever child wrote.– If they did not share the same file offset, this type of interaction would

be more difficult to accomplish.

© 2009 Wipro Ltd - Confidential34 © 2009 Wipro Ltd - Confidential34

fork è File Sharing

© 2009 Wipro Ltd - Confidential35 © 2009 Wipro Ltd - Confidential35

fork è File Sharing

• If parent and child write to the same descriptor without any form of synchronization, their output will be intermixed.

• 2 normal cases for handling descriptors after fork:– Parent waits for child to complete.

• Parent does not need to do anything with its descriptors.• When child terminates, any of the shared descriptors that child read from or

wrote to will have their file offsets updated accordingly.– Parent and child go their own ways.

• After fork, parent closes descriptors that it doesn’t need. Child does the same thing.

• This way, neither interferes with other’s open descriptors.• Often done in network servers.

© 2009 Wipro Ltd - Confidential36 © 2009 Wipro Ltd - Confidential36

fork è Inherited Attributes

• Open files• Real user ID, real group ID,

effective user ID, effective group ID

• Supplementary group IDs• Process group ID• Session ID• Controlling terminal• set-user-ID and set-group-ID

flags• Current working directory

• Root directory• File mode creation mask• Signal mask and dispositions• The close-on-exec flag for any

open file descriptors• Environment• Attached shared memory

segments• Memory mappings• Resource limits

© 2009 Wipro Ltd - Confidential37 © 2009 Wipro Ltd - Confidential37

fork è Non-inherited Attributes

• Return value from fork• Process IDs• Parent process IDs

– Parent process ID of child is parent– Parent process ID of parent doesn’t change

• Child’s tms_utime, tms_stime, tms_cutime, and tms_cstime values (set to 0)

• File locks set by parent are not inherited by child• Pending alarms are cleared for child• Set of pending signals for child is set to the empty set

© 2009 Wipro Ltd - Confidential38 © 2009 Wipro Ltd - Confidential38

fork è Uses

• When a process wants to duplicate itself so that parent and child can each execute different sections of code at the same time.– Common for network servers.– Parent waits for a service request from a client.– When the request arrives, parent calls fork and lets child handle the

request.– Parent goes back to waiting for the next service request to arrive.

• When a process wants to execute a different program. – Common for shells.– Child does an exec right after it returns from fork.

• Note: fork may fail due to:– Insufficient memory available for creation of child process.– Calling process has exceeded the resource limit of child processes.

© 2009 Wipro Ltd - Confidential39 © 2009 Wipro Ltd - Confidential39

Process Termination

• For any of the 8 ways of termination, we want the terminating process to be able to notify its parent how it terminated.– For exit functions, this is done by passing an exit status as the argument

to the function.– For abnormal termination, kernel generates a termination status to

indicate the reason.– Parent can obtain the termination status from either wait or waitpid

function.• What happens if parent terminates before child?

– init becomes the parent process of child.• When a process terminates, kernel goes through all active processes to see

whether it is the parent of any existing process.• If so, parent PID of the surviving process is changed to be 1.• Guaranteed that every process has a parent.

© 2009 Wipro Ltd - Confidential40 © 2009 Wipro Ltd - Confidential40

Process Termination

• What happens if child terminates before parent?– If child disappears completely, parent won’t be able to fetch child’s

termination status.• By the time parent is ready to check termination status, kernel may have

discarded it.– Zombieà A process that has terminated, but whose parent has not yet

waited for it.– If we write a long-running program that forks many child processes, they

become zombies unless we wait for them and fetch their termination status.

• What happens when a process that has been inherited by initterminates?– Does it become a zombie? No.– init is written so that whenever one of its children terminates, init

calls one of the wait functions to fetch the termination status.– init prevents the system from being clogged by zombies.

© 2009 Wipro Ltd - Confidential41 © 2009 Wipro Ltd - Confidential41

Process Termination Status

• When a process terminates (normally or abnormally), kernel notifies parent by sending SIGCHLD signal to parent.– Parent can choose to ignore it (default action), or– It can provide a signal handler.

• pid_t wait(int *statloc)• pid_t waitpid(pid_t pid, int *statloc, int options)

– Block, if all of its children are still running.– Return immediately with termination status of a child, if it has terminated

and is waiting for its termination status to be fetched.– Return immediately with an error, if it doesn’t have any child processes.

• Termination status is different from exit status.– Exit status is argument to one of the exit functions or return value from

main.– Converted into a termination status by the kernel when _exit is finally

called.

© 2009 Wipro Ltd - Confidential42 © 2009 Wipro Ltd - Confidential42

Process Termination Status

– Macros to examine termination status returned by wait & waitpid.

Macro Description Additional InformationWIFEXITED(status) True if status was returned for a

child that terminated normally.WEXITSTATUS(status)to fetch the low-order 8 bits of the argument that the child passed to exit, _exit,or _Exit.

WIFSIGNALED(status) True if status was returned for a child that terminated abnormally, by receipt of a signal that it didn't catch.

WTERMSIG(status)to fetch the signal number that caused the termination.

WIFSTOPPED(status) True if status was returned for a child that is currently stopped.

WSTOPSIG(status)to fetch the signal number that caused the child to stop.

WIFCONTINUED(status) True if status was returned for a child that has been continued after a job control stop.

© 2009 Wipro Ltd - Confidential43 © 2009 Wipro Ltd - Confidential43

Process Termination

• Differences between wait & waitpid:– wait can block the caller until a child process terminates; waitpid has

an option that prevents it from blocking.– waitpid doesn't wait for the child that terminates first; it has a number

of options that control which process it waits for.• If a child has already terminated and is a zombie, wait returns

immediately with that child’s status.• Otherwise, it blocks the caller until a child terminates.

– If the caller blocks and has multiple children, wait returns when one terminates.

– We can find out which child has terminated because its PID is returned by wait.

© 2009 Wipro Ltd - Confidential44 © 2009 Wipro Ltd - Confidential44

Process Termination

• Eg: Print a description of the exit status.

void pr_exit(int status){ if (WIFEXITED(status)) printf("normal termination, exit status = %d\n", WEXITSTATUS(status)); else if (WIFSIGNALED(status)) printf("abnormal termination, signal number = %d\n", WTERMSIG(status)); else if (WIFSTOPPED(status)) printf("child stopped, signal number = %d\n", WSTOPSIG(status));}

© 2009 Wipro Ltd - Confidential45 © 2009 Wipro Ltd - Confidential45

Process Termination

• Eg: Termination status with multiple children.int main(void){ pid_t pid; int status;

if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) /* child */ exit(7);

if (wait(&status) != pid) /* wait for child */ err_sys("wait error"); pr_exit(status); /* and print its status */

if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) /* child */ abort(); /* generates SIGABRT */

© 2009 Wipro Ltd - Confidential46 © 2009 Wipro Ltd - Confidential46

Process Termination

• Eg: Termination status with multiple children (continued). if (wait(&status) != pid) /* wait for child */ err_sys("wait error"); pr_exit(status); /* and print its status */

if ((pid = fork()) < 0) err_sys("fork error"); else if (pid == 0) /* child */ status /= 0; /* divide by 0 generates SIGFPE */

if (wait(&status) != pid) /* wait for child */ err_sys("wait error"); pr_exit(status); /* and print its status */ exit(0);}

$ ./a.outnormal termination, exit status = 7abnormal termination, signal number = 6abnormal termination, signal number = 8

© 2009 Wipro Ltd - Confidential47 © 2009 Wipro Ltd - Confidential47

Waiting For A Specific Process

• waitpid provides ability to wait for a specific process to terminate.

pid argument Behaviourpid == -1 Waits for any child process. (Equivalent to wait.)pid > 0 Waits for the child whose process ID equals pid.pid == 0 Waits for any child whose process group ID equals that of

the calling process.pid < -1 Waits for any child whose process group ID equals the

absolute value of pid.

© 2009 Wipro Ltd - Confidential48 © 2009 Wipro Ltd - Confidential48

Zombie Process è Example/* mkzombie.c -- Create some defunct processes */

int main(void){ pid_t pids[5]; int i;

for (i = 4; i >= 0; --i) { pids[i] = fork(); if (pids[i] == 0) _exit(0); }

sleep(5);

for (i = 4; i >= 0; --i) waitpid(pids[i], NULL, 0);

return 0;}

© 2009 Wipro Ltd - Confidential49 © 2009 Wipro Ltd - Confidential49

Zombie Process è Example

$ ./mkzombie & ps jHT[1] 18306 PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND13644 13700 13700 13700 pts/5 18307 Rs 1002 0:00 -bash13700 18306 18306 13700 pts/5 18307 S 1002 0:00 ./mkzombie13700 18307 18307 13700 pts/5 18307 R+ 1002 0:00 ps jHT18306 18308 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>18306 18309 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>18306 18310 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>18306 18311 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>18306 18312 18306 13700 pts/5 18307 Z 1002 0:00 [mkzombie] <defunct>$ after 5 seconds$ ps jHT PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND13644 13700 13700 13700 pts/5 18317 Ss 1002 0:00 -bash13700 18317 18317 13700 pts/5 18317 R+ 1002 0:00 ps jHT[1]+ Done ./mkzombie$

Exact options might vary across systems.

© 2009 Wipro Ltd - Confidential50 © 2009 Wipro Ltd - Confidential50

Orphan Process è Example

/* mkorphan.c -- Create some orphan processes */

int main(void){ pid_t pids[5]; int i;

for (i = 4; i >= 0; --i) { pids[i] = fork(); if (pids[i] == 0) { /* to avoid child exiting before parent */ sleep(5); _exit(0); } }

/* exit without waiting for children */ return 0;}

© 2009 Wipro Ltd - Confidential51 © 2009 Wipro Ltd - Confidential51

Zombie Process è Example

$ ./mkorphan & ps jHT[1] 18463 PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND13644 13700 13700 13700 pts/5 18464 Rs 1002 0:00 -bash13700 18463 18463 13700 pts/5 18464 Z 1002 0:00 [mkorphan] <defunct>13700 18464 18464 13700 pts/5 18464 R+ 1002 0:00 ps jHT 1 18465 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan 1 18466 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan 1 18467 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan 1 18468 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan 1 18469 18463 13700 pts/5 18464 S 1002 0:00 ./mkorphan[1]+ Done ./mkorphan$ after ~5 seconds$ ps jHT PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND13644 13700 13700 13700 pts/5 18476 Ss 1002 0:00 -bash13700 18476 18476 13700 pts/5 18476 R+ 1002 0:00 ps jHT$

Exact options might vary across systems.

A very transient state.

© 2009 Wipro Ltd - Confidential52 © 2009 Wipro Ltd - Confidential52

exec Functions

• When a process calls one of the exec functions, that process is completely replaced by the new program.

• New program starts executing at its main function.• PID does not change across an exec.

– A new process is not created.– exec merely replaces the current process’ text, data, heap and stack

segments with a new program from disk.

© 2009 Wipro Ltd - Confidential53 © 2009 Wipro Ltd - Confidential53

Process Life Cycle è date

PID à 300PPID à 200

_______________sh

PID à 400PPID à 300

_______________date

PID à 400PPID à 300

_______________sh

Zombie

fork()

exec()exit()

exit status

© 2009 Wipro Ltd - Confidential54 © 2009 Wipro Ltd - Confidential54

exec Functions

• int execl(const char *pathname, const char *arg0, ... /* (char *)0 */)

• int execv(const char *pathname, char *const argv[])• int execle(const char *pathname, const char *arg0, ... /*

(char *)0, char *const envp[] */)• int execve(const char *pathname, char *const argv[], char

*const envp [])• int execlp(const char *filename, const char *arg0, ... /*

(char *)0 */)• int execvp(const char *filename, char *const argv[])

© 2009 Wipro Ltd - Confidential55 © 2009 Wipro Ltd - Confidential55

exec Functions

• l stands for list:– Require each of the command-line arguments to new program to be

specified as separate arguments. – End of arguments marked with a NULL pointer.

• v stands for vector:– Build an array of pointers to the arguments, and the address of this

array is the argument.• p stands for path:

– Takes a filename argument.– Uses the PATH environment variable to find the executable file.

• e stands for environment:– Takes an envp[] array instead of using the current environment.

© 2009 Wipro Ltd - Confidential56 © 2009 Wipro Ltd - Confidential56

exec Functions è Inherited Properties

• Process ID and parent process ID• Real user ID, real group ID, Supplementary group IDs• Process group ID• Session ID• Controlling terminal• Time left until alarm clock• Current working directory• Root directory• File mode creation mask• File locks• Process signal mask• Pending signals• Resource limits• Values for tms_utime, tms_stime, tms_cutime and tms_cstime

© 2009 Wipro Ltd - Confidential57 © 2009 Wipro Ltd - Confidential57

exec è Exampleint main(){ pid_t pid; int status;

char *arg[] = { "/usr/bin/whoami", 0 }; extern char **environ;

switch (pid = fork()) { case -1: sys_err("fork failed"); case 0: /* On success, execve does not return */ execve(arg[0], arg, environ); printf("exec succeeded\n"); default: wait(&status); } return 0;}

$ ./a.outharry$

© 2009 Wipro Ltd - Confidential58 © 2009 Wipro Ltd - Confidential58

Exercises

1. A program which has opened some files calls _exit() without closing the file descriptors. Will the files remain open? Will the process exit properly? Is the behaviour any different if exit() was used instead?

2. From a process, create a child using fork(). Try to print the values of inheritable & non-inheritable attributes from both parent & child.

3. Write your own implementation of the system() library call.

© 2009 Wipro Ltd - Confidential59

Process Relationships

© 2009 Wipro Ltd - Confidential60 © 2009 Wipro Ltd - Confidential60

Process Groups

• Each process belongs to a process group.• A process group is a collection of one or more processes.

– Usually associated with the same job.– Can receive signals from the same terminal.– Each process group has a unique process group ID.

• pid_t getpgrp(void)– Returns the process group ID of calling process.

• Each process group can have a process group leader.– Identified by its process group ID being equal to its process ID.– Possible for a process group leader to create a process group, create

processes in the group, and then terminate.– Process group still exists, as long as at least one process is in group,

regardless of whether process group leader terminates.

© 2009 Wipro Ltd - Confidential61 © 2009 Wipro Ltd - Confidential61

Process Groups

• int setpgid(pid_t pid, pid_t pgid)– A process can join an existing process group or create a new process

group.– A process can set the process group ID of only itself or any of its

children.• It is possible to:

– Send a signal to either a single process or a process group.– Wait for a single process or one process from a specified process group

using waitpid.

© 2009 Wipro Ltd - Confidential62 © 2009 Wipro Ltd - Confidential62

Sessions

• A session is a collection of one or more process groups.– Eg:

$ proc1 | proc2 &$ proc3 | proc4 | proc5

© 2009 Wipro Ltd - Confidential63 © 2009 Wipro Ltd - Confidential63

Sessions

• Process that creates a session is called a session leader.• A process establishes a new session by:

– pid_t setsid(void)– If calling process is not a process group leader,

• It becomes session leader of this new session. It is the only process in this new session.

• It becomes process group leader of a new process group. The new process group ID is the process ID of the calling process.

• It has no controlling terminal. If it had a controlling terminal before calling setsid, that association is broken.

© 2009 Wipro Ltd - Confidential64 © 2009 Wipro Ltd - Confidential64

Sessions è Example/* setsid.c -- Session example */

int main(){ pid_t pid, sid;

if ((pid = fork()) == -1) sys_err("fork error"); else if (pid != 0) { printf("parent=%d, child=%d\n", getpid(), pid); exit(EXIT_SUCCESS); } if ((sid = setsid()) == -1) sys_err("setsid error");

printf("pid=%d, sid=%d, pgid=%d\n", getpid(), sid, getpgrp()); return 0;}

$ ./setsidparent=29512, child=29513pid=29513, sid=29513, pgid=29513

© 2009 Wipro Ltd - Confidential65

Signals

© 2009 Wipro Ltd - Confidential66 © 2009 Wipro Ltd - Confidential66

• Software interrupts.• Provide a way of handling asynchronous events.

– Eg: A user at a terminal typing the interrupt key to stop a program, letting parent process know that its child has terminated etc.

• Every signal has a name (beginning with “SIG”).– Defined by positive integer constants (signal number) in <signal.h>.– Eg: Some well known signals:

Introduction

Signal Value CommentSIGHUP 1 Hangup detected on controlling terminal or death of controlling processSIGINT 2 Interrupt from keyboardSIGKILL 9 Kill signalSIGSEGV 11 Invalid memory referenceSIGTERM 15 Termination signal

© 2009 Wipro Ltd - Confidential67 © 2009 Wipro Ltd - Confidential67

• Numerous conditions can generate a signal:– Terminal-generated signals occur when users press certain terminal

keys.• Eg: <Control-C> causing SIGINT to be generated.

– Hardware exceptions. • Kernel generates appropriate signal for the process.• Eg: Divide by 0, invalid memory reference.

– kill system call allows a process to send any signal to another process or process group.

• Have to be the owner of the process that we're sending the signal to, or be the superuser.

• Also used by kill command.– Software conditions.

• Eg: SIGPIPE generated when a process writes to a pipe after the reader of the pipe has terminated.

Signal Generation

© 2009 Wipro Ltd - Confidential68 © 2009 Wipro Ltd - Confidential68

Handling Signals

• To a process, signals seemingly appear to be random.– So it can’t simply test a variable to see whether a signal has occurred.– Instead, process has to tell kernel “if and when this signal occurs, do the

following.” (Disposition of the signal, or the action associated it)• Possible actions:

– Ignore the signal.• SIGKILL and SIGSTOP can never be ignored.

– Catch the signal.• By telling the kernel to call a function (signal handler) of ours whenever the signal

occurs.• Handling the condition is left to the function implementation.

– When SIGCHLD is caught, calling waitpid to fetch child's PID and termination status.

– Handling SIGTERM (default signal sent by kill command) to clean up temporary files created by the process.

• SIGKILL and SIGSTOP cannot be caught.– Let the default action apply.

• Every signal has a default action.

© 2009 Wipro Ltd - Confidential69 © 2009 Wipro Ltd - Confidential69

Handling Signals• void (*signal(int signo, void (*func)(int)))(int)

– func is SIG_IGN (ignore), SIG_DFL (default) or address of signal handler.

static void sig_usr(int signo) /* argument is signal number */{ if (signo == SIGUSR1) printf("received SIGUSR1\n"); else if (signo == SIGUSR2) printf("received SIGUSR2\n"); else err_dump("received signal %d\n", signo);}

int main(void){ if (signal(SIGUSR1, sig_usr) == SIG_ERR) err_sys("can't catch SIGUSR1"); if (signal(SIGUSR2, sig_usr) == SIG_ERR) err_sys("can't catch SIGUSR2"); for ( ; ; ) pause(); /* suspends calling process until a signal is received */}

It is possible to use the same signal handler for handling multiple signals.

© 2009 Wipro Ltd - Confidential70 © 2009 Wipro Ltd - Confidential70

Handling Signals

– Behaviour from command line:

– When a process calls fork, child inherits parent’s signal dispositions.• So address of a signal-catching function has meaning in the child.

$ ./a.out & start process in background[1] 7216 job-control shell prints job number & Process ID$ kill -USR1 7216 send it SIGUSR1received SIGUSR1$ kill -USR1 7216 send it SIGUSR1 againreceived SIGUSR1$ kill -USR1 7216 send it SIGUSR1 one last timereceived SIGUSR1$ kill -USR2 7216 send it SIGUSR2received SIGUSR2$ kill 7216 now send it SIGTERM[1]+ Terminated ./a.out

© 2009 Wipro Ltd - Confidential71 © 2009 Wipro Ltd - Confidential71

• Signal generation– A signal is generated for a process (or sent to a process) when the

event that causes the signal occurs.• Event could be a hardware exception (Eg: divide by 0), a software condition

(Eg: an alarm timer expiring), a terminal-generated signal, or a call to killfunction.

– When the signal is generated, kernel sets a flag of some form in the process table.

• Signal delivery– A signal is delivered to a process when the action for a signal is taken.

• Signal pending– During the time between generation of a signal and its delivery, the

signal is said to be pending.

Signal Terminology

© 2009 Wipro Ltd - Confidential72 © 2009 Wipro Ltd - Confidential72

Signal Terminology

• Signal blocking– A process has the option of blocking the delivery of a signal.– If a signal that is blocked is generated for a process, and if the action for

that signal is either the default action or to catch the signal, then the signal remains pending for the process until the process either:

• unblocks the signal, or • changes the action to ignore the signal.

– The system determines what to do with a blocked signal when the signal is delivered, not when it's generated.

• Signal mask– Each process has a signal mask that defines the set of signals currently

blocked from delivery to that process.• Signal set

– Data type (sigset_t) to represent multiple signals.– Eg: Signal mask is stored in a signal set.

© 2009 Wipro Ltd - Confidential73 © 2009 Wipro Ltd - Confidential73

Signal Generation è kill and raise

• int kill(pid_t pid, int signo)– Sends a signal to a process or a group of processes.

• int raise(int signo)– Allows a process to send a signal to itself.– Equivalent to: kill(getpid(), signo);

pid Behaviour> 0 Signal is sent to the process whose process ID is pid.== 0 Signal is sent to all processes whose process group ID equals the

process group ID of the sender and for which the sender has permission to send the signal.

< -1 Signal is sent to all processes whose process group ID equals the absolute value of pid and for which the sender has permission to send the signal.

== -1 Signal is sent to all processes on the system for which the sender has permission to send the signal.

Note: (For the last 3 cases (pid <= 0), system processes (kernel processes and init) are excluded.

© 2009 Wipro Ltd - Confidential74 © 2009 Wipro Ltd - Confidential74

Signal Generation è kill and raise

• A process needs permission to send a signal to another process.– Superuser can send a signal to any process.– For other users, basic rule is:

• Real or effective user ID of sender = Real or effective user ID of receiver.

© 2009 Wipro Ltd - Confidential75 © 2009 Wipro Ltd - Confidential75

Signal Generation è alarm and pause

• unsigned int alarm(unsigned int seconds)– Sets a timer that will expire at a specified time in future.

• When timer expires, SIGALRM signal is generated.– Default action is to terminate the process.

• But most processes that use an alarm clock catch SIGALRM.– Ensure that signal handler is installed before calling alarm.

– Only one alarm clock per process.• If we call alarm, and a previously registered alarm has not expired:

– Time left for previous alarm clock is returned.– Previous registered alarm clock is replaced by new value.

– fork clears pending alarms in child process.• int pause(void)

– Suspends calling process until a signal is caught.• If signal’s action is to terminate the process, pause will not return.• If action is to execute a signal handler, pause will return -1 after handler

returns.

© 2009 Wipro Ltd - Confidential76 © 2009 Wipro Ltd - Confidential76

alarm & pause è Examplestatic void catch_sig(int signo){ if (signo == SIGALRM) printf("Caught SIGALRM\n");}

int main(void){ signal(SIGALRM, catch_sig); printf("Timeout in 5 seconds\n");

alarm(5); /* Timeout in 5 seconds */ pause();

return 0;}

$ ./a.outTimeout in 5 secondsCaught SIGALRM$

© 2009 Wipro Ltd - Confidential77 © 2009 Wipro Ltd - Confidential77

Signal Set Operations• int sigemptyset(sigset_t *set)

– Initialize signal set so that all signals are excluded.• int sigfillset(sigset_t *set)

– Initialize signal set so that all signals are included.• int sigaddset(sigset_t *set, int signo)

– Add a signal to an existing set.• int sigdelset(sigset_t *set, int signo)

– Remove a signal from an existing set.• int sigismember(const sigset_t *set, int signo)

– Tests whether a signal is a member of an existing set.

• Note:– No signal set should be used unless sigemptyset or sigfillset has

been called to initialize the set.– Any signal set function can be applied after initialization has been

performed.

© 2009 Wipro Ltd - Confidential78 © 2009 Wipro Ltd - Confidential78

Signal Set Operations è Exampleint main(){ sigset_t sigset1, sigset2;

sigemptyset(&sigset1); /* Initialize as empty */ sigaddset(&sigset1, SIGINT); /* Add SIGINT to set */ sigaddset(&sigset1, SIGPIPE); /* Add SIGPIPE to set */

sigfillset(&sigset2); /* Initialize with all sigs */ sigdelset(&sigset2, SIGINT); /* Del SIGINT from set */

if (sigismember(&sigset1, SIGINT)) printf("sigset1 has SIGINT\n"); else printf("sigset1 doesn't have SIGINT\n");

if (sigismember(&sigset1, SIGTERM)) printf("sigset1 has SIGTERM\n"); else printf("sigset1 doesn't have SIGTERM\n");

© 2009 Wipro Ltd - Confidential79 © 2009 Wipro Ltd - Confidential79

Signal Set Operations è Example if (sigismember(&sigset2, SIGINT)) printf("sigset2 has SIGINT\n"); else printf("sigset2 doesn't have SIGINT\n");

if (sigismember(&sigset2, SIGTERM)) printf("sigset2 has SIGTERM\n"); else printf("sigset2 doesn't have SIGTERM\n");

return 0;}

$ ./a.outsigset1 has SIGINTsigset1 doesn't have SIGTERMsigset2 doesn't have SIGINTsigset2 has SIGTERM

© 2009 Wipro Ltd - Confidential80 © 2009 Wipro Ltd - Confidential80

Blocking Signals

• Certain signals could be blocked during call to signal handler.• Use case è An application can enter a critical piece of code where

signals could cause problems.– Eg:

• A program is keeping track of child process termination status in a linked list.• If program is updating the list, you do not want signal handler to be called

until the list has been completely updated.• Otherwise, corruption of the list would result.

– Critical sections of code can block certain signals from taking place.– Once critical section is completed, then selected signals can be

enabled.– This functionality is supported by sigprocmask.

© 2009 Wipro Ltd - Confidential81 © 2009 Wipro Ltd - Confidential81

Signal Mask Operations• int sigprocmask(int how, const sigset_t *set, sigset_t *oldset)

– A process can examine its signal mask, change its signal mask, or perform both operations in one step.

– If oldset is a non-NULL, process’ current signal mask is returned through it.– If set is a non-NULL, how indicates how current signal mask is modified.

– After calling sigprocmask, if any unblocked signals are pending, at least one of them is delivered to the process before sigprocmask returns.

– Defined only for single-threaded processes.

how DescriptionSIG_BLOCK New signal mask = Current signal mask U set.

(set contains additional signals to be blocked.)SIG_UNBLOCK New signal mask = Current signal mask • Complement of set.

(set contains the additional signals to be unblocked.)

SIG_SETMASK New signal mask = set.

© 2009 Wipro Ltd - Confidential82 © 2009 Wipro Ltd - Confidential82

Signal Mask Operations è Example

/* Example showing how to block signals SIGINT & SIGPIPE from being received */

sigset_t set_block; /* Signals to block */sigset_t set_save; /* Saved signal mask */

sigemptyset(&set_block); /* Clear set */sigaddset(&set_block, SIGINT); /* Add SIGINT */sigaddset(&set_block, SIGPIPE); /* Add SIGPIPE */sigprocmask(SIG_BLOCK, &set_block, &set_save); /* Block signals */

/* !!! Critical code goes here !!! */

sigprocmask(SIG_SETMASK, &set_save, 0); /* Restore mask */

© 2009 Wipro Ltd - Confidential83 © 2009 Wipro Ltd - Confidential83

Pending Signals

• When signals are blocked by sigprocmask,– They are not ‘lost’.– Rather, they become pending signals.– A program can inquire if a signal is pending.

• int sigpending(sigset_t *set)– Gets set of signals that are blocked from delivery and currently pending

for the calling process.– Once pending set is obtained, you can query for a specific signal using

sigismember.

© 2009 Wipro Ltd - Confidential84 © 2009 Wipro Ltd - Confidential84

Signal Mask/Set/Pending è Examplestatic void sig_quit(int signo){ printf("caught SIGQUIT\n"); if (signal(SIGQUIT, SIG_DFL) == SIG_ERR) printf("can't reset SIGQUIT");}

int main(void){ sigset_t newmask, oldmask, pendmask;

if (signal(SIGQUIT, sig_quit) == SIG_ERR) printf("can't catch SIGQUIT");

/* Block SIGQUIT and save current signal mask. */ sigemptyset(&newmask); sigaddset(&newmask, SIGQUIT); if (sigprocmask(SIG_BLOCK, &newmask, &oldmask) < 0) printf("SIG_BLOCK error");

Beware: changing the order of sigemptysetand sigaddset is a common bug.

© 2009 Wipro Ltd - Confidential85 © 2009 Wipro Ltd - Confidential85

Signal Mask/Set/Pending è Example sleep(5); /* SIGQUIT here will remain pending */ if (sigpending(&pendmask) < 0) printf("sigpending error"); if (sigismember(&pendmask, SIGQUIT)) printf("\nSIGQUIT pending\n");

/* Reset signal mask which unblocks SIGQUIT. */ if (sigprocmask(SIG_SETMASK, &oldmask, NULL) < 0) printf("SIG_SETMASK error"); printf("SIGQUIT unblocked\n");

sleep(5); /* SIGQUIT here will terminate with core file */ exit(0);}

$ ./a.out^\ generate signal once (before 5 seconds are up)SIGQUIT pending after return from sleepcaught SIGQUIT in signal handlerSIGQUIT unblocked after return from sigprocmask^\Quit(coredump) generate signal again; printed by shell$

© 2009 Wipro Ltd - Confidential86 © 2009 Wipro Ltd - Confidential86

Signal Mask/Set/Pending è Example

– Notes:• <Control-backslash> is the terminal quit character.

– Understand the correct characters on your system by running ‘stty –a’command.

• If a signal is pending and becomes unblocked, it is delivered before sigprocmask returns.

• Though the quit signal is generated multiple times while the process is asleep, it is delivered only once to the process when it’s unblocked.

– Signals are not queued.• The message Quit(coredump) is printed by the shell when it sees that its

child terminated abnormally.

$ ./a.out^\^\^\ generate signal 3 times (before 5 seconds are up)SIGQUIT pending after return from sleepcaught SIGQUIT in signal handler; signal is generated only onceSIGQUIT unblocked after return from sigprocmask^\Quit(coredump) generate signal again; printed by shell$

© 2009 Wipro Ltd - Confidential87 © 2009 Wipro Ltd - Confidential87

Signal Action• int sigaction(int signo, const struct sigaction *act, struct

sigaction *oldact)– Examine or modify (or both) action associated with a particular signal.– Supersedes signal.

– oldact allows us to obtain original handler state.• Used when new handler is temporary, such as within a library function.• Before library function returns, original signal action can be restored

precisely as it was.– sa_mask represents the set of other signals that should be blocked

while current signal is being processed.• In addition, signal being processed will be blocked unless SA_NODEFER or SA_NOMASK flag is used.

struct sigaction { void (*sa_handler)(int); /* address of signal handler, */ /* or SIG_IGN, or SIG_DFL */ sigset_t sa_mask; /* additional signals to block */ int sa_flags; /* signal options */ void (*sa_sigaction)(int, siginfo_t *, void *); /* alternate handler */};

© 2009 Wipro Ltd - Confidential88 © 2009 Wipro Ltd - Confidential88

Signal Action è Examplestatic int count = 0;

void handler(int signo){ ++count; printf("Got SIGINT (%d)\n", signo);}

void get_handler_status(int signo){ struct sigaction sa_old;

if (sigaction(signo, 0, &sa_old) == -1) /* Query signal */ sys_err("sigaction failed");

if (sa_old.sa_handler == SIG_DFL) printf("SIG_DFL - System default\n"); else if (sa_old.sa_handler == SIG_IGN) printf("SIG_IGN - Ignore signal\n"); else printf("sa_handler=%p\n", sa_old.sa_handler);}

© 2009 Wipro Ltd - Confidential89 © 2009 Wipro Ltd - Confidential89

Signal Action è Exampleint main(void){ struct sigaction sa_old, sa_new;

get_handler_status(SIGINT); /* Get default action */

sa_new.sa_handler = handler; sigemptyset(&sa_new.sa_mask); sa_new.sa_flags = 0; sigaction(SIGINT, &sa_new, &sa_old); /* Save old action */ get_handler_status(SIGINT); /* Verify new action */

while (count < 2) { printf("Waiting for SIGINT...\n"); sleep(4); }

sigaction(SIGINT, &sa_old, 0); /* Restore old action */ get_handler_status(SIGINT); /* Verify old action */ return 0;}

© 2009 Wipro Ltd - Confidential90 © 2009 Wipro Ltd - Confidential90

Signal Action è Example$ ./a.outSIG_DFL - System defaultsa_handler=0x4006dcWaiting for SIGINT...Waiting for SIGINT...Waiting for SIGINT...Waiting for SIGINT...^CGot SIGINT (2)Waiting for SIGINT...Waiting for SIGINT...^CGot SIGINT (2)SIG_DFL - System default$

© 2009 Wipro Ltd - Confidential91 © 2009 Wipro Ltd - Confidential91

Unblocking Pending Signals

• After noting that a signal is pending, we need a way to unblock that signal and allow the signal to be raised.

• int sigsuspend(sigset_t *set)– Temporarily applies the signal mask supplied and waits for signal to be

raised.– If the mask permits the signal you know to be pending, signal action will

take place immediately.– Otherwise, the program will pause indefinitely until an unblocked signal

is received.– Once signal action is carried out, original signal mask is re-established.

• When sigsuspend is called, program is suspended indefinitely until a signal is raised.

© 2009 Wipro Ltd - Confidential92 © 2009 Wipro Ltd - Confidential92

sigsuspendè Examplesigset_t pending; /* Pending signal set */sigset_t notpipe; /* All but SIGPIPE */

sigfillset(&notpipe); /* Set to all signals */sigdelset(&notpipe, SIGPIPE); /* Remove SIGPIPE */

sigpending(&pending); /* Query which signals are pending */if (sigismember(&pending, SIGPIPE)) /* Is SIGPIPE pending? */ sigsuspend(&notpipe); /* Yes, allow SIGPIPE to be raised */

© 2009 Wipro Ltd - Confidential93 © 2009 Wipro Ltd - Confidential93

sigsuspendè Examplestatic void catch_sig(int signo){ if (signo == SIGINT) { alarm(0); /* Cancel the timer */ printf("CAUGHT SIGINT\n"); } else if (signo == SIGALRM) printf("CAUGHT SIGALRM\n");}

int main(void){ sigset_t sigs; struct sigaction sa_old, sa_new;

sa_new.sa_handler = catch_sig; sigemptyset(&sa_new.sa_mask); sigaddset(&sa_new.sa_mask, SIGALRM); sigaddset(&sa_new.sa_mask, SIGINT); sa_new.sa_flags = 0;

sigaction(SIGINT, &sa_new, &sa_old); sigaction(SIGALRM, &sa_new, 0);

© 2009 Wipro Ltd - Confidential94 © 2009 Wipro Ltd - Confidential94

sigsuspendè Example sigfillset(&sigs); sigdelset(&sigs, SIGINT); sigdelset(&sigs, SIGALRM);

printf("You have 10 seconds to SIGINT:\n");

alarm(10); /* Timeout in 10 seconds */ sigsuspend(&sigs); /* Wait for SIGINT or SIGALRM */

printf("Done\n"); return 0;}

$ ./a.outYou have 10 seconds to SIGINT:CAUGHT SIGALRMDone$ ./a.outYou have 10 seconds to SIGINT:CAUGHT SIGINTDone$

Let the timer expire by not issuing a keyboard interrupt.

Before the timer expires, issue a keyboard interrupt.

© 2009 Wipro Ltd - Confidential95 © 2009 Wipro Ltd - Confidential95

Job-Control Signals

• Usually 6.

SIGCHLD Child process has stopped or terminated.SIGCONT Continue process, if stopped.SIGSTOP Stop signal (can't be caught or ignored).SIGTSTP Interactive stop signal.SIGTTIN Read from controlling terminal by member of a background process group.SIGTTOU Write to controlling terminal by member of a background process group.

© 2009 Wipro Ltd - Confidential96

Daemon Processes

© 2009 Wipro Ltd - Confidential97 © 2009 Wipro Ltd - Confidential97

• Processes that live for a long time.– Often started during system boot-up & terminate only when system is

shutdown.– Perform specific perform day-to-day activities.

• Don’t have a controlling terminal; so they “run in the background”.• Typical output from ps command:

Daemon Characteristics

PPID PID PGID SID TTY TPGID STAT UID TIME COMMAND1 3809 3809 3809 ? -1 Ss 101 0:02 /sbin/syslogd1 3866 3866 3866 ? -1 Ss 0 0:00 /usr/sbin/sshd1 3882 3882 3882 ? -1 Ss 0 0:11 /usr/sbin/nmbd -D1 3884 3884 3884 ? -1 Ss 0 0:00 /usr/sbin/smbd -D1 3900 3899 3899 ? -1 S 0 0:00 /usr/sbin/vsftpd1 3931 3931 3931 ? -1 Ss 1 0:00 /usr/sbin/atd1 3956 3956 3956 ? -1 Ss 0 0:02 /usr/sbin/cron1 3975 3975 3975 ? -1 Ss 0 0:13 /usr/sbin/apache2

© 2009 Wipro Ltd - Confidential98 © 2009 Wipro Ltd - Confidential98

Coding Rules

1. Call umask to set file mode creation mask to 0.– Mask that’s inherited could be set to deny certain permissions.– If daemon process is going to create files, it may want to set specific

permissions.2. Call fork and have parent exit.

– If daemon was started from a shell, having parent terminate makes the shell think that the command is done.

– Inherits process group ID of parent but gets a new PID.• Guarantees that child is not a process group leader.• Prerequisite for Step 3.

3. Call setsid to create a new session.– The process:

• Becomes a session leader of a new session.• Becomes process group leader of a new process group.• Has no controlling terminal.

© 2009 Wipro Ltd - Confidential99 © 2009 Wipro Ltd - Confidential99

Coding Rules

4. Change current working directory (CWD) to root directory.– CWD inherited from parent could be on a mounted file system.– Since daemons normally exist until the system is rebooted, if the

daemon stays on a mounted file system, that file system cannot be unmounted.

5. Unneeded file descriptors should be closed.– Prevent daemon from holding open any descriptors that it may have

inherited from its parent.6. Some daemons open file descriptors 0, 1, and 2 to /dev/null.

– Any library routines that try to read from standard input or write to standard output or standard error will have no effect.

• Some systems provide a daemon routine to achieve these.– We will implement our own version of this.

© 2009 Wipro Ltd - Confidential100 © 2009 Wipro Ltd - Confidential100

Daemon Coding Rules è Examplevoid daemonize(const char *cmd){ int i, fd0, fd1, fd2; pid_t pid; struct rlimit rl; struct sigaction sa;

/* Clear file creation mask. */ umask(0);

/* Get maximum number of file descriptors. */ if (getrlimit(RLIMIT_NOFILE, &rl) < 0) err_quit("%s: can't get file limit", cmd);

/* Become a session leader to lose controlling TTY. */ if ((pid = fork()) < 0) err_quit("%s: can't fork", cmd); else if (pid != 0) /* parent */ exit(0); setsid();

© 2009 Wipro Ltd - Confidential101 © 2009 Wipro Ltd - Confidential101

Daemon Coding Rules è Example /* Ensure future opens won't allocate controlling TTYs. */ sa.sa_handler = SIG_IGN; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; if (sigaction(SIGHUP, &sa, NULL) < 0) err_quit("%s: can't ignore SIGHUP"); if ((pid = fork()) < 0) err_quit("%s: can't fork", cmd); else if (pid != 0) /* parent */ exit(0);

/* Change the current working directory to the root so * we won't prevent file systems from being unmounted. */ if (chdir("/") < 0) err_quit("%s: can't change directory to /");

/* Close all open file descriptors. */ if (rl.rlim_max == RLIM_INFINITY) rl.rlim_max = 1024; for (i = 0; i < rl.rlim_max; i++) close(i);

© 2009 Wipro Ltd - Confidential102 © 2009 Wipro Ltd - Confidential102

Daemon Coding Rules è Example /* Attach file descriptors 0, 1, and 2 to /dev/null. */ fd0 = open("/dev/null", O_RDWR); fd1 = dup(0); fd2 = dup(0);

/* Initialize the log file. */ openlog(cmd, LOG_CONS, LOG_DAEMON); if (fd0 != 0 || fd1 != 1 || fd2 != 2) { syslog(LOG_ERR, "unexpected file descriptors %d %d %d", fd0, fd1, fd2); exit(1); }}

© 2009 Wipro Ltd - Confidential103 © 2009 Wipro Ltd - Confidential103

Daemon Conventions

• Single-instance daemons use file locking to ensure that only one copy of a daemon is running.– Daemon creates a file and places a write lock on the entire file. – Another attempt to write lock will fail, indicating that another daemon

instance is already running.– Lock will be removed automatically if daemon exits.

• If daemon uses a lock file, it is usually stored in /var/run.– Usually <name>.pid, where <name> is name of daemon or service.

• If daemon supports configuration options, they are usually stored in /etc.– Usually named <name>.conf.

• Usually started from one of system initialization scripts (/etc/rc* or /etc/init.d/*).

• If a daemon has a configuration file, it is read only on start-up.– To reload any of the configuration changes, daemons will catch SIGHUP

and re-read configuration files when they receive the signal.

© 2009 Wipro Ltd - Confidential104 © 2009 Wipro Ltd - Confidential104

References / Further Reading

• Advanced Programming in the UNIX Environment (2nd Edition) è by W. Richard Stevens, Stephen A. Rago

• Unix Programming Environmentè by Brian W. Kernighan, Rob Pike

• Advanced UNIX Programming (2nd Edition) è by Marc J. Rochkind• Design of the UNIX Operating Systemè by Maurice J. Bach

© 2009 Wipro Ltd - Confidential

Unix FCG

Thank You