Process
•
A process is the execution of a program
•
A process is consists of
text
(machine code),
data
and
stack
•
Many process can run simultaneously as
kernel schedules them for execution
•
Several processes may be instances of one
program
•
A process reads and writes its data and stack
sections, but it cannot read or write the data
and stack of other processes
•
Kernel has a
process table
that keeps
tract of all active processes
•
Each entry in the process table
contains pointers to the text, data,
stack and the U Area of a process.
•
All processes in UNIX system, except
the very first process (process 0)
Kernel Support for Process
UNIX Process Data Structure
Text
Stack Data
File Descriptor Table
Per Process Region Table Kernel
Process Table
Kernel Region Table A Process
• When a process is created by fork, it contains
duplicated copies of text, data & stack segment of its parent.
• Also it has a file descriptor table that contains references to opened file by its parent.
• Along with this, process is assigned following
attributes which are inherited by parent or set by kernel.
Real User Identification Number (rUID)
Real Group Identification Number (rGID)
Effective User Identification Number (eUID)
Effective Group Identification Number (eGID)
Process Group Identification Number (PGID)
Current Directory
• In addition to these attributes are different between parent & child processes
Process Identification Number (PID)
Parent Process Identification Number (PPID)
Process APIs
fork, vfork
• The fork system call is used to create a child
process. The function prototype is
#include <sys/types.h> pid_t fork( void );
• The call succeeds. A child process is created and
the function returns child process ID to the parent. The child process receives a zero return value from fork.
• The call fails. No child process is created and
function sets errno with error code & returns -1.
• The common errors are ENOMEM (Insufficient
#include <iostream.h> #include <stdio.h>
#include <unistd.h> int main()
{
pid_t child_pid;
cout<<“PID:”<<getpid()<<“, Parent:”<<getppid(); switch(child_pid=fork()) {
case (pid_t)-1 : perror(“Fork”); break;
case (pid_t)0 : cout<<“Child Created: PID” <<getpid()<<“Parent:”<<getppid()<<endl; exit(0);
default : cout<<“Parent after fork. PID :”<<getpid() <<“Child PID: “ <<child_pid<<endl;
}
• An alternative API is vfork with same prototype
#include <sys/types.h> pid_t vfork( void );
• The vfork() function is the same
as fork() except that it does not make a copy of the address space.
• The memory is shared reducing the overhead of
spawning a new process with a unique copy of all the memory.
• This is typically used when
using fork() to exec() a process and terminate.
• The vfork() function also executes the child
_exit
•
The _exit system call terminates a process.
•
This API will cause calling process data segment,
stack segment and U area to be deallocated and
all open file descriptors to be closed.
•
The process table slot entry for this process is
still intact so that the process exit status and its
execution status are recorded therein.
•
The process is now called
zombie process
, as it
can no longer scheduled to run.
•
A
zombie process
or
defunct process
is
•
An
orphan process
is a computer
process whose parent process has
finished or terminated, though it
remains running itself.
•
The data stored in process table
entry can be retrieved by the parent
process using wait or waitpid system
call.
#include<unistd.h>
wait, waitpid
•
The parent process will often want to wait
until all child processes have been
completed/terminated.
•
This can be implemented with the wait()
waitpid() function call.
•
These call will deallocate Process Table
slot of the child process. The prototypes
are
#include<sys/wait.h>
pid_t wait (int *status_p);
•
wait
: Blocks calling process until a signal is
sent to the process or the child process
terminates or is stopped. If child process has
already terminated, the wait call returns
immediately.
•
If the calling process has multiple child
processes, the function returns when one
returns.
•
waitpid
: this is more general than wait.
•
Options available to block calling process for a
particular child process not the first one by
•
If pid is equal to -1, status is requested for
any child process. In this
respect, waitpid() is equivalent to wait().
•
If pid is greater than 0, it specifies the
process ID of a single child process for which
status is requested.
•
If pid is 0, status is requested for any child
process whose process group ID is equal to
that of the calling process.
•
If pid is less than -1, status is requested for
• status_p specifies the location to which the child process' exit status is stored. If NULL is passed, no exit status is returned. Otherwise, the following
macros defined in <sys/wait.h> can be used to evaluate the returned status:
• WIFEXITED(status_p) : Returns a nonzero value if child was terminated via _exit otherwise zero.
• WEXITSTATUS(status_p) Returns a child exit code that was assigned to an _exit call
• WIFSIGNALED(status_p) Returns a nonzero value if a child was terminated due to signal interruption. • WTERMSIG(status_p) If the value
of WIFSIGNALED(s) is non-zero, this macro
• WIFSTOPPED(status_p) Evaluates to a non-zero
value if status was returned for a child process that is currently stopped.
• WSTOPSIG(status_p) If the value
of WIFSTOPPED(s) is non-zero, this macro evaluates to the number of the signal that caused the child
process to stop.
• options is the bitwise OR of zero or more of the following flags, defined in <sys/wait.h>:
• WNOHANG The waitpid() function does not suspend execution of the calling thread if status is not
immediately available for one of the child processes specified by pid.
• WNOTRACED The status of any child processes
RETURN VALUES
• If waitpid() was invoked with WNOHANG set
in options, and there are children specified by pid for which status is not available, waitpid() returns 0.
• If WNOHANG was not set, waitpid() returns the
process ID of a child when the status of that child is available.
• Otherwise, it returns -1 and sets errno to one of the
following values:
– ECHILD The process or process group specified
by pid does not exist or is not a child of the calling process.
– EFAULT stat_loc is not a writable address.
– EINTR The function was interrupted by a signal. The
value of the location pointed to by stat_loc is undefined.
exec
• The exec family of functions will change calling
process context and initiate a program from within a program.
• There are six versions of exec system call. They have same function but they differ from each other in their argument.
• The exec family of functions creates a new process image from a regular, executable file. This file is
either an executable object file, or an interpreter script.
• There is no return from a successful call to an exec() function, because the calling process is functionally replaced by the new process.
•
The prototypes of exec functions are
#include <unistd.h>
int execl(const char *
path
, const char*
arg
,
...);
int execlp(const char *
file
, const char*
arg
,
…);
int execle(const char *
path
, const char
*
arg
, …, const char**
env
);
int execv(const char *
path
, const
char**
argv,…
);
int execvp(const char *
file
, const
char**
argv
, …);
int execve(const char *
path
, const char**
•
The first argument to the function is
either path name or file name of a
program to be executed, this should be
an executable file or shell script(excelp &
execvp).
•
If call succeeds, the calling process
instruction and data memory are
overloaded with new program instruction
text & data.
•
When a new program completes
execution, the process is terminated &
exit code will be send to its parent
PARAMETERS
• path Specifies the path name of the new process image file.
• file Is used to construct a path name that
identifies the new process image file. If it contains a slash character, the argument is used as the
path name for this file. Otherwise, the path prefix for this file is obtained by a search of the
directories in the environment variable PATH.
• arg0, ..., argn Point to null-terminated
character strings. These strings constitute the
argument list for the new process image. The list is terminated by a NULL pointer.
• The argument arg0 should point to a file name
•
argv is the argument list for the new
process image. This should contain an array
of pointers to character strings, and the
array should be terminated by
a NULL pointer. The value in argv[0]
should point to a file name that is associated
with the process being started by
the exec() function.
•
envp Specifies the environment for the new
process image. This should contain an array
of pointers to character strings, and the
• The const char *arg and subsequent ellipses in the
execl(), execlp(), and execle() functions can be thought of as arg0, arg1, ..., argn.
• Together they describe a list of one or more
pointers to null-terminated strings that represent the argument list available to the executed
program.
• The first argument, by convention, should point to the filename associated with the file being
executed.
• The list of arguments must be terminated by a NULL pointer, and, since these are variadic
functions ( variadic function is a function of
indefinite arity, i.e., one which accepts a variable number of arguments), this pointer must be cast
•
The
execv
(),
execvp
(), and
execvpe
()
functions provide an array of pointers to
null-terminated strings that represent the argument
list available to the new program.
•
The first argument should point to the filename
associated with the file being executed.
•
The array of pointers
must
be terminated by a
NULL pointer.
•
The
execle
() and
execvpe
() functions allow
the caller to specify the environment of the
executed program via the argument
envp
.
•
The
envp
argument is an array of pointers to
#include <unistd.h>
//common to all
programs
main()
{
execl
("/bin/ls", "/bin/ls", "-r", "-t", "-l",
(char *) 0);
// (char *) 0 can be replace with NULL
}
main()
{
char *args[] = {"/bin/ls", "-r", "-t", "-l", (char
*) 0 };
main()
{
execlp
(“ls", “ls", "-r", "-t", "-l", NULL);
}
main()
{
char *const parmList[] = {"/bin/ls", "-l", "/u/
userid/dirname", NULL};
char *const envParms[2] =
{"STEPLIB=SASC.V6.LINKLIB", NULL};
execve
("/u/userid/bin/newShell", parmList,
envParms);
system
•
The system call will execute an OS shell
command as described by a character command
string.
•
This function is implemented using fork, exec
and waitpid.
•
The command string is executed by calling
/bin/sh -c
command-string
.
•
Example
#include <stdio.h>
#include <stdlib.h>
main()
{
system("ls -l");
• Signals are sometimes called “software interrupts”. • Signals are triggered by events and are posted on a
process to notify it that something has happened and requires some action.
• For ex:- divide-by-zero, <Delete> or <Ctrl-C> key, etc.
• A signal is an asynchronous event which is delivered to a process.
• Asynchronous means that the event can occur at any time. The process does not know ahead of time exactly when a signal will occur.
Signal can be sent by one process to another
process (or to itself) or by the kernel to a process.
Signal
SIGALRM Alarm timer time-out. Generated by alarm(
) API. No
SIGABRT Abort process execution. Generated by
abort( ) API. Yes
SIGFPE Illegal mathematical operation. Yes
SIGHUP Controlling terminal hang-up. No
SIGILL Execution of an illegal machine instruction. Yes
SIGINT Process interruption. Can be generated by
<Delete> or <ctrl_C> keys. No
SIGKILL Sure kill a process. Can be generated by
“kill -9 <process_id>” command. Yes
SIGPIPE Illegal write to a pipe. Yes
SIGQUIT Process quit. Generated by <crtl_\> keys. Yes
Signals are defined as integer flags, and the <signal.h>
header depicts the list of signals defined for UNIX.
Signal
SIGSEGV Segmentation fault. generated by
de-referencing a NULL pointer. Yes
SIGTERM process termination. Can be generated by
“kill <process_id>” command. Yes
SIGUSR1 Reserved to be defined by user. No
SIGUSR2 Reserved to be defined by user. No
SIGCHLD Sent to a parent process when its child
process has terminated. No
SIGCONT Resume execution of a stopped process. No
SIGSTOP Stop a process execution. No
SIGTTIN Stop a background process when it tries to
read from from its controlling terminal. No
SIGTSTP Stop a process execution by the control_Z
keys. No
SIGTTOUT
Stop a background process when it tries to
Sources for Generating Signals
*
Hardware
- A process attempts to access
addresses outside its own address space.
- Divides by zero.
*
Kernel
- Notifying the process that an I/O
device for which it has been waiting is available.
*
Other Processes
- A child process
notifying its parent process that it has
terminated.
•
When a signal is sent to a process, it is pending
on the process to handle it.
•
Process that receives a signal can take one of
three action:
* Perform the system-specified default for the signal - notify the parent process that it is terminating; - generate a core file
(a file containing the current memory image of the process)
- terminate.
* Ignore the signal :- A process can do ignoring with all signal but two special signals: SIGSTOP and SIGKILL. * Catch the Signal :- When a process catches a signal,
except SIGSTOP and SIGKILL, it invokes a special signal handing routine.
signal API
• All UNIX systems and ANSI-C support the signal API, which can be used to define the per-signal handling method.
• The prototype of the signal API is
void (*signal(int signo, void(*handler)(int) ) ) (int); • Or in simple format
#include <signal.h>
typedef void sighandler_t(int);
sighandler_t *signal( int signo, sighandler_t *handler );
signal returns a pointer to a function that returns an int (i.e. it returns a pointer to sighandler_t)
• RETURN VALUE :- The signal() function returns
Signal Handling
• Use the signal handling library: signal.h
• Then can use the signal call:
#include <signal.h>
void (*signal( int sig, void (*handler)(int))) (int) ;
• signal returns a pointer to the PREVIOUS signal
handler
• #include <signal.h>
typedef void Sigfunc(int);
Sigfunc *signal( int signo, Sigfunc *handler );
Signal is a function
that takes two
arguments:
sig and handler
The signal to be
caught or ignored
is given as argument
sig
The function to be called
when the specified signal
is received is given as a
pointer to the function
handler
The handler function
Receives a single integer
Argument and returns void
The signal function itself
returns a pointer to a function. The return type is the same
as the function that is passed in,
i.e., a function that takes an
int and returns a void
The returned function
takes a integer
Signal Mask - sigprocmask API
• Each process has a system mask that defines which signals are blocked when generated to a process.
• A blocked signal depends on the recipient process to unblock it and handle it accordingly.
• A process initially inherits the parent’s signal mask when it is created, but any pending signals for the parent process are not passed on.
• A process can query or set its signal mask via
sigprocmask API.
#include<signal.h>
int sigprocmask ( int cmd, cost sigset_t *new_mask,
sigset_t *old_mask);
• new_mask: defines a set of signals to be set or reset
in a calling process signal mask.
new_mask = NULL, current process signal mask unaltered.
• cmd: specifies how the new_mask value is to be used:
- SIG_SETMASK: Overrides the calling process signal mask with the value specified in the new_mask argument.
- SIG_BLOCK: Adds the signals specified in the new_mask argument to the calling process signal mask.
- SIG_UNBLOCK: Removes the signals specified in the new_mask argument from the calling process signal mask
• old_mask: Address of a sigset_t variable that will be
assigned the calling processing’s original signal mask.
The BSD UNIX & POSIX.1 define a set of API known as
sigsetops functions, which set, reset and query the presence of signals in a sigset_t typed variable
* int sigemptyset (sigset_t* sigmask);
Clears all signal flags in the sigmask argument.
* int sigaddset (sigset_t* sigmask, const int signal_num);
Sets the flag corresponding to the signal_num signal in the sigmask argument.
* int sigdelset (sigset_t* sigmask, const int signal_num);
Clears the flag corresponding to the signal_num signal in the sigmask argument.
* int sigfillset(sigset_t* sigmask);
Sets all the signal flags in the sigmask argument.
These functions returns zero if call succeed, -1 if they fails.
* int sigismember(const sigset_t* sigmask,const int signal_num);
This program checks whether the SIGINT signal is present in a process signal mask and adds it to the mask if it is not there. It clears the SIGSEGV signal from the process signal mask.
int main( ){
sigset_t sigmask;
sigemptyset(&sigmask); /*initialize set */ if(sigprocmask(0,0,&sigmask)==-1)
/*get current signal mask*/
{ perror(“sigprocmask”); exit(1); }
else sigaddset(&sigmask, SIGINT); /* set SIGINT flag*/
sigdelset(&sigmask, SIGSEGV); /* clear SIGSEGV flag */
if (sigprocmask(SIG_SETMASK,&sigmask,0) == -1)
sigpending API
•
The sigpending API can find out whether one
or more signals are pending for a process and
set up special signal handing methods for
those signals before the process calls the
sigprocmask API to unblock them.
# Include<signal.h>
int
sigpending
(sigset_t* sigmask);
•
sigmask argument, to the
sigpending
API, is
the address of a sigset_t-type variable and is
assigned the set of signals pending for the
calling process by the API.
•
The API returns 0 on Success; -1 on Failure
/* This program reports whether the SIGTERM
signal is pending for the process. */
int main ( ) {
sigset_t
sigmask;
sigemptyset(&sigmask); /* initialize set */
if (sigpending(&sigmask) == -1)
/* Any signal is pending */
perror(“sigpending”);
else
cout<<”SIGTERM signal is:” <<
(sigismember (&sigmask,SIGTERM) ? “Set” : “No
Set”);
sigaction API
• The sigaction API is a replacement for the signal API in
latest UNIX & POSIX systems.
• The sigaction API setups a signal handling method
for each signal it wants to deal with and passes back the previous signal handling method for a given
signal.
• The sigaction API blocks the signal it is catching
allowing a process to specify additional signals to be blocked when the API is handling a signal.
include<signal.h>
int sigaction ( int signal_num, struct sigaction* action,
struct sigaction* old_action);
• The API returns 0 on Success,
struct sigaction
{
void (*sa_handler) (int);
sigset_t sa_mask;
int sa_flag;
}
•
sa_handler
is the function point of a
user-defined signal handler function, SIG_IGN (ignores
a signal), or SIG_DFL (accepts the default action
of a signal).
•
sa_mask
specifies additional signals that a
process wishes to block when it is handling the
signal_num signal.
The values for sa_flag are as follows
0:when the signal_num is SIGCHLD, the kernel will send the SIGCHLD signal to the calling process whenever its child process is either terminated or stopped.
SA_NOCLDSTOP: when the signal_num is SIGCHLD, the kernel will generate the SIGCHLD signal to the calling process whenever its child process is either terminated, but not when the child process has been stopped.
SA_RESETHAND: If signal_num is caught, the sa_handler is set to SIG_DFL before the signal handler function is called,
and signal_num will not be added to the process signal
mask
SA_RESTART: If a signal is caught while a process is
Arguments of
sigaction
-
sigaction (4)
* signal_num
The signal_num argument designates which signal handling action is defined in the action argument.
* old_action
The previous signal handling method for
signal_num will be returned via the old_action argument if it is not a NULL pointer.
* action
action argument sets up a signal handling method for the signal_num argument.
If the action argument is a NULL pointer, the