0% found this document useful (0 votes)
41 views

UnixCG Process Programming

The document discusses Unix process control concepts including process environment, memory layout, creating processes using fork(), process exit handling, waiting for child processes, and executing a new program using exec(). It provides code examples and questions to modify and explore the concepts. The key points are that fork() creates a new process while sharing memory with the parent, exec() loads a new program replacing the current process memory, and wait/waitpid() are used by the parent to retrieve the termination status of child processes.

Uploaded by

Anuj Kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
41 views

UnixCG Process Programming

The document discusses Unix process control concepts including process environment, memory layout, creating processes using fork(), process exit handling, waiting for child processes, and executing a new program using exec(). It provides code examples and questions to modify and explore the concepts. The key points are that fork() creates a new process while sharing memory with the parent, exec() loads a new program replacing the current process memory, and wait/waitpid() are used by the parent to retrieve the termination status of child processes.

Uploaded by

Anuj Kumar
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

Unix Process Control - Programming

By
Unix FCG

Version: 1.0
Date: Feb 2008
Index

• Process Environment
• Process memory layout
• Create a process
• Process exit
• Wait for child
• Exec a new program
• What are signals ?
• Generation of signals
• Disposition of signals
• Lifecycle of a signal
• Signal Handling using POSIX API
• Signals and re-entrancy

Wipro confidential 2
Process Environment

Simple C Program ( a.out )


• When a program is executed, the kernel does
#include <stdio.h> an exec of the program ( a.out )

extern char **environ;


• The kernel invokes a special startup routine
which setups the commands line arguments
int main( int argc, char *argv[] ) for the process
{ • argc: No of program arguments,
printf( “Hello World\n” ); • argv[0], argv[1] etc contain the values of the
printf( “Argument no 1 is %s\n”, argv[1] );
program arguments. argv[0] is the program
printf( “Environment settings: %s\n%s\n”,
environ[0], environ[1] ); name itself
exit(1) • Program terminates upon call to exit(),
} return() or from returning from main()
$./a.out Hello • Using char **environ, the environment
Hello World variables can be accessed
a.out Hello
HOME=/home/user1
PATH=/usr/bin:/bin:.
$

When you run the reference program with an argument of “*” i.e a.out *, what is the value
of argc, argv ?

Wipro confidential 3
Process Memory layout

#include <stdio.h> • Program code is stored in the “text” segment


• Initialised global data is part of the “data”
int g_data1 = 100;
segment eg. g_data1
int g_data2;
• Uninitialized global data is part of the “bss”
int main( int argc, char *argv[] ) segment eg. g_data2
{
int count;
• Automatic variables are stored on the stack eg.
char *p_string; Count
p_string = ( char * )malloc(1024); • Also stored in the stack is information about the
printf( “Hello World\n” ); caller’s environment whenever a function is
}
called, this is restored when the called function
$size a.out terminates
text data bss dec hex filename • Dynamically allocated data is stored in the heap
702 256 4 966 3c6 a.out
eg. p_string
• Using the ‘size” command, the size of the text,
data and bss segments may be determined

Why does the size command not show the size of heap and stack ?
Explore the objdump utility for its usefulness

Wipro confidential 4
Create a process…fork

Process creation example


#include <stdio.h>
• A new process can be created using the fork()
system call
int main( ) • fork() returns twice
{ • Returns 0 in the child, returns the child process
int pid; id in the parent
pid = fork();
if( pid == 0 ) • Newly created process is called child process
{ • Child shares the parent’s text segment
printf( “Inside child\n” );
…. • Child gets a copy( does not share ) of the
} parent’s data, heap and stack segments
else
{
printf( “Inside parent\n” )
….
}
}

Modify the reference program given here to print the process ids within the child and parent processes.

Also print the parent process id in the child and vice-versa.

Add global, local variables( before and after fork() ) to the program. Change the values of these variables in
the child, see how it affects the value in the parent’s copy of these variables

Wipro confidential 5
Process exit

• A process exits normally by calling exit(), return() or returning from main


• The value returned at exit is the process exit status
• A process exits abnormally by calling abort() or when it receives certain signals
( eg. SIGTERM )
• Kernel, at exit, closes all open file descriptors, releases memory used by process
• The parent process must be notified of the child’s exit status
• Kernel sends a SIGCHLD to the parent to handle the termination status of the child
• If the parent process dies before handling the child’s termination status, the child
becomes an orphan process. Init process takes over as the parent and handles the
termination status
• If the child terminates before the parent has handled its termination status, the
child process becomes a zombie

-Modify the reference example given in the previous slide, create orphan and zombie
processes by killing them from the command line . Observe the process status in the ps
command output
- Can a process inherited by init become a zombie ?

Explore the use of atexit() to register exit handlers and see how they are called at process
exit.

Wipro confidential 6
Wait for child

Wait - example
• A parent process may use wait() or waitpid()
#include <stdio.h>
to wait for its children’s termination status
• Upon child process termination, wait returns
int main( ) with the exit status of the child process
{
• wait() blocks till any one of the children
int pid, status;
pid = fork();
terminate
if( pid == 0 ) • waitpid() has a non-blocking option, can be
{ used to wait on a particular process id
sleep(2); • Parent can examine the child process
exit(0);
}
termination status
else • Parent can register for SIGCHLD and call
{ wait() in the context of the signal handler
if( wait( &status ) == pid )
printf( “Child exited\n” );
}
}

- Modify the example code to call wait() in the context of the SIGCHLD handler. Register for the signal by
calling signal( SIGCHLD, sig_handler ), where sig_handler is the signal handler function
- Use waitpid in non-blocking mode, wait for specific child process ids;

Wipro confidential 7
Wait – more!

Try these !

In the previous example,

- What happens to the parent process if SIGCHLD is not handled ?

- What happens to the parent and child process if the SIGCHLD is ignored explicitly
- i.e signal( SIGCHLD, SIG_IGN )

-Fork multiple children, wait on all children. Observe status of children not “waited”
upon

- We do not want the parent process to “wait”. We do not want them to become
zombies either. How do we accomplish this ? [ Clue: Init does not have its children
as zombies ]

Wipro confidential 8
Exec a new program

Process creation example with fork and


exec
• Using exec() after a fork() allows a new
// This program spawns a new program program( executable) to be executed
which runs the executable a1 • Process ID of child does not change after a fork

#include <stdio.h> • Child runs with the data, heap and stack
segments of the new executable
int main( ) • Different exec variants available – execl,
{
int pid;
execv, execle,execve, execlp, execvp
pid = fork(); • Differ in manner program arguments and
if( pid == 0 ) environment variables are passed to the child
{
printf( “Inside child\n” );
execlp( “/home/user1/a1”, “a1”,
“arg1”, “arg2”, (char *)0 ); Write you own program “a1” that prints the command
} line argument and environment variables. Run the
else example program given here and observe the output
{
printf( “Inside parent\n” )
wait ( &status );
}
}

Wipro confidential 9
What are signals ?

• Signals are software interrupts

• Signals are asynchronous events generated by the operating


system in response to certain conditions

• Every signal has a name starting SIGxxxx eg. SIGALRM


• All signals are defined in /usr/include/signal.h

• The OS supports a standard set of signals


• Eg Linux has 31 signals

• Provides support for additional application defined signals real-


time extensions

Wipro confidential 10
How are signals generated ?

• Terminal generated signals, when certain keys are pressed


• Ctrl-C key generates SIGINT

• When certain hardware exceptions occur


• Divide by 0(SIGFPE), invalid memory reference(SIGSEGV) etc.
• Exception detected by h/w, kernel is notified, kernel generates the signal and
sends it to the process

• Kill command to send signal to a process

• Kill function to send signal from one process to another

• When certain software conditions occur


• SIGPIPE, when there is a write to a pipe with no reader
• SIGALRM, when a software timer expires

Wipro confidential 11
Some signals….

 SIGKILL and SIGSTOP cannot be caught/ignored by the


process
• Can you think of why this is so ?
 SIGCHLD sent by child process to parent process
• Parent calls waitpid to receive the child’s process ID and
termination status…again why is this required ?
 SIGALRM handling
• Generated when a timer set by alarm() or settimer() expires
 SIGSEGV
• Generated by kernel when software makes an invalid memory
reference
 SIGSTOP and SIGCONT
• Job control signals, to stop and resume a stopped process

Read you man pages about the other signals supported.

Wipro confidential 12
Basic disposition of signal

Sample signal handler Disposition of signal is the action


associated with a signal
#include <stdio.h>

void sig_handler( int ); • Ignore the signal


• SIGKILL and SIGSTOP cannot be
main( )
ignored
{
if( signal( SIGINT, sig_handler) < 0 ) • If certain signals are ignored( such as
printf( “Error: cannot catch SIGINT\n” ); hardware exceptions), behaviour is
if( signal( SIGUSR1, SIG_IGN ) < 0 ) undefined
printf( “Error: cannot ignore SIGUSR1 ); • Catch the signal
while(1);
• Kernel invokes the signal handler
}
function defined in the program
void sig_handler( int signo ) • Else, default action applies, which is
{ one of
if( signo == SIGINT )
• Terminate process and may generate
printf( “SIGINT received\n” );
}
core
• Ignore signal
• Stop process

Run the example program, send SIGINT, SIGUSR1 from command line, observe result.

Wipro confidential 13
Disposition of signal… try this

Try the following exercises:

Using the example program given in the previous slide, send these signals more than
once and observe the result.

Send a different signal that is not handled, observe the default behaviour.

Use alarm() to implement a timer, handle the SIGALRM generated

Fork a child process after the signal() call. Send the signals from the command line and
observe the behaviour in the parent and child

Wipro confidential 14
Lifecycle of a signal

During its lifetime, signal may be in one of the following states


• Generated - When the event that causes the signal occurs

• Delivered - Action for signal is taken


• Process ignores the signal
• Default or specific signal handler invoked

• Pending – For the duration between generation and delivery

• Blocking – If the process chooses to block delivery of the signal

• Queued – If multiple signals are blocked or pending delivery to the


process

Wipro confidential 15
Signal handling using POSIX API

Signal handling using POSIX API • Process can block a set of signals
#include <stdio.h>
from being delivered to it
• Using sigprocmask() API
main( )
{ • Operates on a set of signals
// Register signal handler represented by sigset_t
if( signal( SIGUSR1, sig_handler ) < 0 )
printf( “Error: cannot catch SIGUSR1\n” ); • Process can see the set of signals
// Setup the signal mask that are blocked and pending
sigset_t mask, pendmask;
sigemptyset( &mask );
delivery
sigaddset( &mask, SIGUSR1 ); • sigpending()
sigprocmask( SIG_BLOCK, &mask, 0 );

sleep(5);
• APIs to manipulate signal sets
if( sigpending( &pendmask ) < 0 ) • sigemptyset(), sigfillset(),
printf( “Error in pending mask );
sigismember() etc
if( sigismember( &pendmask, SIGUSR1 ) )
printf( “SIGUSR1 pending\n” );
} Run the example program, send SIGUSR1 from
command line, observe result.
void sig_handler( int signo ) Modify the program to unblock SIGUSR1 and see if
{
the signal handler is invoked.
……………………..
} In this case, observe what happens is there is no
signal handler defined?
What happens if someother signal is sent to the
process?
Wipro confidential 16
Signal handling using POSIX API…sigaction()

Signal handling using POSIX API


• Process can
#include <stdio.h> define/modify/examine action
associated with a signal
main( )
{
• sigaction() API
struct sigaction act; • Associate signal handler for a
particular signal
// Register signal handler
act.sa_handler = sig_handler; • Allows definition of set of signals to
sigemptyset( &act.sa_mask ); be blocked on occurrence of signal,
act.sa_flags = 0; including itself
if( sigaction( SIGUSR1, &act, NULL ) < 0 )
• Signals are unblocked after the
printf( “Error: cannot catch SIGINT\n” ); signal handler is executed
• Signal handler is installed till it is
while(1);
}
explicitly changed

void sig_handler( int signo ) Run the example program, send SIGUSR1 from
{ command line, observe result.
printf( “SIGUSR1 received\n” ); Explore the different sigaction flags and try out sample
} programs with them

Wipro confidential 17
Signals and re-entrancy

 What are non-reentrant functions ?


• They use static data structures
• They use malloc/free
• Typical implementations of malloc maintain linked lists of allocated
area and this is manipulated from within the call…
• They use standard library functions
• Typically uses global data structures in a non-reentrant way
• They may call other non-reentrant functions
 Only reentrant functions can be invoked from within signal
handlers
• Ensures no loss of data or data corruption

Wipro confidential 18
Thank you.

Information contained and transmitted by this presentation is proprietary to Wipro Limited and is intended for use only by the individual or entity to which it is addressed,
and contains information that is privileged, confidential or exempt from disclosure under applicable law.

Wipro confidential 19

You might also like