0% found this document useful (0 votes)
2 views39 pages

OS Final Lab File [Final][Final][Final]

The document outlines the lab file for the Operating System course at Pranveer Singh Institute of Technology, detailing the vision, mission, educational objectives, program outcomes, and specific outcomes for the Computer Science & Engineering department. It includes a list of experiments focusing on UNIX commands and CPU scheduling algorithms, along with course outcomes aligned with Bloom's taxonomy. The document serves as a comprehensive guide for second-year B. Tech students during the Even Semester of 2024-25.
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)
2 views39 pages

OS Final Lab File [Final][Final][Final]

The document outlines the lab file for the Operating System course at Pranveer Singh Institute of Technology, detailing the vision, mission, educational objectives, program outcomes, and specific outcomes for the Computer Science & Engineering department. It includes a list of experiments focusing on UNIX commands and CPU scheduling algorithms, along with course outcomes aligned with Bloom's taxonomy. The document serves as a comprehensive guide for second-year B. Tech students during the Even Semester of 2024-25.
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/ 39

PRANVEER SINGH INSTITUTE OF TECHNOLOGY, KANPUR

DEPARTMENT OF COMPUTER SCIENCE & ENGINEERING

Even Semester 2024-25

B. Tech.- Second Year

Semester- IV

Lab File
Operating System
(BCS451)

Submitted To : Submitted By :
Faculty Name : Name :
Designation : Roll No. :
Section :
Table of Contents
• Vision and Mission Statements of the Institute

• Vision and Mission Statements of the Department

• PEOs, POs, PSOs of the Department

• Course Objective and Outcomes

• List of Experiments

• Index
Department Vision Statement
To be a recognized Department of Computer Science & Engineering that produces versatile computer
engineers, capable of adapting to the changing needs of computer and related industry.

Department Mission Statements


The mission of the Department of Computer Science and Engineering is:

i. To provide broad based quality education with knowledge and attitude to succeed in Computer
Science & Engineering careers.

ii. To prepare students for emerging trends in computer and related industry.

iii. To develop competence in students by providing them skills and aptitude to foster culture of
continuous and lifelong learning.

iv. To develop practicing engineers who investigate research, design, and find workable solutions to
complex engineering problems with awareness & concern for society as well as environment.

Program Educational Objectives (PEOs)


i. The graduates will be efficient leading professionals with knowledge of computer science &
engineering discipline that enables them to pursue higher education and/or successful careers in
various domains.

ii. Graduates will possess capability of designing successful innovative solutions to real life problems
that are technically sound, economically viable and socially acceptable.

iii. Graduates will be competent team leaders, effective communicators and capable of working in
multidisciplinary teams following ethical values.

iv. The graduates will be capable of adapting to new technologies/tools and constantly upgrading their
knowledge and skills with an attitude for lifelong learning
Department Program Outcomes (POs)
The students of Computer Science and Engineering Department will be able:

1. Engineering knowledge: Apply the knowledge of mathematics, science, Computer Science &
Engineering fundamentals, and an engineering specialization to the solution of complex engineering
problems.

2. Problem analysis: Identify, formulate, review research literature, and analyze complex
engineering problems reaching substantiated conclusions using first principles of mathematics,
natural sciences, and Computer Science & Engineering sciences.

3. Design/development of solutions: Design solutions for complex Computer Science &


Engineering problems and design system components or processes that meet the specified needs
with appropriate consideration for the public health and safety, and the cultural, societal, and
environmental considerations.

4. Investigation: Use research-based knowledge and research methods including design of


experiments, analysis and interpretation of data, and synthesis of the information to provide valid
conclusions.

5. Modern tool usage: Create, select, and apply appropriate techniques, resources, and modern
engineering and IT tools including prediction and modelling to complex Computer Science &
Engineering activities with an understanding of the limitations.

6. The Engineering and Society: Apply reasoning informed by the contextual knowledge to assess
societal, health, safety, legal and cultural issues and the consequent responsibilities relevant to the
professional engineering practice in the field of Computer Science and Engineering.

7. Environment and sustainability: Understand the impact of the professional Computer Science
& Engineering solutions in societal and environmental contexts, and demonstrate the knowledge of,
and need for sustainable development.

8. Ethics: Apply ethical principles and commit to professional ethics and responsibilities and norms
of the Computer Science & Engineering practice.

9. Individual and team work: Function effectively as an individual, and as a member or leader in
diverse teams, and in multidisciplinary settings.

10. Communication: Communicate effectively on complex Computer Science & Engineering


activities with the engineering community and with society at large, such as, being able to
comprehend and write effective reports and design documentation, make effective presentations,
and give and receive clear instructions.

11. Project management and finance: Demonstrate knowledge and understanding of the Computer
Science & Engineering and management principles and apply these to one’s own work, as a member
and leader in a team, to manage projects and in multidisciplinary environments.

12. Life-long learning: Recognize the need for, and have the preparation and ability to engage in
independent and life-long learning in the broadest context of technological change.
Department Program Specific Outcomes (PSOs)
The students will be able to:

1. Use algorithms, data structures/management, software design, concepts of programming


languages and computer organization and architecture.

2. Understand the processes that support the delivery and management of information systems
within a specific application environment.

Course Outcomes
*Level of Bloom’s Level to be
*Level of Bloom’s Taxonomy Level to be met
Taxonomy met
L1: Remember 1 L2: Understand 2
L3: Apply 3 L4: Analyze 4
L5: Evaluate 5 L6: Create 6

CO Number Course Outcomes


BCS-451.1 To be able to practice [L3: Apply] basic UNIX Commands
To be able to experiment with [L3: Apply] CPU scheduling algorithms, page
BCS-451.2 replacement and memory management algorithms.
List of Experiments

S. No. Topic COs


1 Unix commands practice. CO1
2 Implementation of CPU Scheduling Algorithms CO2
a) FCFS b) SJF
3 Implementation of CPU Scheduling Algorithms CO2
a) Priority (Non-Pre-emptive)
b) Multi-level Queue (Level-1 Time Quantum = 2 ms, Level-2 Time
Quantum = 4 ms, Level-3 FCFS)
4 Implementation of resource allocation graph (RAG). CO2
5 Implementation of Banker’s algorithm for Deadlock Avoidance. CO2
6 Conversion of resource allocation graph (RAG) to wait for graph (WFG) CO2
for each type of method used for storing graph.
7 Implementation of contiguous allocation techniques: CO2
a) Worst-Fit b) Best- Fit c) First- Fit
8 Implement the solution for Bounded Buffer (producer-consumer) CO2
problem using inter process communication techniques-Semaphores
9 Implement the solutions for Readers-Writers problem using inter CO2
process communication technique –Semaphore
10 Implementation of System calls. CO2
INDEX

S Lab Experiment Date of Date of Marks Faculty


No Experiment Submission Signature

10
EXPERIMENT 1: Unix commands practice.

UNIX Commands:

1. Date Command :

This command is used to display the current data and time.


Syntax: $date

2. Calendar Command :

This command is used to display the calendar of the year or the particular month of calendar year.
Syntax :
$cal<year>
$cal<month><year>
Here the first syntax gives the entire calendar for given year & the second Syntax gives the calendar
of reserved month of that year.

3. Echo Command :
This command is used to print the arguments on the screen .
Syntax : $echo <text>
Multi line echo command :
To have the output in the same line , the following commands can be used.
Syntax : $echo <text\>text
To have the output in different line, the following command can be used.
Syntax : $echo “text
>line2
>line3”

4. ‘who’ Command :
It is used to display who are the users connected to our computer currently.
Syntax : $who – option‟s
Options : -
H–Display the output with headers.
b–Display the last booting date or time or when the system was lastely rebooted.

5. ‘who am i’ Command :
Display the details of the current working directory.
Syntax : $who am i

6. ‘tty’ Command :
It will display the terminal name.
Syntax : $tty

7. ‘CLEAR’ Command :
It is used to clear the screen.
Syntax : $clear
8. ‘MAN’ Command :
It help us to know about the particular command and its options & working. It is like
„help‟ command in windows .
Syntax : $man <command name>

9. MANIPULATION Command :
It is used to manipulate the screen. Syntax :$tput<argument>
Arguments :
1. Clear – to clear the screen.
2. Longname – Display the complete name of the terminal.
3. SMSO – background become white and foreground become black color. 4.rmso – background
become black and foreground becomes white color. 5.Cols – Display the number of columns in our
terminals.

10. LIST Command :


It is used to list all the contents in the current working directory. Syntax :$ls–options <arguments>
If the command does not contain any argument means it is working in the Current directory.
Options :
• a– used to list all the files including the hidden files. c– list all the files column wise.
• d- list all the directories.
• m- list the files separated by commas.
• p- list files include „/‟ to all the directories. r- list the files in reverse alphabetical order.
• f- list the files based on the list modification date. x-list in column wise sorted order.

DIRECTORY RELATED COMMANDS

1. Present Working Directory Command :


To print the complete path of the current working directory.
Syntax : $pwd

2. MKDIR Command :
To create or make a new directory in a current directory .Syntax :$mkdir<directory name>

3. CD Command :
To change or move the directory to mentioned directory .Syntax :$cd <directory name>

4. RMDIR Command :
To remove a directory in the current directory & not the current directory itself.
Syntax :$rmdir<directory name>

FILE RELATED COMMANDS

1. CREATE A FILE :
To create a new file in the current directory we use CAT command.
Syntax :
$cat > filename.
The > symbol is redirectory we use cat command.
2. DISPLAY A FILE :
To display the content of file mentioned we use CAT command without „>‟ operator.
Syntax :
$cat <filename.
Options –s = to neglect the warning /error message.

3. COPYING CONTENTS :
To copy the content of one file with another. If file doesnot exist, a new file is created
and if the file exists with some data then it is overwritten.
Syntax :
$ cat<filename source>>><destination filename>
Options : -
-n content of file with numbers included with blank lines.
Syntax :
$cat –n <filename>

4. SORTING A FILE :
To sort the contents in alphabetical order or in reverse order.
Syntax :
$sort <filename >
Option : $ sort –r <filename>

5. COPYING CONTENTS FROM ONE FILE TO ANOTHER :


To copy the contents from source to destination file .so that both contents are same.
Syntax :
$cp<source filename><destination filename>
$cp<source filename path ><destination filename path>

6. MOVE Command :
To completely move the contents from source file to destination file and to remove the source file.
Syntax :
$ mv<source filename><destination filename>

7. REMOVE Command :
To permanently remove the file we use this command .
Syntax :
$rm<filename>

8. WORD Command :
To list the content count of no of lines , words, characters .
Syntax :
$wc<filename>
Options :
-c – to display no of characters.
-l – to display only the lines.
-w – to display the no of words.

9. LINE PRINTER :
To print the line through the printer, we use lp command.
Syntax :
$lp<filename>
10. PAGE Command :
This command is used to display the contents of the file page wise & next page can be
viewed by pressing the enter key.
Syntax :
$pg<filename>

11. FILTERS AND PIPES


HEAD :It is used to display the top ten lines of file. Syntax: $head<filename>
TAIL :This command is used to display the last ten lines of file.
Syntax: $tail<filename>
PAGE : This command shows the page by page a screen full of information is displayed after which
the page command displays a prompt and passes for the user to strike the enter key to continue
scrolling.
Syntax: $page<filename>

MORE :It also displays the file page by page .To continue scrolling with more command ,press the
space bar key.
Syntax: $more<filename>

GREP :This command is used to search and print the specified patterns from the file.
Syntax: $grep [option] pattern <filename>

SORT :This command is used to sort the datas in some order.


Syntax: $sort<filename>

PIPE :It is a mechanism by which the output of one command can be channeled into the input of
another command.
Syntax: $who | wc-l

TR :The tr filter is used to translate one set of characters from the standard inputs to another.
Syntax: $tr “[a-z]” “[A-Z]”
EXPERIMENT 2: Implementation of CPU Scheduling Algorithms
a) FCFS b) SJF

a.) FCFS
Algorithm:
(i) We randomly generate the number of jobs. There must be a limit on the number of jobs in a system.
(ii) The execution time of the generated jobs is also not known. Here, we are generating the CPU burst
of each job making use of the past history.
(iii) All the jobs are then arranged in a queue where searching is done to find the one with the least
CPU burst. There may be two jobs in queue with the same execution time then FCFS approach is to be
performed.

Program:
#include <stdio.h>

struct Process {
int id;
int arrival_time;
int burst_time;
int waiting_time;
int turnaround_time;
int completion_time;
};

void calculateTimes(struct Process processes[], int n) {


int total_waiting_time = 0;
int total_turnaround_time = 0;

processes[0].waiting_time = 0;
processes[0].completion_time = processes[0].arrival_time + processes[0].burst_time;
processes[0].turnaround_time = processes[0].burst_time;

for (int i = 1; i < n; i++) {


int start_time = (processes[i - 1].completion_time > processes[i].arrival_time) ?
processes[i - 1].completion_time : processes[i].arrival_time;

processes[i].waiting_time = start_time - processes[i].arrival_time;


processes[i].completion_time = start_time + processes[i].burst_time;
processes[i].turnaround_time = processes[i].completion_time - processes[i].arrival_time;
}

for (int i = 0; i < n; i++) {


total_waiting_time += processes[i].waiting_time;
total_turnaround_time += processes[i].turnaround_time;
}

printf("\nProcess\tArrival\tBurst\tCompletion\tTurnaround\tWaiting\n");
for (int i = 0; i < n; i++) {
printf("P%d\t%d\t%d\t%d\t\t%d\t\t%d\n",
processes[i].id,
processes[i].arrival_time,
processes[i].burst_time,
processes[i].completion_time,
processes[i].turnaround_time,
processes[i].waiting_time);
}

printf("\nAverage Waiting Time: %.2f", (float)total_waiting_time / n);


printf("\nAverage Turnaround Time: %.2f\n", (float)total_turnaround_time / n);
}

int main() {
int n;
printf("Enter the number of processes: ");
scanf("%d", &n);

struct Process processes[n];

for (int i = 0; i < n; i++) {


processes[i].id = i + 1;
printf("Enter arrival time and burst time for process %d: ", i + 1);
scanf("%d %d", &processes[i].arrival_time, &processes[i].burst_time);
}

// Sort by arrival time


for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (processes[j].arrival_time > processes[j + 1].arrival_time) {
struct Process temp = processes[j];
processes[j] = processes[j + 1];
processes[j + 1] = temp;
}
}
}

calculateTimes(processes, n);
return 0;
}
b.) SJF
Algorithm:
(i) We randomly generate the number of jobs. There must be a limit on the number of jobs in a system.
(ii) The execution time of the generated jobs is also not known. Here, we are generating the CPU burst
of each job making use of the past history.
(iii) All the jobs are then arranged in a queue where searching is done to find the one with the least
CPU burst. There may be two jobs in queue with the same execution time then FCFS approach is to be
performed.

Note: If the algorithm is non preemptive in nature, then the newly arriving job is to be added to the
job queue even though it is of lesser execution time than the one running on the processor.

Program:
#include <stdio.h>

struct Process {
int id;
int arrival_time;
int burst_time;
int waiting_time;
int turnaround_time;
int completion_time;
};

void calculateTimes(struct Process processes[], int n) {


int total_waiting_time = 0, total_turnaround_time = 0;
int completed = 0, current_time = 0;

while (completed != n) {
int idx = -1;
int min_burst = 99999;

for (int i = 0; i < n; i++) {


if (processes[i].arrival_time <= current_time && processes[i].completion_time == 0) {
if (processes[i].burst_time < min_burst ||
(processes[i].burst_time == min_burst && processes[i].arrival_time <
processes[idx].arrival_time)) {
min_burst = processes[i].burst_time;
idx = i;
}
}
}

if (idx != -1) {
processes[idx].completion_time = current_time + processes[idx].burst_time;
processes[idx].turnaround_time = processes[idx].completion_time - processes[idx].arrival_time;
processes[idx].waiting_time = processes[idx].turnaround_time - processes[idx].burst_time;

total_waiting_time += processes[idx].waiting_time;
total_turnaround_time += processes[idx].turnaround_time;

completed++;
current_time = processes[idx].completion_time;
} else {
current_time++;
}
}

printf("\nProcess\tArrival\tBurst\tCompletion\tTurnaround\tWaiting\n");

for (int i = 0; i < n; i++) {


printf("P%d\t%d\t%d\t%d\t\t%d\t\t%d\n",
processes[i].id,
processes[i].arrival_time,
processes[i].burst_time,
processes[i].completion_time,
processes[i].turnaround_time,
processes[i].waiting_time);
}

printf("\nAverage Waiting Time: %.2f\n", (float)total_waiting_time / n);


printf("Average Turnaround Time: %.2f\n", (float)total_turnaround_time / n);
}

int main() {
int n;
printf("Enter the number of processes: ");
scanf("%d", &n);

struct Process processes[n];


for (int i = 0; i < n; i++) {
processes[i].id = i + 1;
printf("Enter arrival time and burst time for process %d: ", i + 1);
scanf("%d %d", &processes[i].arrival_time, &processes[i].burst_time);
processes[i].completion_time = 0;
}

calculateTimes(processes, n);
return 0;
}
EXPERIMENT 3: Implementation of CPU Scheduling Algorithms
a) Priority (Non-Pre-emptive)
b) Multi-level Queue (Level-1 Time Quantum = 2 ms, Level-2 Time
Quantum = 4 ms, Level-3 FCFS)

a) Priority (Non-Pre-emptive)
Algorithm:
For PRIORITY algorithm,
(i) We again prefer to compute the CPU burst from past history.
(ii) Priority may be assigned on the basis of their CPU burst (simplest approach)
Program:

#include <stdio.h>

struct Process {
int id;
int arrival_time;
int burst_time;
int priority;
int waiting_time;
int turnaround_time;
int completion_time;
};

void calculateTimes(struct Process processes[], int n) {


int total_waiting_time = 0;
int total_turnaround_time = 0;
int completed = 0, current_time = 0;

while (completed != n) {
int idx = -1;
int highest_priority = -1;

for (int i = 0; i < n; i++) {


if (processes[i].arrival_time <= current_time && processes[i].completion_time == 0) {
if (processes[i].priority > highest_priority) {
highest_priority = processes[i].priority;
idx = i;
}
if (processes[i].priority == highest_priority) {
if (processes[i].arrival_time < processes[idx].arrival_time) {
idx = i;
}
}
}
}
if (idx != -1) {
processes[idx].completion_time = current_time + processes[idx].burst_time;
processes[idx].turnaround_time = processes[idx].completion_time -
processes[idx].arrival_time;
processes[idx].waiting_time = processes[idx].turnaround_time - processes[idx].burst_time;

total_waiting_time += processes[idx].waiting_time;
total_turnaround_time += processes[idx].turnaround_time;
completed++;
current_time = processes[idx].completion_time;
} else {
current_time++;
}
}

printf("Process\tArrival Time\tBurst Time\tPriority\tWaiting Time\tTurnaround Time\n");


for (int i = 0; i < n; i++) {
printf("P%d\t%d\t\t%d\t\t%d\t\t%d\t\t%d\n", processes[i].id, processes[i].arrival_time,
processes[i].burst_time, processes[i].priority, processes[i].waiting_time,
processes[i].turnaround_time);
}

printf("\nAverage Waiting Time: %.2f\n", (float)total_waiting_time / n);


printf("Average Turnaround Time: %.2f\n", (float)total_turnaround_time / n);
}

int main() {
int n;

printf("Enter the number of processes: ");


scanf("%d", &n);

struct Process processes[n];

for (int i = 0; i < n; i++) {


processes[i].id = i + 1;
printf("Enter arrival time, burst time and priority for process %d: ", i + 1);
scanf("%d %d %d", &processes[i].arrival_time, &processes[i].burst_time,
&processes[i].priority);
processes[i].completion_time = 0; // Initially, no process is completed
}

calculateTimes(processes, n);

return 0;
}
b) Multi-level Queue (Level-1 Time Quantum = 2 ms, Level-2 Time Quantum = 4
ms, Level-3 FCFS)

Program:

#include <stdio.h>
#include <stdbool.h>

#define MAX_PROCESSES 100

struct Process {
int id;
int arrival_time;
int burst_time;
int remaining_time;
int waiting_time;
int turnaround_time;
int completion_time;
int queue_level;
bool is_completed;
};

// Round Robin for a specific queue level


void roundRobin(struct Process processes[], int n, int tq, int queue_level, int *current_time) {
bool done;
do {
done = true;
for (int i = 0; i < n; i++) {
if (processes[i].queue_level == queue_level && !processes[i].is_completed &&
processes[i].arrival_time <= *current_time) {

done = false;
if (processes[i].remaining_time > tq) {
*current_time += tq;
processes[i].remaining_time -= tq;
} else {
*current_time += processes[i].remaining_time;
processes[i].remaining_time = 0;
processes[i].completion_time = *current_time;
processes[i].turnaround_time = processes[i].completion_time - processes[i].arrival_time;
processes[i].waiting_time = processes[i].turnaround_time - processes[i].burst_time;
processes[i].is_completed = true;
}
}
}
} while (!done);
}
// FCFS for a specific queue level
void fcfs(struct Process processes[], int n, int queue_level, int *current_time) {
for (int i = 0; i < n; i++) {
if (processes[i].queue_level == queue_level && !processes[i].is_completed) {
if (*current_time < processes[i].arrival_time)
*current_time = processes[i].arrival_time;

*current_time += processes[i].burst_time;
processes[i].completion_time = *current_time;
processes[i].turnaround_time = processes[i].completion_time - processes[i].arrival_time;
processes[i].waiting_time = processes[i].turnaround_time - processes[i].burst_time;
processes[i].is_completed = true;
}
}
}

void calculateTimes(struct Process processes[], int n) {


int total_waiting_time = 0;
int total_turnaround_time = 0;

printf("\nScheduling Algorithm Used:\n");


printf("Queue 1: Round Robin (Time Quantum = 2)\n");
printf("Queue 2: Round Robin (Time Quantum = 4)\n");
printf("Queue 3: First Come First Serve (FCFS)\n");

printf("\nProcess\tArrival\tBurst\tQueue\tCompletion\tTurnaround\tWaiting\n");
for (int i = 0; i < n; i++) {
printf("P%d\t%d\t%d\t%d\t%d\t\t%d\t\t%d\n",
processes[i].id,
processes[i].arrival_time,
processes[i].burst_time,
processes[i].queue_level,
processes[i].completion_time,
processes[i].turnaround_time,
processes[i].waiting_time);

total_waiting_time += processes[i].waiting_time;
total_turnaround_time += processes[i].turnaround_time;
}

printf("\nAverage Waiting Time: %.2f\n", (float)total_waiting_time / n);


printf("Average Turnaround Time: %.2f\n", (float)total_turnaround_time / n);
}

int main() {
int n;
printf("Enter the number of processes: ");
scanf("%d", &n);

struct Process processes[MAX_PROCESSES];


for (int i = 0; i < n; i++) {
processes[i].id = i + 1;
printf("Enter arrival time, burst time and queue level (1-3) for process %d: ", i + 1);
scanf("%d %d %d", &processes[i].arrival_time, &processes[i].burst_time,
&processes[i].queue_level);
processes[i].remaining_time = processes[i].burst_time;
processes[i].is_completed = false;
}

int current_time = 0;

roundRobin(processes, n, 2, 1, &current_time);
roundRobin(processes, n, 4, 2, &current_time);
fcfs(processes, n, 3, &current_time);

calculateTimes(processes, n);
return 0;
}
EXPERIMENT 4: Implementation of resource allocation graph (RAG).

Program:

#include <stdio.h>
#define MAX 100

// Function to print the Resource Allocation Graph (RAG)


void printRAG(int allocation[MAX][MAX], int request[MAX][MAX], int processes, int resources) {
printf("\nResource Allocation Graph (RAG):\n");

// Print Allocation Matrix


printf("\nAllocation Matrix:\n");
printf(" ");
for (int j = 0; j < resources; j++)
printf("R%d ", j);
printf("\n");

for (int i = 0; i < processes; i++) {


printf("P%d | ", i);
for (int j = 0; j < resources; j++) {
printf("%-3d ", allocation[i][j]);
}
printf("\n");
}

// Print Request Matrix


printf("\nRequest Matrix:\n");
printf(" ");
for (int j = 0; j < resources; j++)
printf("R%d ", j);
printf("\n");

for (int i = 0; i < processes; i++) {


printf("P%d | ", i);
for (int j = 0; j < resources; j++) {
printf("%-3d ", request[i][j]);
}
printf("\n");
}
}

int main() {
int processes, resources;
int allocation[MAX][MAX];
int request[MAX][MAX];

// Input number of processes and resources


printf("Enter the number of processes: ");
scanf("%d", &processes);
printf("Enter the number of resources: ");
scanf("%d", &resources);
// Input Allocation Matrix
printf("Enter the allocation matrix (P x R):\n");
for (int i = 0; i < processes; i++) {
for (int j = 0; j < resources; j++) {
scanf("%d", &allocation[i][j]);
}
}

// Input Request Matrix


printf("Enter the request matrix (P x R):\n");
for (int i = 0; i < processes; i++) {
for (int j = 0; j < resources; j++) {
scanf("%d", &request[i][j]);
}
}

// Display RAG
printRAG(allocation, request, processes, resources);
return 0;
}
EXPERIMENT 5: Implementation of Banker’s algorithm for Deadlock
Avoidance.
Theory:
The banker’s algorithm is a resource allocation and deadlock avoidance algorithm that tests for safety by
simulating the allocation for predetermined maximum possible amounts of all resources, then makes an
“s-state” check to test for possible activities, before deciding whether allocation should be allowed to
continue.
Following Data structures are used to implement the Banker’s Algorithm:
Let ‘n’ be the number of processes in the system and ‘m’ be the number of resources types.
Available :
• It is a 1-d array of size ‘m’ indicating the number of available resources of each type.
• Available[ j ] = k means there are ‘k’ instances of resource type Rj
Max :
• It is a 2-d array of size ‘n*m’ that defines the maximum demand of each process in a system.
• Max[ i, j ] = k means process Pi may request at most ‘k’ instances of resource type Rj.
Allocation :

It is a 2-d array of size ‘n*m’ that defines the number of resources of each type currently allocated
to each process.
• Allocation[ i, j ] = k means process Pi is currently allocated ‘k’ instances of resource type Rj
Need :
• It is a 2-d array of size ‘n*m’ that indicates the remaining resource need of each process.
• Need [ i, j ] = k means process Pi currently allocated ‘k’ instances of resource type Rj
• Need [ i, j ] = Max [ i, j ] – Allocation [ i, j ]
Allocationi specifies the resources currently allocated to process Pi and Needi specifies the additional
resources that process Pi may still request to complete its task.
Algorithm:
Banker’s algorithm consist of Safety algorithm and Resource request algorithm
Safety Algorithm
The algorithm for finding out whether or not a system is in a safe state can be described as follows:
1. Let Work and Finish be vectors of length ‘m’ and ‘n’ respectively.
Initialize: Work= Available
Finish [i]=false; for i=1,2,……,n
2. Find an i such that both
a) Finish [i]=false
b) Need_i<=work
if no such i exists goto step (4)
3. Work=Work + Allocation_i
Finish[i]= true
goto step(2)
4. If Finish[i]=true for all i,
then the system is in safe state.

(i) Perform Banker's algorithm when a request for R is made.


(ii) Compute Need[i,j]=Max[i,j]-Allocation[i,j].
(iii) Update accordingly.

Once the resources are allocated, check to see if the system state is safe. If unsafe, the process must wait
and the old resource-allocated state is restored.
Program:

#include <stdio.h>
#include <stdbool.h>

#define MAX_PROCESSES 10
#define MAX_RESOURCES 10

// Function to calculate the Need matrix


void calculateNeed(int need[MAX_PROCESSES][MAX_RESOURCES],
int max[MAX_PROCESSES][MAX_RESOURCES],
int allocation[MAX_PROCESSES][MAX_RESOURCES],
int processes, int resources) {
for (int i = 0; i < processes; i++) {
for (int j = 0; j < resources; j++) {
need[i][j] = max[i][j] - allocation[i][j];
}
}
}

// Function to check if the system is in a safe state


bool isSafe(int processes, int resources,
int available[MAX_RESOURCES],
int max[MAX_PROCESSES][MAX_RESOURCES],
int allocation[MAX_PROCESSES][MAX_RESOURCES]) {

int need[MAX_PROCESSES][MAX_RESOURCES];
calculateNeed(need, max, allocation, processes, resources);

bool finished[MAX_PROCESSES] = {false};


int work[MAX_RESOURCES];
for (int i = 0; i < resources; i++) {
work[i] = available[i];
}

while (true) {
bool found = false;

for (int i = 0; i < processes; i++) {


if (!finished[i]) {
bool canAllocate = true;

for (int j = 0; j < resources; j++) {


if (need[i][j] > work[j]) {
canAllocate = false;
break;
}
}
if (canAllocate) {
for (int j = 0; j < resources; j++) {
work[j] += allocation[i][j];
}
finished[i] = true;
found = true;
}
}
}

if (!found) {
break;
}
}

for (int i = 0; i < processes; i++) {


if (!finished[i]) {
return false;
}
}
return true;
}

// Main function
int main() {
int processes, resources;
int allocation[MAX_PROCESSES][MAX_RESOURCES];
int max[MAX_PROCESSES][MAX_RESOURCES];
int available[MAX_RESOURCES];

// Input
printf("Enter the number of processes: ");
scanf("%d", &processes);
printf("Enter the number of resources: ");
scanf("%d", &resources);

printf("Enter the Allocation Matrix (%d x %d):\n", processes, resources);


for (int i = 0; i < processes; i++) {
for (int j = 0; j < resources; j++) {
scanf("%d", &allocation[i][j]);
}
}

printf("Enter the Maximum Matrix (%d x %d):\n", processes, resources);


for (int i = 0; i < processes; i++) {
for (int j = 0; j < resources; j++) {
scanf("%d", &max[i][j]);
}
}

printf("Enter the Available Resources (%d):\n", resources);


for (int i = 0; i < resources; i++) {
scanf("%d", &available[i]);
}
// Check system safety
if (isSafe(processes, resources, available, max, allocation)) {
printf("\nThe system is in a SAFE state.\n");
} else {
printf("\nThe system is NOT in a safe state.\n");
}

return 0;
}
EXPERIMENT 6: Conversion of resource allocation graph (RAG) to wait
for graph (WFG) for each type of method used for storing graph.

Program:

#include <stdio.h>
#include <stdlib.h>

#define MAX 100

// --------------------- Structures ---------------------


typedef struct Node {
int vertex;
struct Node* next;
} Node;

typedef struct {
int from, to;
} Edge;

// --------------------- Global Variables ---------------------


int n, m, total; // n = processes, m = resources
int adjMatrix[MAX][MAX]; // For method 1
Node* adjList[MAX]; // For method 2
Node* wfgList[MAX]; // For method 2
Edge ragEdges[MAX]; // For method 3
Edge wfgEdges[MAX]; // For method 3
int edgeCount = 0, wfgEdgeCount = 0;

// --------------------- Utility Functions ---------------------


Node* createNode(int v) {
Node* node = (Node*)malloc(sizeof(Node));
node->vertex = v;
node->next = NULL;
return node;
}

void addEdgeToList(Node* graph[], int src, int dest) {


Node* node = createNode(dest);
node->next = graph[src];
graph[src] = node;
}
// --------------------- Method 1: Adjacency Matrix ---------------------
void convertMatrixToWFG(int wfg[MAX][MAX]) {
for (int i = 0; i < n; i++) {
for (int j = n; j < total; j++) {
if (adjMatrix[i][j]) {
for (int k = 0; k < n; k++) {
if (adjMatrix[j][k]) {
wfg[i][k] = 1;
}
}
}
}
}
}

void printMatrix(int mat[MAX][MAX], int size) {


for (int i = 0; i < size; i++) {
printf("P%d: ", i);
for (int j = 0; j < size; j++) {
if (mat[i][j])
printf("P%d ", j);
}
printf("\n");
}
}

// --------------------- Method 2: Adjacency List ---------------------


void convertListToWFG() {
for (int i = 0; i < n; i++) {
Node* req = adjList[i];
while (req) {
int r = req->vertex;
Node* alloc = adjList[r];
while (alloc) {
int p2 = alloc->vertex;
addEdgeToList(wfgList, i, p2);
alloc = alloc->next;
}
req = req->next;
}
}
}

void printAdjList(Node* graph[], int size) {


for (int i = 0; i < size; i++) {
printf("P%d: ", i);
Node* temp = graph[i];
while (temp) {
printf("P%d ", temp->vertex);
temp = temp->next;
}
printf("\n");
}
}
// --------------------- Method 3: Edge List ---------------------
void convertEdgeListToWFG() {
for (int i = 0; i < edgeCount; i++) {
int from = ragEdges[i].from;
int to = ragEdges[i].to;

if (from < n && to >= n) {


for (int j = 0; j < edgeCount; j++) {
if (ragEdges[j].from == to && ragEdges[j].to < n) {
wfgEdges[wfgEdgeCount++] = (Edge){from, ragEdges[j].to};
}
}
}
}
}

void printEdgeList(Edge edges[], int count) {


for (int i = 0; i < count; i++) {
printf("P%d -> P%d\n", edges[i].from, edges[i].to);
}
}

// --------------------- Main Function ---------------------


int main() {
int choice;

printf("Enter number of processes and resources: ");


scanf("%d %d", &n, &m);
total = n + m;

printf("\nChoose Method to use:\n");


printf("1. Adjacency Matrix\n");
printf("2. Adjacency List\n");
printf("3. Edge List\n");
printf("Enter choice (1/2/3): ");
scanf("%d", &choice);

if (choice == 1) {
printf("Enter Adjacency Matrix (%d x %d):\n", total, total);
for (int i = 0; i < total; i++) {
for (int j = 0; j < total; j++) {
scanf("%d", &adjMatrix[i][j]);
}
}

int wfg[MAX][MAX] = {0};


convertMatrixToWFG(wfg);

printf("\nWait-For Graph (Adjacency Matrix):\n");


printMatrix(wfg, n);

} else if (choice == 2) {
int edges;
printf("Enter number of edges in RAG: ");
scanf("%d", &edges);
printf("Enter edges (from to):\n");
for (int i = 0; i < edges; i++) {
int from, to;
scanf("%d %d", &from, &to);
addEdgeToList(adjList, from, to);
}

convertListToWFG();

printf("\nWait-For Graph (Adjacency List):\n");


printAdjList(wfgList, n);

} else if (choice == 3) {
printf("Enter number of edges in RAG: ");
scanf("%d", &edgeCount);

printf("Enter edges (from to):\n");


for (int i = 0; i < edgeCount; i++) {
scanf("%d %d", &ragEdges[i].from, &ragEdges[i].to);
}

convertEdgeListToWFG();

printf("\nWait-For Graph (Edge List):\n");


printEdgeList(wfgEdges, wfgEdgeCount);
} else {
printf("Invalid choice!\n");
}

return 0;
}
Experiment7: Implementation of contiguous allocation techniques:
a) Worst-Fit b) Best- Fit c) First- Fit
Theory:
One of the simplest methods for memory allocation is to divide memory into several fixed-sized
partitions. Each partition may contain exactly one process. In this multiple-partition method, when a
partition is free, a process is selected from the input queue and is loaded into the free partition. When the
process terminates, the partition becomes available for another process. The operating system keeps a
table indicating which parts of memory are available and which are occupied. Finally, when a process
arrives and needs memory, a memory section large enough for this process is provided. When it is time to
load or swap a process into main memory, and if there is more than one free block of memory of
sufficient size, then the operating system must decide which free block to allocate. Best-fit strategy
chooses the block that is closest in size to the request. First-fit chooses the first available block that is
large enough. Worst-fit chooses the largest available block.

First Fit:
In the first fit approach is to allocate the first free partition or hole large enough which can
accommodate the process. It finishes after finding the first suitable free partition.
Best Fit:
The best fit deals with allocating the smallest free partition which meets the requirement of the
requesting process. This algorithm first searches the entire list of free partitions and considers the
smallest hole that is adequate. It then tries to find a hole which is close to actual process size needed.
Worst fit:
In worst fit approach is to locate largest available free portion so that the portion left will be big
enough to be useful. It is the reverse of best fit.

Algorithm:
First Fit
1. Get no. of Processes and no. of blocks.
2. After that get the size of each block and process requests.
3. Now allocate processes
if(block size >= process size)
//allocate the process
else
//move on to next block
4. Display the processes with the blocks that are allocated to a respective process.
5. Stop.
Best Fit
1. Get no. of Processes and no. of blocks.
2. After that get the size of each block and process requests.
3. Then select the best memory block that can be allocated using the above definition.
4. Display the processes with the blocks that are allocated to a respective process.
5. Value of Fragmentation is optional to display to keep track of wasted memory.
6. Stop.
Worst Fit
1. Get no. of Processes and no. of blocks.
2. After that get the size of each block and process requests.
3. Then select the largest available memory block that can be allocated using the above definition.
4. Display the processes with the blocks that are allocated to a respective process.
5. Value of Fragmentation is optional to display to keep track of wasted memory.
6. Stop.
Program:
#include <stdio.h>

// Worst-Fit allocation: allocate process to largest block that fits


void worstFit(int block_sizes[], int num_blocks, int process_size) {
int max_idx = -1;
for (int i = 0; i < num_blocks; i++) {
if (block_sizes[i] >= process_size) {
if (max_idx == -1 || block_sizes[i] > block_sizes[max_idx]) {
max_idx = i;
}
}
}
if (max_idx != -1) {
printf("Process of size %d allocated to block %d (Remaining block size: %d)\n", process_size,
max_idx, block_sizes[max_idx] - process_size);
block_sizes[max_idx] -= process_size;
} else {
printf("Process of size %d could not be allocated (No suitable block found)\n", process_size);
}
}

// Best-Fit allocation: allocate process to smallest block that fits


void bestFit(int block_sizes[], int num_blocks, int process_size) {
int min_idx = -1;
for (int i = 0; i < num_blocks; i++) {
if (block_sizes[i] >= process_size) {
if (min_idx == -1 || block_sizes[i] < block_sizes[min_idx]) {
min_idx = i;
}
}
}
if (min_idx != -1) {
printf("Process of size %d allocated to block %d (Remaining block size: %d)\n", process_size,
min_idx, block_sizes[min_idx] - process_size);
block_sizes[min_idx] -= process_size;
} else {
printf("Process of size %d could not be allocated (No suitable block found)\n", process_size);
}
}

// First-Fit allocation: allocate process to first block that fits


void firstFit(int block_sizes[], int num_blocks, int process_size) {
for (int i = 0; i < num_blocks; i++) {
if (block_sizes[i] >= process_size) {
printf("Process of size %d allocated to block %d (Remaining block size: %d)\n", process_size, i,
block_sizes[i] - process_size);
block_sizes[i] -= process_size;
return;
}
}
printf("Process of size %d could not be allocated (No suitable block found)\n", process_size);
}
int main() {
int num_blocks, num_processes;

printf("Enter number of blocks: ");


scanf("%d", &num_blocks);

int block_sizes[num_blocks];
printf("Enter block sizes: ");
for (int i = 0; i < num_blocks; i++) {
scanf("%d", &block_sizes[i]);
}

printf("Enter number of processes: ");


scanf("%d", &num_processes);

int process_sizes[num_processes];
printf("Enter process sizes: ");
for (int i = 0; i < num_processes; i++) {
scanf("%d", &process_sizes[i]);
}

int choice;
printf("Enter allocation technique (1-WorstFit, 2-BestFit, 3-FirstFit): ");
scanf("%d", &choice);

printf("\nAllocation results:\n");
switch (choice) {
case 1:
for (int i = 0; i < num_processes; i++) {
worstFit(block_sizes, num_blocks, process_sizes[i]);
}
break;
case 2:
for (int i = 0; i < num_processes; i++) {
bestFit(block_sizes, num_blocks, process_sizes[i]);
}
break;
case 3:
for (int i = 0; i < num_processes; i++) {
firstFit(block_sizes, num_blocks, process_sizes[i]);
}
break;
default:
printf("Invalid choice\n");
}

return 0;
}
Experiment 8: Implement the solution for Bounded Buffer (producer-
consumer) problem using inter process communication techniques-
Semaphores.
Program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/wait.h>

#define BUFFER_SIZE 5

// Shared memory structure


typedef struct {
int buffer[BUFFER_SIZE];
int front;
int rear;
sem_t full;
sem_t empty;
sem_t mutex;
} shared_data_t;

void producer(shared_data_t *shared, int item) {


sem_wait(&shared->empty);
sem_wait(&shared->mutex);

shared->buffer[shared->rear] = item;
shared->rear = (shared->rear + 1) % BUFFER_SIZE;

sem_post(&shared->mutex);
sem_post(&shared->full);
}

int consumer(shared_data_t *shared) {


int item;

sem_wait(&shared->full);
sem_wait(&shared->mutex);

item = shared->buffer[shared->front];
shared->front = (shared->front + 1) % BUFFER_SIZE;

sem_post(&shared->mutex);
sem_post(&shared->empty);

return item;
}
int main() {
int num_items;
printf("Enter the number of items to produce and consume: ");
scanf("%d", &num_items);
// Allocate shared memory
shared_data_t *shared = mmap(NULL, sizeof(shared_data_t),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (shared == MAP_FAILED) {
perror("mmap");
exit(1);
}

// Initialize shared variables


shared->front = 0;
shared->rear = 0;
sem_init(&shared->full, 1, 0); // 1 means shared between processes
sem_init(&shared->empty, 1, BUFFER_SIZE);
sem_init(&shared->mutex, 1, 1);

pid_t producer_pid = fork();


if (producer_pid == 0) {
// Producer process
for (int i = 1; i <= num_items; i++) {
producer(shared, i);
printf("Produced: %d\n", i);
sleep(1);
}
exit(0);
}

pid_t consumer_pid = fork();


if (consumer_pid == 0) {
// Consumer process
for (int i = 1; i <= num_items; i++) {
int item = consumer(shared);
printf("Consumed: %d\n", item);
sleep(1);
}
exit(0);
}

// Parent waits for children to finish


wait(NULL);
wait(NULL);

// Cleanup semaphores and shared memory


sem_destroy(&shared->full);
sem_destroy(&shared->empty);
sem_destroy(&shared->mutex);
munmap(shared, sizeof(shared_data_t));

return 0;
}
Experiment 9: Implement the solutions for Readers-Writers problem
using inter process communication technique –Semaphore.
Program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <semaphore.h>
#include <sys/mman.h>
#include <sys/wait.h>

// Shared memory structure


typedef struct {
int data; // shared data
int read_count; // number of readers reading
sem_t mutex; // protects read_count
sem_t w_mutex; // ensures exclusive writer access
} shared_data_t;

void writer(shared_data_t *shared, int value) {


sem_wait(&shared->w_mutex);
shared->data = value;
printf("Writer wrote %d\n", value);
sem_post(&shared->w_mutex);
}

void reader(shared_data_t *shared) {


sem_wait(&shared->mutex);
shared->read_count++;
if (shared->read_count == 1) {
sem_wait(&shared->w_mutex); // first reader locks writers out
}
sem_post(&shared->mutex);

// Reading the data


printf("Reader read %d\n", shared->data);

sem_wait(&shared->mutex);
shared->read_count--;
if (shared->read_count == 0) {
sem_post(&shared->w_mutex); // last reader lets writers in
}
sem_post(&shared->mutex);
}

int main() {
int num_writers, num_readers;

printf("Enter number of writers: ");


scanf("%d", &num_writers);
printf("Enter number of readers: ");
scanf("%d", &num_readers);
// Allocate shared memory
shared_data_t *shared = mmap(NULL, sizeof(shared_data_t),
PROT_READ | PROT_WRITE,
MAP_SHARED | MAP_ANONYMOUS, -1, 0);
if (shared == MAP_FAILED) {
perror("mmap");
exit(1);
}

// Initialize shared data


shared->data = 0;
shared->read_count = 0;
sem_init(&shared->mutex, 1, 1); // shared between processes
sem_init(&shared->w_mutex, 1, 1);

// Create writer processes


for (int i = 0; i < num_writers; i++) {
pid_t pid = fork();
if (pid == 0) {
// Writer process: write its index+1
writer(shared, i + 1);
exit(0);
}
}

// Create reader processes


for (int i = 0; i < num_readers; i++) {
pid_t pid = fork();
if (pid == 0) {
// Reader process
reader(shared);
exit(0);
}
}

// Wait for all children


for (int i = 0; i < num_writers + num_readers; i++) {
wait(NULL);
}

// Cleanup
sem_destroy(&shared->mutex);
sem_destroy(&shared->w_mutex);
munmap(shared, sizeof(shared_data_t));

return 0;
Experiment 10: Implementation of System calls.
THEORY:
This code implements a menu-driven program that allows the user to choose from the
following system calls:
- Create Process (fork)

- Execute Command (execv)

- Wait for Process (wait)

- Exit

Program:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main() {
int choice, status;
pid_t pid;

while (1) {
printf("\nSystem Calls Menu:\n");
printf("1. Create Process (fork)\n");
printf("2. Execute Command (execv)\n");
printf("3. Wait for Process (wait)\n");
printf("4. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
pid = fork();
if (pid == 0) {
// Child process
printf("Child process (PID: %d) created.\n", getpid());
exit(0); // Ensure child exits
} else if (pid > 0) {
// Parent process
waitpid(pid, &status, 0); // Wait for child to finish
printf("Parent process (PID: %d) continued after child.\n", getpid());
} else {
perror("fork failed");
}
break;
case 2: {
char *args[] = {"/bin/ls", "-l", NULL};
execv("/bin/ls", args);
perror("execv failed"); // only reached if execv fails
break;
}
case 3:
pid = wait(&status);
if (pid > 0) {
printf("Process %d terminated with status %d\n", pid, WEXITSTATUS(status));
} else {
perror("wait failed");
}
break;
case 4:
exit(0);
default:
printf("Invalid choice\n");
}
}
return 0;
}

You might also like