OS System Call 15
OS System Call 15
The “exec()” system call is used to replace the current process with a new
program or executable. It loads a new program into the current process’s
memory, overwriting the existing program’s code, data, and stack.
When “exec()” is called, the operating system performs the following steps:
a. The current process’s memory is cleared, removing the old program’s
instructions and data.
b. The new program is loaded into memory.
c. The program’s entry point is set as the starting point of execution.
d. The new program’s code begins execution.
The “exec()” system call is often used after a “fork()” call in order to replace the
child process’s code with a different program.
This allows the child process to execute a different program while preserving the
parent process’s execution.
The “exec()” system call takes the path to the executable as an argument and can
also accept additional arguments, such as command-line arguments to be passed
to the new program.
It’s worth noting that after a successful “exec()”, the new program completely
replaces the old program, including its code, data, and file descriptors.
execl()
execlp()
execle()
execv()
execvp()
execve()
ps System call
Header line
o %CPU: It shows how much the process is using the CPU.
o %MEM: It shows how much the process is using memory.
o ADDR: It shows the memory address of a process.
o CP or C: It shows scheduling information and CPU usage.
o COMMAND*: It shows the process name, including arguments if available.
o NI: It shows nice value.
o The nice value determines the priority of the process. The higher the
value, the lower the priority--the "nicer" the process is to other
processes. The default nice value is 0 on Linux workstations.
o F: It displays flags.
o PID: It shows the number of a Process ID.
o PPID: It shows the number of the parent processes of the process.
o PRI: It shows the process's priority.
o RSS: It stands for Resident set size.
o STAT or S: It shows the status code of the process.
o STIME or START: It shows the time when a process started.
o TIME: It shows the CPU time amount utilized by a process.
o VSZ: It shows virtual memory usage.
o TTY or TT: It shows the terminal corresponding to the process.
o USER or UID: It shows the username of the owner of the process.
o WCHAN: It shows an event's memory address the process is delaying for.
When the fork system call is used, the operating system completely copies the
parent process to produce a new child process.
The memory, open file descriptors, and other pertinent properties of the parent
process are passed down to the child process.
The child process, however, has a unique execution route and PID.
The copy-on-write method is used by the fork system call to maximize memory
use.
At first, the physical memory pages used by the parent and child processes are
the same.
To avoid unintentional changes, a separate copy is made whenever either
process alters a shared memory page.
The return value of the fork call can be used by the parent to determine the
execution path of the child process.
If fork() returns 0 then it is executing the child process, if it returns -1
then there is some error; and if it returns some positive value, then it is
the PID of the child process.
Example 1
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
fork();
fork();
fork();
printf("hello\n");
return 0;
}
Output
hello
hello
hello
hello
hello
hello
hello
hello
Explanation
The number of times ‘hello’ is printed is equal to the number of processes created.
Total Number of Processes = 2n, where n is the number of fork system calls.
So here n = 3, 23 = 8 Let us put some label names for the three lines:
fork (); // Line 1
fork (); // Line 2
fork (); // Line 3
L1 // There will be 1 child process
/ \ // created by line 1.
L2 L2 // There will be 2 child processes
/ \ / \ // created by line 2
L3 L3 L3 L3 // There will be 4 child processes
// created by line 3
So there is a total of eight processes (new child processes and one original process). If
we want to represent the relationship between the processes as a tree hierarchy it
would be the following: The main process: P0 Processes created by the 1st fork: P1
Processes created by the 2nd fork: P2, P3 Processes created by the 3rd fork: P4, P5,
P6, P7
P0
/ | \
P1 P4 P2
/ \ \
P3 P6 P5
/
P7
Example 2:
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
void forkexample()
{
pid_t p;
p = fork();
if(p<0)
{
perror("fork fail");
exit(1);
}
// child process because return value zero
else if ( p == 0)
printf("Hello from Child!\n");
Output
Hello from Parent!
Hello from Child!
Note: In the above code, a child process is created. fork() returns 0 in the child process
and positive integer in the parent process. Here, two outputs are possible because the
parent process and child process are running concurrently. So we don’t know whether
the OS will first give control to the parent process or the child process.
Parent process and child process are running the same program, but it does not mean
they are identical. OS allocates different data and states for these two processes, and the
control flow of these processes can be different
A call to wait() blocks the calling process until one of its child processes exits or a signal
is received. After child process terminates, parent continues its execution after wait
system call instruction.
Child process may terminate due to any of these:
It calls exit();
It returns (an int) from main
It receives a signal (from the OS or another process) whose default action is to
terminate.
If any process has more than one child processes, then after calling wait(),
parent process has to be in wait state if no child terminates.
If only one child process is terminated, then wait() returns process ID of the
terminated child process.
If more than one child processes are terminated than wait() gathered
any arbitrarily child and return a process ID of that child process.
When wait() returns they also define exit status (which tells our, a process
why terminated) via pointer
If any process has no child process then wait() returns immediately “-1”.
The join() is called by both the parent and the child. The child process calls join() after
it has finished execution. This operation is done implicitly. The parent process waits
until the child joins and continues later.
The join() call breaks the concurrency because the child process exits. The join()
inform the parent that child operation is finished.
1. The child joins first and then the parent joins without waiting for any process.
2. The parent process joins first and wait, the child process joins, and the parent
continues thereafter.
Example #1
The parent executes “fork L” statement. It creates a child process which runs
concurrently- one process (parent) continues after the fork operation and other
(child) statement runs at statement labeled L.
S1;
fork L;
...
...
L: S3 /* statement labeled L */
The fork splits the single operation into two independent operation – S2 and S3.
The join call combines the two concurrent process into one. The process which
executes join first will be terminated and the other process continues. If it is parent S2
that terminates first, then it will wait for S3 to finish.
Figure 2 – Join () Precedence Graph
If S3 join first, then S2 will join later after finishing the execution without waiting.