You are on page 1of 55

Process management

1
The kernel

The core set of service that the OS provides

2
User Mode & kernel mode
User mode apps delegate to system APIs in order to access hardware

User
User space
Utilities compile / shell

Standard library

Kernel space o.s

3
What is a Shell?
• A user app running in user space.
• An interface to the kernel.
• Shell ≠ kernel.
• Shell ó OS.
• Shell commands delegate to system calls.

4
Bash shell
Bash - the classical Unix shell. Probably the most widly shell in use.

There are many other shells for Linux

5
System Calls
Definition:
Internal kernel routines that are exposed to user applications directly, through
the C library, or via any other user mode interfaces are called system calls.

System call = the programmatic way to requests a service from the kernel.

(!) System calls are implemented in the kernel and are not part of the C library.

6
System Calls

Typically system call may be used to perform:

• process control operations


• file management
• device manipulation
• information maintenance
• communication

7
Linux process management

8
The process ID
• Each process is represented by a unique identifier, the process ID (pid).

• It guaranteed to be unique at any single point in time.

• The process ID is represented by the pid_t type.

9
process ID Allocation
• By default, the kernel imposes a maximum process ID value of 32768.

• The kernel allocates process IDs to processes in a strictly linear fashion.

• The kernel does not reuse process ID values until it wraps around from the
top. That is, earlier values will not be reused until the values will allocate.

10
The type pid_t

Used for process IDs (and process group IDs).

11
System( )
System() –execute shell command.

# include <stdlib.h>
int system (const char *string);

The system function runs the command passed to it as a string and waits
for it to complete.

Example:

#include <stdio.h>
#include <string.h>
int main (){
char command [50];
strcpy(command,”ls –l”);
system(command);
return(0);
}

12
The exec family
The exec family are system calls (and not C library function), that executing
a new program.

#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, ..., char * const envp[]);
• int execv(const char *path, char *const argv[]);
• int execvp(const char *file, char *const argv[]);
• int execvpe(const char *file, char *const argv[], char *const envp[]);

13
execvp() - Definition
• replaces the program in the current process with a new program.
• return value:
– on error, returns -1.
– on success, there is no process to return values to.

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

14
main.c
execvp() -Example
kid.c
#include <stdio.h>


 #include <stdio.h>

int main(){
 

char** args = {0};
 int main(){

exevp("/home/ubuntu/workspace/ printf("hello! I am the same
kid", args);
 process (:\n");

printf("no one will print it return 0;

\n");
 }
return 0;

}

$ gcc main.c -o main


$ gcc kid.c -o kid
$ ./main
hello! I am the same process (:

15
The fork()

A System call that create a process by duplicating the invoking process

16
The fork()
#include <sys/types.h>
#include <unistd.h>

Pid_t fork (void);

When a process invokes fork() it is “duplicated” and a child process is created.


fork() is a system call and not a C library function.

Return value:
Upon success: 0 to the childand the PID ot the child to the parent.
Upon failure: no process is created , -1 returned to the parent.

17
fork() Example 1
pid_t new_pid;
new_pid = fork();
switch(new_pid){
case -1: /*Error*/
break;
case 0: /*We are child*/
break;
default: /*We are parent*/
break;
}

18
fork() Example 2
#include <sys/types.h> (Code cont.)
{
#include <unistd.h> case -1:
#include <stdio.h> perror(“fork failed”);
#include <stdlib.h> exit(1);
case 0:
int main() message = “This is the child”;
{ n = 5;
break;
pid_t pid;
default:
char *message; message = “This is the parent”;
int n; n = 3;
break;
printf(“fork program starting\n”); }
for(; n > 0; n--) {
pid = fork();
puts(message);
switch(pid) sleep(1);

 }
exit(0);
}

19
fork() introduces non-determinism
example:

pid_t x = fork();


if(x){

printf("1");

}else{

printf("2");

}

two possible outputs:


• 12
• 21

Note: In this code we have no control over the scheduling.

20
fork() Example 3
An example:
int i = 1;
printf("my process pid is %d\n",getpid());
fork_id=fork(); Program flow:
if (fork_id==0){
i= 2;
printf(“child pid %d, i=%d
\n",getpid(),i); PID = 8864 i=1
} else
printf(“parent pid %d, i=%d
\n",getpid(),i); fork ()
return 0;

Possible Output:

fork_id=0

my process pid is 8864 fork_id = 8865
 i=2
child pid 8865, i=2 i=1
parent pid 8864, i=1
PID = 8864 PID = 8865

21
getpid() vs. getppid()
int main(void)
{
pid_t parentPID;
pid_t childPID;

childPID = fork();

if (childPID >= 0) { // fork was successful


if (childPID == 0) // child process
printf("\n Child Process :: childPID %d parentPID %d\n", getpid(),
getppid());
else // parent process
printf("\n Parent Process :: childPID %d parentPID %d\n",
getpid(), getppid());
} else { // fork failed
printf("\n Fork failed, quitting!!!!\n");
return 1;
}
return 0;
}

Possible output:
Parent Process :: childPID 4672 parentPID 2251

Child Process :: childPID 4673 parentPID 4672 22
What is a possible output? (1)
int main(void)
{
fork();
printf(“fork 1.\n”);

fork();
printf(“fork 2.\n”);

return 0;
}

Possible output: Possible output: Possible output:


fork 1. fork 1. fork 1.
fork 2. fork 2. fork 1.
fork 2. fork 1. fork 2.
fork 1. fork 2. fork 2.
fork 2. fork 2. fork 2.
fork 2. fork 2. fork 2.

a b c
23
What is a possible output? (2)
What will be printed in each code?

a b

24
What is a possible output? (3)

25
What is a possible output? (4)
How many lines of “Hello” will be printed in the following example:

int main(void) int main(void) int main(void)


{ { {
int i; int i; int i;
for (i=0; i<10; i++){ for (i=0; i<10; i++){ for (i=0; i<10; i++)
fork(); printf(“Hello \n”); fork();
printf(“Hello \n”); fork(); printf(“Hello \n”);
} } return 0;
return 0; return 0; }
} }

a b c

26
Tree of processes (1)
Draw the tree of process that will result:

int x;
fork();
x = fork();
if(x != 0)
fork();
printf(“pid= %d”,getpid()); Solution:

1
5 4
What are possible outputs of the code?
2

6 3
27
Tree of processes(2)
Write code that creates this tree:

28
Tree of processes(2)
Solution:
1
int main(void)
{
pid_t id= = fork(); 2
if (id == 0) { // if this is process #2
fork();
}
return 0; 3
}

29
Tree of processes(3)
Write code that creates this tree:

3 4
2

5 6 7

30
Tree of processes(3)
Solution: 1

int main(void)
{ 3 4
pid_t first_id= = fork(); 2
fork();
fork();
5 6 7
if (first_id == 0)
{
fork(); Naive solution, Does not work!
fork();
fork();
}

return 0;
}

31
Tree of processes(3)
Solution:
1
int main(void)
{
first_id = fork(); // create #2
if (first_id != 0) //if you’re the father 3 4
{ 2
second_id = fork(); // create #3
if (second_id != 0) //if you’re the father
fork(); // create #4
}
5 6 7
if (first_id == 0) //if you’re #2 (a child)
{
forth_id = fork(); // create #5

if (forth_id != 0) { //if you’re the father (#2)


fifth_id = fork(); // create #6
if (fifth_id != 0) //if you’re the father (#2)
fork(); // create #7
}
}
return 0;
}

32
fork() and Binary Tree

fork() && fork()

33
fork() and Binary Tree

fork() && fork()

lazy evaluation -
• if “&&” left side evaluated to be false, right side will not executed.
• if “||” left side evaluated to be true, right side will not executed.

sometimes, computers are almost as lazy as humans :P

34
fork() and Binary Tree

fork() && fork()

• first fork:
– return true for the parent
– return false for the child
• second fork:
– Lazy evaluation - the child has false, so it won’t execute the right
hand

first fork 1

second fork

2 3

35
fork() and Binary Tree

fork() || fork()

36
fork() and Binary Tree

fork() || fork()

Lazy evaluation - the parent recieved true, so it won’t execute the right hand

1
first fork

second fork 2

3
37
fork() and Binary Tree

fork() && fork() || fork()

38
fork() and Binary Tree

fork() && fork() || fork()


1 2 3

fork 1

true false
fork 3

fork 2

true && false == false


fork 3
true && true == true

39
fork() and Binary Tree

REAL TEST QUESTION!


fork();
fork() && fork() || fork();
fork();
printf(“I <3 the fork command!\n”);

how many lines will be printed?

40
fork() and Binary Tree
fork();
fork() && fork() || fork();
fork();

41
fork() & for loops (1)

int i;

for( i=0; i<3 && fork() ; i++ );
printf("line\n");


42
fork() & for loops (2)

int i;

for( i=0; i<3 || fork() ; i++ ){
printf("line %d\n", i);
}


43
fork-exec combination
main.c kid.c
#include <stdio.h>


int main(){
 #include <stdio.h>

char** args = {0};
 

if(!fork())
 int main(){

execvp("/home/ubuntu/workspace/ printf("hello! I am just a
kid", args);
 child (:\n");

else
 return 0;

printf("I am the parent !\n");
 }
printf("only parent, will print it
\n");

return 0;

}

$ gcc main.c -o main


$ gcc kid.c -o kid
$ ./main
I am the parent !
only parent, will print it
hello! I am just a child (:

44
wait()
#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *stat_loc);

• The wait() system call causes a parent process to pause until one of
its child processes is stopped.

• Returns : PID of the child process(normally be a child process that


has terminated).

45
wait()
• You can interpret the status information using macros defined in sys/
wait.h, shown in the following table.

Macro Definition

(WIFEXITED(stat_val Nonzero if the child is terminated normally

(WEXITSTATUS(stat_val If WIFEXITED is nonzero, this return child exit code

(WIFSIGNALED(stat_val Nonzero if the child is terminated on an uncaught signal

(WTERMSIG(stat_val If WIFSIGNALED is nonzero, this returns a signal number

(WIFSTOPPED(stat_val .Nonzero if the child has stopped

(WSTOPSIG(stat_val If WIFSTOPPED is nonzero, this returns a signal number

46
wait()- Example
#include <sys/types.h> (Code cont.)
{
#include <sys/wait.h>
case -1:
#include <unistd.h> perror(“fork failed”);
#include <stdio.h> exit(1);
#include <stdlib.h> case 0:
message = “This is the child”;
int main() n = 5;
{ exit_code = 37;
pid_t pid; break;
default:
char *message;
message = “This is the parent”;
int n; n = 3;
int exit_code; exit_code = 0;
break;
printf(“fork program starting\n”); }
pid = fork(); for(; n > 0; n--) {
puts(message);
switch(pid)
sleep(1);

 }

(Code cont. next slide)

47
wait()- Example
This section of the program waits for the child process to finish.
(Code cont.)
if (pid!=0) {
int stat_val;
pid_t child_pid;

child_pid = wait(&stat_val);

printf(“Child has finished: PID = %d\n”, child_pid);


if(WIFEXITED(stat_val))
printf(“Child exited with code %d\n”, WEXITSTATUS(stat_val));
else
printf(“Child terminated abnormally\n”);
}
exit(exit_code);
}

48
Zombie Process
When a child process terminates, an association with its parent
survives until the parent in turn either terminates normally or
calls wait().

49
Zombie Process- Example
#include <sys/types.h> (Code cont.)
{
#include <unistd.h> case -1:
#include <stdio.h> perror(“fork failed”);
#include <stdlib.h> exit(1);
case 0:
int main() message = “This is the child”;
{ n = 3;
break;
pid_t pid;
default:
char *message; message = “This is the parent”;
int n; n = 5;
break;
printf(“fork program starting\n”); }
for(; n > 0; n--) {
pid = fork();
puts(message);
switch(pid) sleep(1);

 }
exit(0);
}

50
exit()
#include <stdlib.h>
void exit (int status);

• A call to exit() performs some basic shutdown steps, then instructs


the kernel to terminate the process.
• This function has no way of returning an error, in fact, it never returns
at all.
• The status parameter is used to denote the processes exit status.

51
waitpid()
#include <sys/types.h>
#include <sys/wait.h>

pid_t waitpid(pid_t pid, int *status, int options);

• The waitpid() call is more powerful of wait().


• The pid parameter specifies exactly which processes to wait for.
Its values fall into four camps:
I. <-1.
II. -1.
III. 0.
IV. >0.

52
Daemon process
• A daemon is a process that runs in the background, not connecting to any
controlling terminal. Daemons are normally started at boot time, are run
as root or some other special user ,and handle system-level tasks.

• As a convention, the name of a daemon often ends in d, but this is not


required or even universal.

• A daemon has two general requirements: it must run as a child of init and
it must not be connected to a terminal.

53
Session and Process Groups
• Each process is a member of a process group, which is a collection of one
or more processes generally associated with each other for the purposes
of job control.
• The primary attribute of a process group is that signals may be sent to all
processes in the group.

• Each process group is identified by a process group ID(pgid) and has a


process group leader.

54
You have to learn the following functions on your own

• vfork()
• getsid()
• setsid()
• getuid()
• getgid()

55

You might also like