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

CMPE382 Processes Suppl2

The document discusses processes in a computer system, detailing how they are created using the fork() system call and how they can be controlled and managed. It explains concepts such as zombie and orphan processes, and provides example code snippets to illustrate these concepts. Additionally, it covers how to execute different programs from within a process using various exec functions.

Uploaded by

kaanaydin1441
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 views5 pages

CMPE382 Processes Suppl2

The document discusses processes in a computer system, detailing how they are created using the fork() system call and how they can be controlled and managed. It explains concepts such as zombie and orphan processes, and provides example code snippets to illustrate these concepts. Additionally, it covers how to execute different programs from within a process using various exec functions.

Uploaded by

kaanaydin1441
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

OS Supplementary Material 2: Processes

A typical computer has multi-programming. Either clicking on a program’s icon or typing its name on a
terminal window, the operating system creates an executable copy of the program and starts its execution,
which is known as a process. There may be hundreds of processes active in a system.

1.1 Process Creation

More than one process can be created by either running the same program again and again, or internally by
another process. Try the following program (fork.c):

#include <stdio.h>
#include <unistd.h>
int main() {
printf("test 1\n");
fork();
printf("test 2\n");
return 0;
}

When executed, you should observe that this program produces one line of “test 1” string and two lines of
“test 2” strings. Why?

At the time of the first printf(), there is only one running process (the one you have executed). When the program
code reaches the fork() system call line, the operating system creates a duplicate of this process t, sharing the
same code. Therefore all lines of code following the fork() system call will be executed by two separate processes.
This is the reason you get two “test 2” printed.

The following figure visually illustrates fork procedure:

Figure 1: fork() system call

1.2 Controlling Processes

Any running process is assigned a unique process ID (pid) by the operating system. You can use these id’s to
check if a process is successfully created or not and also assign different programs to them: ( name this small
program as fork1.c)

#include <stdio.h>
#include <unistd.h>
int main() {
pid_t child_pid;
printf("Original pid is %d\n", getpid());
child_pid = fork();
if (child_pid == -1)
printf("Can’t create child process\n");
else if (child_pid == 0)
printf("This is child process, pid = %d, parent pid = %d\n", getpid(), getppid());
else /* child_pid > 0 */
printf("This is parent process, pid = %d\n", getpid());
return 0;
}

getpid() returns the process id of the calling process and getppid() returns the pid of its parent process. If not
succeeded fork() returns -1 as an error case. If succeeded, it returns 0 to the newly created child process and
pid of child process to parent process (a positive integer).

Note that since we have 2 separate processes after a fork() call, variables in the program will be duplicated
too. But because two processes have their variables stored in different addresses in memory, values of these
variables may differ from each other in time as the processes execute their own separate instructions
(fork2.c):

#include <stdio.h>
#include <unistd.h>
int main() {
pid_t child_pid;
int a = 5;
printf("a before fork: %d\n", a);
child_pid = fork();
if (child_pid == 0)
a = 7;
printf("a after fork: %d\n", a);
return 0;
}

What is the output of this program? Why?

1.3 Zombie Processes

If a child process terminates before its parent process, it is still kept in the memory until its parent process
terminates too. A process in this state is called as a zombie process or defunct process. Study the following
program (zombie.c):

#include <stdio.h>
#include <unistd.h>
int main() {
int i;
char* msg;
pid_t child_pid;
child_pid = fork();
if (child_pid == -1) {
perror("fork");
return -1;
} else if (child_pid == 0) {
msg = "CHILD";
i = 3;
} else if (child_pid > 0) {
msg = "PARENT";

i = 10; }

for (; i >= 0; i--) {


printf("[%s] i = %d\n", msg, i);
sleep(1);}
return 0;
}

While running this program, open a second terminal window and run a any appropriate ps command several
times. After few seconds, you should see that the child process will have some changes. Test this and see what
happens while examining the output on the terminal window.

You may let the parent process wait for a child process to end its job before continuing, making the following
change (wait.c):

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int status;
char text[30], input[30];
pid_t child_pid;
FILE* fp;
child_pid = fork();
if (child_pid == -1) {
perror("fork");
return -1;
} else if (child_pid > 0) {
waitpid(child_pid, &status, 0);
fp = fopen("[Link]", "r");
fgets(text, 30, fp);
printf("Read from file: %s\n", text);
} else if (child_pid == 0) {
fp = fopen("[Link]", "w");
printf("Enter something: ");
scanf("%s", input);
fprintf(fp, "%s", input);
}
fclose(fp);
return 0;
}

1.4 Orphan Processes

A process becomes orphan if its parent process terminates first. Processes that are orphaned are owned by
the init process (pid = 1). Study the following program (orphan.c):

#include <stdio.h>
#include <unistd.h>
int main() {
int t;
char *pname;
pid_t child_pid = fork();
if (child_pid == 0) {
pname = "child";
t = 10;
} else if (child_pid > 0) {
pname = "parent";
t = 3; }
printf("%s pid: %d, ppid: %d\n", pname, getpid(), getppid());
sleep(t);
printf("%s process ends now (pid: %d, ppid: %d)\n", pname, getpid(), getppid());
return 0;
}

While this program is running, you’ll notice that child reports different parent process id’s before and after
the sleeping period, as in the following sample output:

parent pid: 4401, ppid: 16154


child pid: 4806, ppid: 4401
parent process ends now (pid: 4401, ppid: 16154)
child process ends now (pid: 4806, ppid: 1)

1.5 Starting Programs from Other Programs

We have used fork() in order to create duplicate processes of the same programs. But sometimes it may be
necessary to execute different programs. In such cases it is possible to start a new program directly from
instructions written in the source code. Study the following code (execl.c):

#include <stdio.h>
#include <unistd.h>
int main() {
printf("Displaying directory contents:\n");
execl("/bin/ls", "ls", NULL);
printf("Displayed directory contents.\n");
return 0;
}

What is the output of this program?

There are 6 functions (execl, execlp, execle, execv, execvp, execvpe) that can be used to call other programs.
They all do their job by replacing the current program with the new one, therefore it is impossible to return
to the original code unless these functions fail. There are minor differences between these six functions; you
may learn all about them by executing “man execl”.

Parameters of execl function can be explained in three parts:

1. The first parameter must be the path of the program to be executed. You may learn the program
paths with the help of which command (e.g. which ls).
2. The following parameters are all passed to the new process as command line arguments. Study the
following examples:
1. execl("/bin/ls", "ls", NULL); - The /bin/ls program is executed and its command line
arguments are “ls”.
2. execl("/bin/ls", "ls", "-l", "-a", NULL); - The /bin/ls program is executed and its command
line arguments are “ls -l -a”.
3. Finally, execl parameters must always end with NULL, so that the system knows when to stop
parsing arguments.

Since these functions replace the program of the calling process, it is a good exercise to create a dedicated
child process for such purposes; so that the main process still continues running. Study the following code
(execl2.c):

#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
int status;
pid_t child_pid;
child_pid = fork();
if (child_pid == -1) {
perror("fork");
return -1;
}
else if (child_pid == 0)
execl("/bin/ls", "ls", NULL);
else if (child_pid > 0) {
printf("Displaying directory contents:\n");
waitpid(child_pid, &status, 0);
printf("Displayed directory contents.\n");
}
return 0;
}

Exercises
1. Read man pages for the following system calls: fork, getpid, getppid, wait.
2. Execute the given programs at least once.
3. Modify fork.c such that it contains three consecutive fork() calls. How many processes will be
created? What will the output be?
4. Modify pid.c such that the parent process also calls getppid(). You should see the pid of an another
process. Which process is it? Does it have a parent process too?
5. Modify execl.c such that you use execl, execlp, execv and execvp correctly one-by-one. You may learn
the differences between them using man pages.

You might also like