You are on page 1of 105

Unix Processes

Version 1.2

Unix FCG

2009 Wipro Ltd - Confidential

Agenda
1 Process Environment
2 Process Control
3 Process Relationships
4 Signals
5 Daemon Processes

2009 Wipro Ltd - Confidential

Process Environment

2009 Wipro Ltd - Confidential

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 - Confidential

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 - Confidential

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 - Confidential

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 - Confidential

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 - Confidential

Orphan & Zombie Processes

Orphaned process
Parent dies before child exits.
Child process is adopted by init.
Childs 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 - Confidential

Process States

Common Process States


Process
State
R
S
D
T
Z

10

Description
Process is running or scheduled to run (runnable ) and is on the run queue.
Process is in an interruptible sleep state (waiting for an event to complete).
Process is in an uninterruptible sleep (usually IO).
Process has been stopped (either by a job control signal or because it is
being traced).
Zombie (or defunct) process, terminated but not reaped by its parent.

2009 Wipro Ltd - Confidential

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 notnice as 0.

11

2009 Wipro Ltd - Confidential

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.
12

2009 Wipro Ltd - Confidential

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.

13

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 - Confidential

Process Start-up

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.

14

2009 Wipro Ltd - Confidential

Process Termination

8 ways:
Normal termination:
1.
2.
3.
4.
5.

Return from main


Calling exit
Calling _exit or _Exit
Return of the last thread from its start routine
Calling pthread_exit from the last thread

Abnormal termination:
6. Calling abort
7. Receipt of a signal
8. 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.

15

2009 Wipro Ltd - Confidential

Process Life Cycle

16

2009 Wipro Ltd - Confidential

atexit Example
static 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);
}
17

2009 Wipro Ltd - Confidential

atexit Example
$ ./a.out
main is done
first exit handler
first exit handler
second exit handler
$ ./a.out n
main is done
$

18

2009 Wipro Ltd - Confidential

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.

19

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 - Confidential

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.

20

2009 Wipro Ltd - Confidential

Typical Memory Arrangement


High address

Command-line arguments & environment variables


Stack

Heap
Uninitialized Data
(BSS)
Initialized Data
(read-write)
Initialized Data
(read-only)
Low address

21

Initialized to zero by exec

Read from the program file by exec

Text

2009 Wipro Ltd - Confidential

Dynamic Memory Management

void
void
void
void

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

Usually implemented with the sbrk system call.


Expands or contracts the heap of the process.

22

2009 Wipro Ltd - Confidential

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.

23

2009 Wipro Ltd - Confidential

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?

24

2009 Wipro Ltd - Confidential

Process Control

25

2009 Wipro Ltd - Confidential

Process Identifiers

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

26

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
pid_t
uid_t
uid_t
gid_t
gid_t

getpid(void)
getppid(void)
getuid(void)
geteuid(void)
getgid(void)
getegid(void)
2009 Wipro Ltd - Confidential

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 parents data space, heap, and stack.
They share the text segment.
Modern implementations dont 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.

27

2009 Wipro Ltd - Confidential

fork Example
int
char

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

int main(void)
{
int
var = 88;
pid_t
pid;

/* automatic variable on the stack */

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);
}
28

2009 Wipro Ltd - Confidential

fork Example
$ ./a.out
a write to stdout
before fork
pid = 430, glob = 7,
pid = 429, glob = 6,
$ ./a.out > temp.out
$ cat temp.out
a write to stdout
before fork
pid = 432, glob = 7,
before fork
pid = 431, glob = 6,

var = 89
var = 88

child's variables were changed


parent's copy was not changed

var = 89
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.

29

2009 Wipro Ltd - Confidential

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 parents 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.

30

2009 Wipro Ltd - Confidential

fork Example
/* fork.c -- Using multiple forks */
int main()
{
fork();
fork();
fork();
fork();
printf("Hello World\n");
return 0;
}
$ ./fork
Hello World
Hello World
. . . repeated 16 times
Hello World

31

2009 Wipro Ltd - Confidential

fork Example
fork
fork
fork
fork
printf
fork
fork
fork
printf
fork
fork
printf

fork
printf

fork
printf

fork
fork
fork
printf
fork
fork
printf

fork
printf

fork
printf

fork
fork
printf

fork
printf

fork
printf

fork
fork
printf

fork
printf

fork
printf

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

32

2009 Wipro Ltd - Confidential

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
parents 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.

33

2009 Wipro Ltd - Confidential

fork File Sharing

34

2009 Wipro Ltd - Confidential

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 doesnt need. Child does the
same thing.
This way, neither interferes with others open descriptors.
Often done in network servers.

35

2009 Wipro Ltd - Confidential

fork Inherited Attributes

36

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 - Confidential

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 doesnt change

37

Childs 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 - Confidential

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.

38

2009 Wipro Ltd - Confidential

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.

39

2009 Wipro Ltd - Confidential

Process Termination

What happens if child terminates before parent?


If child disappears completely, parent wont be able to fetch childs
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 init

terminates?
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.

40

2009 Wipro Ltd - Confidential

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 doesnt 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.

41

2009 Wipro Ltd - Confidential

Process Termination Status


Macros to examine termination status returned by wait & waitpid.
Macro
WIFEXITED(status)

Description
True if status was returned for a
child that terminated normally.

WIFSIGNALED(status)

True if status was returned for a


WTERMSIG(status)
child that terminated abnormally, by to fetch the signal
receipt of a signal that it didn't catch. number that caused the
termination.
True if status was returned for a
WSTOPSIG(status)
child that is currently stopped.
to fetch the signal
number that caused the
child to stop.
True if status was returned for a
child that has been continued after a
job control stop.

WIFSTOPPED(status)

WIFCONTINUED(status)

42

2009 Wipro Ltd - Confidential

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

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 childs 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.

43

2009 Wipro Ltd - Confidential

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));
}

44

2009 Wipro Ltd - Confidential

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)
exit(7);

45

/* child */

if (wait(&status) != pid)
err_sys("wait error");
pr_exit(status);

/* wait for child */


/* and print its status */

if ((pid = fork()) < 0)


err_sys("fork error");
else if (pid == 0)
abort();

/* child */
/* generates SIGABRT */

2009 Wipro Ltd - Confidential

Process Termination

Eg: Termination status with multiple children (continued).


if (wait(&status) != pid)
err_sys("wait error");
pr_exit(status);
if ((pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0)
status /= 0;
if (wait(&status) != pid)
err_sys("wait error");
pr_exit(status);
exit(0);

/* wait for child */


/* and print its status */

/* child */
/* divide by 0 generates SIGFPE */
/* wait for child */
/* and print its status */

}
$ ./a.out
normal termination, exit status = 7
abnormal termination, signal number = 6
abnormal termination, signal number = 8

46

2009 Wipro Ltd - Confidential

Waiting For A Specific Process

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


pid argument
pid == -1
pid > 0
pid == 0
pid < -1

47

Behaviour
Waits for any child process. (Equivalent to wait.)
Waits for the child whose process ID equals pid.
Waits for any child whose process group ID equals that of
the calling process.
Waits for any child whose process group ID equals the
absolute value of pid.

2009 Wipro Ltd - Confidential

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;
}

48

2009 Wipro Ltd - Confidential

Zombie Process Example


Exact options might vary across systems.

$ ./mkzombie & ps
[1] 18306
PPID
PID PGID
13644 13700 13700
13700 18306 18306
13700 18307 18307
18306 18308 18306
18306 18309 18306
18306 18310 18306
18306 18311 18306
18306 18312 18306
$ after 5 seconds
$ ps jHT
PPID
PID PGID
13644 13700 13700
13700 18317 18317
[1]+ Done
$

49

jHT
SID
13700
13700
13700
13700
13700
13700
13700
13700

TTY
pts/5
pts/5
pts/5
pts/5
pts/5
pts/5
pts/5
pts/5

SID TTY
13700 pts/5
13700 pts/5

TPGID
18307
18307
18307
18307
18307
18307
18307
18307

STAT
Rs
S
R+
Z
Z
Z
Z
Z

UID
1002
1002
1002
1002
1002
1002
1002
1002

TIME
0:00
0:00
0:00
0:00
0:00
0:00
0:00
0:00

TPGID STAT
18317 Ss
18317 R+
./mkzombie

UID
1002
1002

TIME COMMAND
0:00 -bash
0:00 ps jHT

2009 Wipro Ltd - Confidential

COMMAND
-bash
./mkzombie
ps jHT
[mkzombie]
[mkzombie]
[mkzombie]
[mkzombie]
[mkzombie]

<defunct>
<defunct>
<defunct>
<defunct>
<defunct>

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;
}

50

2009 Wipro Ltd - Confidential

Zombie Process Example


Exact options might vary across systems.

$ ./mkorphan & ps
[1] 18463
PPID
PID PGID
13644 13700 13700
13700 18463 18463
13700 18464 18464
1 18465 18463
1 18466 18463
1 18467 18463
1 18468 18463
1 18469 18463
[1]+ Done
$ after ~5 seconds
$ ps jHT
PPID
PID PGID
13644 13700 13700
13700 18476 18476
$

51

jHT
SID
13700
13700
13700
13700
13700
13700
13700
13700

TTY
pts/5
pts/5
pts/5
pts/5
pts/5
pts/5
pts/5
pts/5

TPGID STAT
18464 Rs
18464 Z
18464 R+
18464 S
18464 S
18464 S
18464 S
18464 S
./mkorphan

UID
1002
1002
1002
1002
1002
1002
1002
1002

TIME
0:00
0:00
0:00
0:00
0:00
0:00
0:00
0:00

SID TTY
13700 pts/5
13700 pts/5

TPGID STAT
18476 Ss
18476 R+

UID
1002
1002

TIME COMMAND
0:00 -bash
0:00 ps jHT

2009 Wipro Ltd - Confidential

COMMAND
-bash
[mkorphan] <defunct>
ps jHT
./mkorphan
./mkorphan
./mkorphan
A very
./mkorphan
transient
./mkorphan
state.

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.

52

2009 Wipro Ltd - Confidential

Process Life Cycle date

exit status

PID 300
PPID 200
_______________
sh

PID 400
PPID 300
_______________
sh

Zombie

exit()

53

fork()

PID 400
PPID 300
_______________
date
2009 Wipro Ltd - Confidential

exec()

exec Functions

54

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 - Confidential

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.

55

2009 Wipro Ltd - Confidential

exec Functions Inherited Properties

56

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 - Confidential

exec Example
int 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.out
harry
$
57

2009 Wipro Ltd - Confidential

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.

58

2009 Wipro Ltd - Confidential

Process Relationships

59

2009 Wipro Ltd - Confidential

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.

60

2009 Wipro Ltd - Confidential

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.

61

2009 Wipro Ltd - Confidential

Sessions

A session is a collection of one or more process groups.


Eg:
$ proc1 | proc2 &
$ proc3 | proc4 | proc5

62

2009 Wipro Ltd - Confidential

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.

63

2009 Wipro Ltd - Confidential

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;
}
$ ./setsid
parent=29512, child=29513
pid=29513, sid=29513, pgid=29513
64

2009 Wipro Ltd - Confidential

Signals

65

2009 Wipro Ltd - Confidential

Introduction

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:
Signal
SIGHUP
SIGINT
SIGKILL
SIGSEGV
SIGTERM

66

Value
1
2
9
11
15

Comment
Hangup detected on controlling terminal or death of controlling process
Interrupt from keyboard
Kill signal
Invalid memory reference
Termination signal

2009 Wipro Ltd - Confidential

Signal Generation

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.

67

2009 Wipro Ltd - Confidential

Handling Signals

To a process, signals seemingly appear to be random.


So it cant 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.

68

2009 Wipro Ltd - Confidential

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);
}
It is possible to use the same signal
handler for handling multiple signals.
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 */
}

69

2009 Wipro Ltd - Confidential

Handling Signals
Behaviour from command line:
$ ./a.out &
[1]
7216
$ kill -USR1 7216
received SIGUSR1
$ kill -USR1 7216
received SIGUSR1
$ kill -USR1 7216
received SIGUSR1
$ kill -USR2 7216
received SIGUSR2
$ kill 7216
[1]+ Terminated

start process in background


job-control shell prints job number & Process ID
send it SIGUSR1
send it SIGUSR1 again
send it SIGUSR1 one last time
send it SIGUSR2
now send it SIGTERM
./a.out

When a process calls fork, child inherits parents signal dispositions.


So address of a signal-catching function has meaning in the child.

70

2009 Wipro Ltd - Confidential

Signal Terminology

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 kill
function.

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.

71

2009 Wipro Ltd - Confidential

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.

72

2009 Wipro Ltd - Confidential

Signal Generation kill and raise

int kill(pid_t pid, int signo)


Sends a signal to a process or a group of processes.
pid
> 0
== 0

Behaviour
Signal is sent to the process whose process ID is pid.
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.

int raise(int signo)


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

73

2009 Wipro Ltd - Confidential

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.

74

2009 Wipro Ltd - Confidential

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 signals 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.

75

2009 Wipro Ltd - Confidential

alarm & pause Example


static 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.out
Timeout in 5 seconds
Caught SIGALRM
$

76

2009 Wipro Ltd - Confidential

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.

77

2009 Wipro Ltd - Confidential

Signal Set Operations Example


int main()
{
sigset_t sigset1, sigset2;
sigemptyset(&sigset1);
sigaddset(&sigset1, SIGINT);
sigaddset(&sigset1, SIGPIPE);

/* Initialize as empty */
/* Add SIGINT to set */
/* Add SIGPIPE to set */

sigfillset(&sigset2);
sigdelset(&sigset2, SIGINT);

/* Initialize with all sigs */


/* 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");

78

2009 Wipro Ltd - Confidential

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.out
sigset1 has SIGINT
sigset1 doesn't have SIGTERM
sigset2 doesn't have SIGINT
sigset2 has SIGTERM

79

2009 Wipro Ltd - Confidential

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.

80

2009 Wipro Ltd - Confidential

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.
Description
how
SIG_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.

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.

81

2009 Wipro Ltd - Confidential

Signal Mask Operations Example


/* Example showing how to block signals SIGINT & SIGPIPE from being received */
sigset_t set_block;
sigset_t set_save;

/* Signals to block */
/* Saved signal mask */

sigemptyset(&set_block);
sigaddset(&set_block, SIGINT);
sigaddset(&set_block, SIGPIPE);
sigprocmask(SIG_BLOCK, &set_block, &set_save);

/*
/*
/*
/*

Clear set */
Add SIGINT */
Add SIGPIPE */
Block signals */

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


sigprocmask(SIG_SETMASK, &set_save, 0);

82

2009 Wipro Ltd - Confidential

/* Restore mask */

Pending Signals

83

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 - Confidential

Signal Mask/Set/Pending Example


static void sig_quit(int signo)
{
printf("caught SIGQUIT\n");
if (signal(SIGQUIT, SIG_DFL) == SIG_ERR)
printf("can't reset SIGQUIT");
}
Beware: changing the order of sigemptyset
and sigaddset is a common bug.
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");

84

2009 Wipro Ltd - Confidential

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);
exit(0);

/* SIGQUIT here will terminate with core file */

}
$ ./a.out
^\
SIGQUIT pending
caught SIGQUIT
SIGQUIT unblocked
^\Quit(coredump)
$
85

generate signal once (before 5 seconds are up)


after return from sleep
in signal handler
after return from sigprocmask
generate signal again; printed by shell

2009 Wipro Ltd - Confidential

Signal Mask/Set/Pending Example


$ ./a.out
^\^\^\
SIGQUIT pending
caught SIGQUIT
SIGQUIT unblocked
^\Quit(coredump)
$

generate signal 3 times (before 5 seconds are up)


after return from sleep
in signal handler; signal is generated only once
after return from sigprocmask
generate signal again; printed by shell

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 its unblocked.
Signals are not queued.
The message Quit(coredump) is printed by the shell when it sees that its
child terminated abnormally.

86

2009 Wipro Ltd - Confidential

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.
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 */

};

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.
87

2009 Wipro Ltd - Confidential

Signal Action Example


static 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);
}
88

2009 Wipro Ltd - Confidential

Signal Action Example


int 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);
get_handler_status(SIGINT);
return 0;

/* Restore old action */


/* Verify old action */

89

2009 Wipro Ltd - Confidential

Signal Action Example


$ ./a.out
SIG_DFL - System default
sa_handler=0x4006dc
Waiting 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
$

90

2009 Wipro Ltd - Confidential

Unblocking Pending Signals

91

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 - Confidential

sigsuspend Example
sigset_t pending;
sigset_t notpipe;

/* Pending signal set */


/* All but SIGPIPE */

sigfillset(&notpipe);
sigdelset(&notpipe, SIGPIPE);

/* Set to all signals */


/* Remove SIGPIPE */

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

92

2009 Wipro Ltd - Confidential

sigsuspend Example
static 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);
93

2009 Wipro Ltd - Confidential

sigsuspend Example
sigfillset(&sigs);
sigdelset(&sigs, SIGINT);
sigdelset(&sigs, SIGALRM);
printf("You have 10 seconds to SIGINT:\n");
alarm(10);
sigsuspend(&sigs);

/* Timeout in 10 seconds */
/* Wait for SIGINT or SIGALRM */

printf("Done\n");
return 0;
}
$ ./a.out
You have 10 seconds to SIGINT:
CAUGHT SIGALRM
Done
$ ./a.out
You have 10 seconds to SIGINT:
CAUGHT SIGINT
Done
$
94

Let the timer expire by not issuing a


keyboard interrupt.

Before the timer expires, issue a keyboard


interrupt.

2009 Wipro Ltd - Confidential

Job-Control Signals

Usually 6.
SIGCHLD
SIGCONT
SIGSTOP
SIGTSTP
SIGTTIN
SIGTTOU

95

Child process has stopped or terminated.


Continue process, if stopped.
Stop signal (can't be caught or ignored).
Interactive stop signal.
Read from controlling terminal by member of a background process group.
Write to controlling terminal by member of a background process group.

2009 Wipro Ltd - Confidential

Daemon Processes

96

2009 Wipro Ltd - Confidential

Daemon Characteristics

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.

Dont have a controlling terminal; so they run in the background.


Typical output from ps command:
PPID
1
1
1
1
1
1
1
1

97

PID
3809
3866
3882
3884
3900
3931
3956
3975

PGID
3809
3866
3882
3884
3899
3931
3956
3975

SID
3809
3866
3882
3884
3899
3931
3956
3975

TTY
?
?
?
?
?
?
?
?

TPGID
-1
-1
-1
-1
-1
-1
-1
-1

STAT
Ss
Ss
Ss
Ss
S
Ss
Ss
Ss

UID
101
0
0
0
0
1
0
0

2009 Wipro Ltd - Confidential

TIME
0:02
0:00
0:11
0:00
0:00
0:00
0:02
0:13

COMMAND
/sbin/syslogd
/usr/sbin/sshd
/usr/sbin/nmbd -D
/usr/sbin/smbd -D
/usr/sbin/vsftpd
/usr/sbin/atd
/usr/sbin/cron
/usr/sbin/apache2

Coding Rules
1. Call umask to set file mode creation mask to 0.
Mask thats 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:

98

Becomes a session leader of a new session.


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

2009 Wipro Ltd - Confidential

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.

99

2009 Wipro Ltd - Confidential

Daemon Coding Rules Example


void 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();

100

2009 Wipro Ltd - Confidential

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);
101

2009 Wipro Ltd - Confidential

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);
}
}

102

2009 Wipro Ltd - Confidential

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.

103

2009 Wipro Ltd - Confidential

References / Further Reading

104

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

Thank You
Unix FCG

2009 Wipro Ltd - Confidential

You might also like