Professional Documents
Culture Documents
1.unix Processes
1.unix Processes
Version 1.2
Unix FCG
Agenda
1 Process Environment
2 Process Control
3 Process Relationships
4 Signals
5 Daemon Processes
Process Environment
Process
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.
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.
Process Attributes
Process priority
Process Creation
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.
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.
Child process does not consume CPU resources, only occupies an entry in
process table.
Process States
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.
Process Priority
11
Background jobs
Invoked with & suffix; independent of user input from terminal.
13
Process Start-up
14
Process Termination
8 ways:
Normal termination:
1.
2.
3.
4.
5.
Abnormal termination:
6. Calling abort
7. Receipt of a signal
8. Response of the last thread to a cancellation request
15
16
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
atexit Example
$ ./a.out
main is done
first exit handler
first exit handler
second exit handler
$ ./a.out n
main is done
$
18
name=value strings
PATH=:/bin:/usr/bin
HOME=/home/wipro
19
Text segment
Machine instructions that the CPU executes.
Read-only.
Sharable so that a single copy in memory can be used by programs.
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
Heap
Uninitialized Data
(BSS)
Initialized Data
(read-write)
Initialized Data
(read-only)
Low address
21
Text
void
void
void
void
*malloc(size_t size)
*calloc(size_t nobj, size_t size)
*realloc(void *ptr, size_t newsize)
free(void *ptr)
22
Resource Limits
23
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
Process Control
25
Process Identifiers
PID 1
26
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
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
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;
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
var = 89
var = 88
29
fork Example
[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
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
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
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
34
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.
35
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
37
fork Uses
38
Process Termination
39
Process Termination
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
41
Description
True if status was returned for a
child that terminated normally.
WIFSIGNALED(status)
WIFSTOPPED(status)
WIFCONTINUED(status)
42
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
43
Process Termination
44
Process Termination
45
/* child */
if (wait(&status) != pid)
err_sys("wait error");
pr_exit(status);
/* child */
/* generates SIGABRT */
Process Termination
/* 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
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.
48
$ ./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
COMMAND
-bash
./mkzombie
ps jHT
[mkzombie]
[mkzombie]
[mkzombie]
[mkzombie]
[mkzombie]
<defunct>
<defunct>
<defunct>
<defunct>
<defunct>
50
$ ./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
COMMAND
-bash
[mkorphan] <defunct>
ps jHT
./mkorphan
./mkorphan
./mkorphan
A very
./mkorphan
transient
./mkorphan
state.
exec Functions
52
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
exec Functions
55
56
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
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
Process Relationships
59
Process Groups
60
Process Groups
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
Sessions
62
Sessions
63
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
Signals
65
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.
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
Signal Generation
Hardware exceptions.
Kernel generates appropriate signal for the process.
Eg: Divide by 0, invalid memory reference.
Software conditions.
Eg: SIGPIPE generated when a process writes to a pipe after the reader of
the pipe has terminated.
67
Handling Signals
Possible actions:
Ignore the signal.
SIGKILL and SIGSTOP can never be ignored.
68
Handling Signals
69
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
70
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
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.
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
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.
73
74
75
76
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
/* Initialize as empty */
/* Add SIGINT to set */
/* Add SIGPIPE to set */
sigfillset(&sigset2);
sigdelset(&sigset2, SIGINT);
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
79
Blocking Signals
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
SIG_UNBLOCK
SIG_SETMASK
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
/* 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 */
82
/* Restore mask */
Pending Signals
83
84
}
$ ./a.out
^\
SIGQUIT pending
caught SIGQUIT
SIGQUIT unblocked
^\Quit(coredump)
$
85
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
Signal 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;
89
90
91
sigsuspend Example
sigset_t pending;
sigset_t notpipe;
sigfillset(¬pipe);
sigdelset(¬pipe, SIGPIPE);
sigpending(&pending);
/* Query which signals are pending */
if (sigismember(&pending, SIGPIPE)) /* Is SIGPIPE pending? */
sigsuspend(¬pipe);
/* Yes, allow SIGPIPE to be raised */
92
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
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
Job-Control Signals
Usually 6.
SIGCHLD
SIGCONT
SIGSTOP
SIGTSTP
SIGTTIN
SIGTTOU
95
Daemon Processes
96
Daemon Characteristics
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
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.
98
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.
99
100
102
Daemon Conventions
103
104
Thank You
Unix FCG