[go: up one dir, main page]

0% found this document useful (0 votes)
9 views89 pages

Unit 4a Process Control

Uploaded by

s27681903
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)
9 views89 pages

Unit 4a Process Control

Uploaded by

s27681903
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/ 89

UNIX PROCESSES

MAIN FUNCTION
■ PROTOTYPE:
int main(int argc, char *argv[ ]);

Argc – is the number of command line


arguments
argv [ ] – is an array of pointers to the
arguments
■ A C program is started by a kernel

■ A special start up routine is called before


the main function is called

■ This start up routine takes values from the


kernel and sets things up so that the main
function is called
Process termination

■ Normal termination
* return from main
* calling exit
* calling _exit
■ Abnormal termination
* calling abort
* terminated by a signal
exit and _exit functions

■ _exit returns to kernel immediately


■ exit performs certain cleanup processing
and then returns to kernel
■ PROTOTYPE
#include <stdlib.h>
void _exit (int status)
void exit (int status)
■ The exit status is undefined if

1. Either of these function is called without


an exit status
2. Main does a return without a return value
3. Main “falls of the end”
At exit function

■ With ANSI C a process can register up to


32 functions that are called by exit ---called
exit handlers
■ Exit handlers are registered by calling the
atexit function

#include <stdlib.h>
Int atexit (void (*fun) void));
■ Atexit function calls these functions in
reverse order of their registration

■ Each function is called as many times as


it was registered
#include "ourhdr.h"
static void my_exit1(void), my_exit2(void);
int main(void)
{
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");
return(0);
}
static void my_exit1(void)
{
printf("first exit handler\n");
}
static void my_exit2(void)
{
printf("second exit handler\n");
}
Command-line arguments
■ /* program to echo command line
arguments*/
int main (int argc, char* argv[ ])
{
for(int i=0;i<argc ;i++)
{
printf(“argv[%d]:%s \n”,I,argv[i]);
}
}
Memory layout of a C program
■ Text segment – sharable copy
■ Initialized data segment – variables
specifically initialized in the program
■ Uninitialized data segment – “bss”
segment
data is initialized to arithematic 0 or null
■ Stack – return address and information
about caller’s environment
■ Heap – dynamic memory allocation takes
place on the heap
DHigh
ia gaddress
ra m o f M e m o ry la y o u t
Command line arguments
Stack And environment variables

heap

Uninitialised data Intialized to 0 by


exec
initialised data Read from
prog File
Text by exec
Low address
Shared libraries

■ Shared libraries remove the common


library routines from the executable file ,
instead maintaining a single copy of the
library routine some where in memory
that all processes reference
■ Advantage: reduces size of executable file
easy to replace with a newer version
■ Disadvantage: some- runtime overhead
Memory allocation

■ malloc : allocates specified number of


bytes of memory
■ calloc : allocates specified number of
objects of specified size
■ realloc : changes size of previous
allocated area
C o n t..
#include <stdlib.h>
void *malloc (size_t size);
void *calloc (size_t nobj, size_t size);
void *realloc (void *ptr, size_t newsize);

realloc may increase or decrease the


size of previously allocated area .If it
decreases the size no problem occurs
But if the size increases then………….
1. Either there is enough space then the
memory is reallocated and the same
pointer is returned
2. If there is no space then it allocates new
area copies the contents of old area to
new area frees the old area and returns
pointer to the new area
Kernel support for processes

Kernel region table


Process table

Per process region table


text
File descriptor
table data
Current directory stac
root k
Per process u-area
■ A text segment – program text of a
process in machine executable
instruction code format
■ A data segment – static and global
variables in machine executable format
■ A stack segment – function arguments,
automatic variables and return addresses
of all active functions of a process at any
time
■ U-area is an extension of Process table
entry and contains process-specific data
■ UNIX kernel has a process table that keeps track of all
active process present in the system.
■ Some of these processes belongs to the kernel and are
called as “system process”.
■ Every entry in the process table contains pointers to the
text, data ad the stack segment and also to U-area of a
process.
■ U-area of a process is an extension of the process table
entry and contains other process specific data such as
the file descriptor table, current root and working
directory inode numbers and set of system imposed
process limits.
■ Region table entries describes the attributes
of the region, such as whether it contains text
or data, whether it is shared or private.

■ The extra level from the per process region


table to kernel region table allows
independent processes to share regions.
Parent child Process Relationship
■ All process in UNIX system except the process that is
created by the system boot code, are created by the fork
system call.
■ After the fork system call, once the child process is
created, both the parent and child processes resumes
execution.
■ When a process is created by fork, it contains duplicated
copies of text, data and stack segments of its parent as
shown in the Figure.
■ Also it has a file descriptor table, which contains
reference to the same opened files as the parent such
that they both share the same file pointer to each
opened files.
Besides open files the other properties
inherited by child are
■ Real user ID, group ID, effective user ID,
effective group ID
■ Supplementary group ID
■ Process group ID
■ Session ID
■ Controlling terminal
■ set-user-ID and set-group-ID
■ Current working directory
■ Root directory
■ Signal handling
■ Signal mask and dispositions
■ Umask
■ Nice value
■ The difference between the parent & child
■ The process ID
■ Parent process ID
■ File locks
■ Alarms clock time
■ Pending signals
Set jump and long jump

■ To transfer control from one function to


another we make use of setjmp and
longjmp functions

#include <stdio.h>
int setjmp (jmp_buf env);
void longjmp (jmp_buf env, int val);
■ env is of type jmp_buf ,this data type is
form of array that is capable of holding all
information required to restore the status
of the stack to the state when we call
longjmp

■ Val allows us to have more than one


longjmp for one setjmp
#include<stdio.h> void read() void check()
#include<string.h> { {
if(strlen(cmd)<=1)
#include<stdlib.h> printf("Enter a command"); {
#include<setjmp.h> scanf("%s",cmd); puts("Error\n");
static jmp_buf buf,buf1; if(setjmp(buf1)==0) longjmp(buf,2);
}
char cmd[20]; exe(); return;
else }
void read(); printf("Invalid command\n");
void check(); longjmp(buf,1);
void exe(); }
void exe()
int main()
{
{
check();
if(setjmp(buf)==0)
if(system(cmd)!=0)
read();
longjmp(buf1,1);
else
}
printf(“end of program");
Return 0;
}
Output :
Enter a command :
date
Sat Mar 30 13:18:15 IST
2019
end of program

Enter a command :
q
Error
end of program

Enter a command :
pwe
sh: 1: pwe: not found
Invalid command
end of program
getrlimit and setrlimit

■ A core file is created when a program terminates


unexpectedly, due to a bug, or a violation of the OS or
hardware protection mechanisms.
■ A hard limit is the maximum number of resources
allowed to a process, set by the superuser/root.
■ A soft limit is the effective number of resources right
now allocated to a process.
■ The user can increase the soft limit on their own in times
of needing more resources, but cannot set the soft limit
higher than the hard limit.
getrlimit and setrlimit

■ Every process has a set of resource limits, some of


which can be queried and changed by the getrlimit
and setrlimit functions.
Struct rlimit
{
rlim_t rlim_cur; /*soft limit*/
rlim_t rlim_max; /*hard limit */
}
1. Soft link can be changed by any process
to a value <= to its hard limit
2. Any process can lower its hard limit to a
value greater than or equal to its soft
limit
3. Only super user can raise hard limit
■ RLIMIT_CORE – max size in bytes of a
core file
■ RLIMIT_CPU – max amount of CPU time in
seconds
■ RLIMIT_DATA – max size in bytes of data
segment
■ RLIMIT_FSIZE – max size in bytes of a file
that can be created
■ RLIMIT_MEMLOCK – locked in-memory
address space
■ RLIMIT_NOFILE – max number of open
files per process
■ RLIMIT_NPROC – max number of child
process per real user ID
■ RLIMIT_OFILE – same as RLIMIT_NOFILE
■ RLIMIT_RSS – max resident set size in
bytes
■ RLIMIT_STACK – max size in bytes of the
stack
■ RLIMIT_VMEM – max size in bytes of the
mapped address space
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include "ourhdr.h"
#define doit(name) pr_limits(#name, name)
static voidpr_limits(char *, int);
int main(void)
{
doit(RLIMIT_CORE);
doit(RLIMIT_CPU);
doit(RLIMIT_DATA);
doit(RLIMIT_FSIZE);
#ifdef RLIMIT_MEMLOCK
doit (RLIMIT_MEMLOCK);
#endif
#ifdef RLIMIT_NOFILE /* SVR4 name */
doit (RLIMIT_NOFILE);
#endif
#ifdef RLIMIT_OFILE /* 44BSD name */
doit (RLIMIT_OFILE);
#endif
#ifdef RLIMIT_NPROC
doit (RLIMIT_NPROC);
#endif
#ifdef RLIMIT_RSS
doit(RLIMIT_RSS);
#endif
doit(RLIMIT_STACK);
#ifdef RLIMIT_VMEM
doit(RLIMIT_VMEM);
#endif
exit(0);
}
static void
pr_limits(char *name, int resource)
{
struct rlimit limit;
if (getrlimit(resource, &limit) < 0)
err_sys("getrlimit error for %s", name);
printf("%-14s ", name);
if (limit.rlim_cur == RLIM_INFINITY)
printf("(infinite) ");
else
printf("%10ld ", limit.rlim_cur);
if (limit.rlim_max == RLIM_INFINITY)
printf("(infinite)\n");
else
printf("%10ld\n", limit.rlim_max);
}
system function

■ It helps us execute a command string


within a program
■ System is implemented by calling fork,
exec and waidpid

#include <stdlib.h>
int system (const char *cmdstring);
Process identifiers
■ Every process has a unique process ID, a
non negative integer
■ Special processes :
■ process ID 0 : scheduler process also
known as swapper
■ Process ID 1: init process never dies ,it’s
a normal user process run with super user
privilege
■ Process ID 2: pagedaemon
#include <unistd.h>
#include <sys/types.h>
pid_t getpid (void);
pid_t getppid (void);
uid_t getuid (void);
gid_t getgid (void);
Fork function

■ The only way a new process is created


by UNIX kernel is when an existing
process calls the fork function

#include <sys/types.h>
#include <unistd.h>
pid_t fork (void);
■ The new process created by fork is called child
process
■ The function is called once but returns twice
■ The return value in the child is 0
■ The return value in parent is the process ID of
the new child
■ The child is a copy of parent
■ Child gets a copy of parents text, data , heap
and stack
#include <sys/types.h>
#include "ourhdr.h"
int glob = 6;
/* external variable in initialized data */
char buf[ ] = "a write to stdout\n";
int main(void)
{
int var;
/* automatic variable on the stack */
pid_t pid;
var = 88;
if (write(STDOUT_FILENO, buf, sizeof(buf)
-1) != sizeof(buf)-1)
err_sys("write error");

printf("before fork\n");
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);
}
File sharing
■ Fork creates a duplicate copy of the file
descriptors opened by parent
■ File Table is shared Offset changes are
reflected both in parent and child
■ There are two ways of handling descriptors
after fork
1. The parent waits for the child to complete.
2. After fork the parent closes all descriptors that it doesn’t
need and the child does the same thing.
Besides open files the other properties inherited by child are
■ Real user ID, group ID, effective user ID, effective
group ID
■ Supplementary group ID
■ Process group ID
■ Session ID
■ Controlling terminal
■ set-user-ID and set-group-ID
■ 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
■ Resource limits
The difference between the parent and child
■ The return value of fork
■ The process ID
■ Parent process ID
■ The values of tms_utime , tms_stime ,
tms_cutime , tms_ustime is 0 for child
■ file locks set by parent are not inherited by
child
■ Pending alarms are cleared for the child
■ The set of pending signals for the child is set
to empty set
■ The functions of fork

1. A process can duplicate itself so that


parent and child can each execute
different sections of code

1. A process can execute a different


program
vfork

■ It is same as fork.
■ It is intended to create a new process when the
purpose of new process is to exec a new
program
■ The child runs in the same address space as
parent until it calls either exec or exit.
■ vfork guarantees that the child runs first,
until the child calls exec or exit.
int glob = 6;
/* external variable in initialized data */
int main(void)
{
int var;
/* automatic variable on the stack */
pid_t pid;
var = 88;
printf("before vfork\n");
if ( (pid = vfork()) < 0)
err_sys("vfork error");
else if (pid == 0) { /* child */
glob++;
/* modify parent's variables */
var++;
_exit(0); /* child terminates */
}
/* parent */
printf("pid = %d, glob = %d, var = %d\n",
getpid(), glob, var);
exit(0);
}
exit functions
■ Normal termination
1. Return from main
2. Calling exit – includes calling exit handlers
3. Calling _exit – it is called by exit function
■ Abnormal termination
4. Calling abort – SIGABRT
5. When process receives certain signals
■ Exit status is used to notify parent how a
child terminated
■ When a parent terminates before the
child, the child is inherited by init process
■ If the child terminates before the parent
then the information about the child is
obtained by parent when it executes wait
or waitpid
■ The information consists of the process
ID, the termination status and amount of
CPU time taken by process
■ A process that has terminated , but
whose parents has not yet waited for
it, is called a zombie
■ When a process inherited by init
terminates it doesn’t become a zombie
■ Init executes one of the wait functions to
fetch the termination status
exec functions

■ Exec replaces the calling process by a


new program
■ The new program has same process ID as
the calling process
■ No new process is created , exec just
replaces the current process by a new
program Starts from main.
■ File name:if slash in it treat as path name
■ Otherwise search in dir looking at PATH
variable.
■ Six Different exec functions
#include <unistd.h>

1. int execl( const char *pathname, const char *arg0 ,… /*(char *) 0*/);

1. int execv(const char *pathname, char * const argv[ ]);

1. int execle(const char *pathname, const char *arg0 ,… /*(char *)


0, char *const envp[ ] */);

1. int execve( const char *pathname, char *const argv[ ],


char *const envp [ ]);

1. int execlp (const char *filename, const char *arg0 ,… /*(char *) 0*/);

1. int execvp (const char *filename ,char *const argv[ ] );


■ Relation between exec functions

execl execle
execlp
Build argv Build argv Build argv

Try each use


execvp execv environ
execve
PATH prefix
New program inherits following
properties from calling process
Pid, ppid, ruid, rgid, sgid, pgid, sid,
Control terminal, alarm clock, current working
dir, root dir,
file mode creation mask, file locks,
process signal mask, pending signals,
resource limits, Close on Exec: fd will kept
open if flag not set.
#include <sys/types.h>
#include <sys/wait.h>
#include "ourhdr.h"
char *env_init[ ] =
{ "USER=unknown", "PATH=/tmp", NULL };
int main(void)
{
pid_t pid;
if ( (pid = fork()) < 0)
err_sys("fork error");
else if (pid == 0) {
/* specify pathname, specify environment */
if ( execle ("/home/stevens/bin/echoall",
"echoall", "myarg1", "MY ARG2",
(char *) 0, env_init) < 0)
err_sys("execle error");
}
if (waitpid(pid, NULL, 0) < 0)
err_sys("wait error");

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


err_sys("fork error");
else if (pid == 0) {
/* specify filename, inherit environment */
if (execlp("echoall",
"echoall", "only 1 arg",
(char *) 0) < 0)
err_sys("execlp error");
}
exit(0);
}
Changing user IDs and group IDs

■ Prototype

#include <sys/types.h>
#include <unistd.h>
int setuid (uid_t uid);
int setgid (gid_t gid);
■ Rules
1. If the process has superuser privilege,
the setuid function sets – real user ID,
effective user ID , saved set-user-ID to
uid
2. If the process doesnot have superuser
privilege, but uid equals either real user
ID or saved set-user-ID, setuid sets only
effective user ID to uid
3. If neither of the two conditions is true,
errno is set to EPERM and an error is
returned
ID exec exec
Set-user-ID Set-user-Id bit
bit off on
Real user ID unchanged unchanged
Effective user unchanged Set from user ID
ID of program file
Saved set copied from copied from
user ID effective effective user ID
user ID
ID Super Un
user privileged
user
Real user ID Set to uid unchanged
Effective user ID Set to uid Set to uid
Saved set-user ID Set to uid unchanged
setreuid and setregid

#include <sys/types.h>
#include <unistd.h>
int setreuid (uid_t ruid, uid_t euid);
int setregid (gid_t rgid,gid_t egid);
seteuid and setegid

#include <sys/types.h>
#include <unistd.h>

int seteuid (uid_t euid);


int setegid (gid_t egid);
Superuser Superuser Superuser
setreuid setuid seteuid
euid uid uid
uid

uid

Effective Saved
Real user ID User ID Unprivileged Set-user-ID
Unprivileged setreuid
setreuid Exec of
set-user-id
Unprivileged Unprivileged
Setuid or Setuid or
seteuid seteuid
■ Return values of system function

■ -1 – if either fork fails or waitpid returns an


error other than EINTR
■ 127 -- If exec fails [as if shell has
executed exit ]
■ termination status of shell -- if all three
functions succeed
#include <sys/types.h>
#include <sys/wait.h>
#include <errno.h>
#include <unistd.h>

int system(const char *cmdstring)


/* version without signal handling */
{
pid_t pid;
int status;
if (cmdstring == NULL)
return(1);
/* always a command processor with Unix */
if ( (pid = fork()) < 0)
{
status = -1;
/* probably out of processes */

} else if (pid == 0)
{ /* child */
execl("/bin/sh", "sh", "-c", cmdstring,
(char *) 0);
_exit(127); /* execl error */
■}
else { /* parent */
while (waitpid(pid, &status, 0) < 0)
if (errno != EINTR) {
status = -1;
/* error other than EINTR from waitpid() */
break;
}
}
return(status);
}
/* calling system function*/
#include <sys/types.h>
#include <sys/wait.h>
#include "ourhdr.h"
int main(void)
{
int status;

if ( (status = system("date")) < 0)


err_sys("system() error");
pr_exit(status);
if ( (status = system("nosuchcommand")) < 0)
err_sys("system() error");
pr_exit(status);

if ( (status = system("who; exit 44")) < 0)


err_sys("system() error");
pr_exit(status);

exit(0);
}
Process accounting

■ Process accounting : when enabled


kernel writes an accounting record each
time a process terminates

■ Accounting records : 32 bytes of binary


data
Struct acct
{
char ac_flag;
char ac_stat;
uid_t ac_uid;
gid_t ac_gid;
dev_t ac_ttty;
time_t ac_btime;
comp_t ac_utime;
comp_t ac_stime;
comp_t ac_etime;
comp_t ac_mem;
comp_t ac_io;
comp_t ac_rw;
char ac_comm;
}
/*prog: to generate accounting data */
#include <sys/types.h>
#include <sys/acct.h>
#include "ourhdr.h"
#define ACCTFILE "/var/adm/pacct"
static unsigned long
compt2ulong(comp_t);
int main(void)
{
struct acct acdata;
FILE *fp;
if ( (fp = fopen(ACCTFILE, "r")) == NULL)
err_sys("can't open %s", ACCTFILE);
while
(fread(&acdata, sizeof(acdata), 1, fp) == 1)
{ printf("%-*.*s e = %6ld, chars = %7ld, "
"stat = %3u: %c %c %c %c\n",
sizeof(acdata.ac_comm),
sizeof(acdata.ac_comm),
acdata.ac_comm,
compt2ulong(acdata.ac_etime),
compt2ulong(acdata.ac_io),
(unsigned char) acdata.ac_stat,
#ifdef ACORE
/* SVR4 doesn't define ACORE */
acdata.ac_flag & ACORE ? 'D' : ' ',
#else
' ',
#endif
#ifdef AXSIG
/* SVR4 doesn't define AXSIG */
acdata.ac_flag & AXSIG ? 'X' : ' ',
#else
' ',
#endif
acdata.ac_flag & AFORK ? 'F' : ' ',
acdata.ac_flag & ASU ? 'S' : ' ');
}
if (ferror(fp))
err_sys("read error");
exit(0);
}
static unsigned long
compt2ulong(comp_t comptime)
/* convert comp_t to unsigned long */
{
unsigned long val;
int exp;
val = comptime & 017777;
/* 13-bit fraction */
exp = (comptime >> 13) & 7;
/* 3-bit exponent (0-7) */
while (exp-- > 0)
val *= 8;
return(val);
}
User identification

■ To obtain the login name

#include <unistd.h>
char *getlogin (void);
Questions
■ Explain briefly the memory layout of a C
program (10)
■ What is fork and vfork ? Explain with an
example for each (8)
■ What is a zombie process ? Write a
program in C/C++ to avoid zombie
process by forking twice (6)
■ What is job control ? Summarize the job
control features with the help of a figure
(10)
■ Explain the different exec functions.
Explain how their functioning differ from
each other . Write a program that execs an
interpreter file (10)
■ What is job control ? What support is
required for job control ? Explain with an
example (10)
■ Explain how accounting is done in UNIX
system. Write a program to generate
accounting data and give its process
structure (10)
■ What is a controlling terminal ? Explain its
characteristics and relation to session
and process groups (10)
■ With an example explain the use of setjmp
and longjmp functions (10)
■ With a neat block diagram, explain how a
C program is started and the various ways
it can terminate. Give the prototypes for
exit and _exit functions and explain their
difference (10)

You might also like