OS Workbook Answers-2
OS Workbook Answers-2
Aim/Objective:
The aim of learning basic commands with examples in operating systems is to familiarize, oneself with the
fundamental commands and their functionalities. These commands allow users to interact with the operating
system and perform various tasks efficiently.
Description:
Basic commands in operating systems refer to the essential commands used to interact with the operating system
via the command-line interface (CLI) or terminal. These commands allow users to perform various tasks, such as
navigating directories, managing files and processes, accessing system information, and configuring system
settings.
Pre-Requisites:
● General idea of what an Operating System is (an interface between User and Hardware)
● How users communicate with the hardware? (Using commands)
● What is a Shell?
● How commands can be executed (through Shell)?
Pre-Lab:
BASICCOMMANDS FUNCTIONALITY
Man
display information about users who are currently logged into the system
Who
Make directories
mkdir
to concatenate and display the contents of one or more text files to the terminal
cat
used to create empty files and update the timestamps of existing files
Touch
used for moving files and directories from one location to another
mv
used for sorting the lines of text files or the contents of files in various ways,
such as alphabetically or numerically
sort
grep
used for changing the permissions (read, write, execute) of files and directories.
chmod
Head
cal
In-Lab:
Problem Description:
Stanley wants to get started with terminal commands in Linux.
Help him out toper form the following set of statements:
a. He wants to know his current directory that he is working with, in the system. After identifying
the current directory, he desires to create a folder called Marvel.
Ans:
➔ Pwd
➔ mkdir Marvel
b. Now, he wants to list out all the Avengers of the “Marvel” universe. He adds the following
set of Avengers to Avengers.txt:
i. Ironman
ii. Captain America
iii. Thor
iv. Hulk
v. Black widow
Ans:
➔ cd Marvel
➔ nano Avengers.txt
➔ Ironman
Captain America
Thor
Hulk
Black Widow
➔ cat Avengers.txt
c. After adding the names displayed above check whether the names are inserted or not.
Ans:
➔ cd Marvel
➔ cat Avengers.txt
➔ Ironman
Captain America
Thor
Hulk
Black Widow
d. Stanley wants to relocate the file (Avengers.txt) from Marvel to Desktop, after relocating the file
give all the permissions to user and group and give only read permission to others.
Verify the permissions when done.
➔ Ans: cd ~/Marvel
➔ mv Avengers.txt ~/Desktop
➔ chmod 664 ~/Desktop/Avengers.txt
➔ ls -l ~/Desktop/Avengers.txt
➔ -rw-rw-r-- 1 user group 0 Oct 10 10:00 Avengers.txt
e. Stanley now wants to add more avengers to the Marvel, Add the following set of new avengers to
Avengers.txt.
1. Black panther
2. Groot
3. Captain marvel
4. Spiderman
➔ Ans: cd ~/Marvel
➔ nano Avengers.txt
➔ Black Panther
Groot
Captain Marvel
Spiderman
➔ cat Avengers.txt
f. Sort the names of the file in lexicographical order and export the result to Sortedavengers.txt and
display the content of it.
Ans:
➔ cd ~/Marvel
➔ sort Avengers.txt > Sortedavengers.txt
➔ cat Sortedavengers.txt
g. Now, Stanley sends the first avenger from Sortedavengers.txt to visit Wakanda.txt
(another file in the desktop) as a part of mission to kill Thanos. After sending, move the
wakanda.txt to marvel.
Ans:
➔ cd ~/Desktop
➔ head -n 1 Sortedavengers.txt >> Wakanda.txt
➔ mv Wakanda.txt ~/Marvel
POST LAB
uname
The umount command allows you to safely and cleanly detach a mounted
filesystem from a mount point, making the filesystem inaccessible until it is
mounted again.
umount
more command is used to view the contents of text files one screen at a time
more
the less command is used as a text viewer, similar to the more command. It
allows users to view the contents of text files one screen at a time, navigate
less through the file, and search for text
the diff command is used to compare the contents of two text files and display
the differences between them
diff
ln
"rm" is a command used to remove files and directories. It stands for "remove."
rm
cp
"rmdir" command is used to remove (delete) empty directories. It stands for "remove
directory."
rmdir
the "gzip" command is used to compress and decompress files using the GNU Zip (gzip)
compression algorithm.
gzip
the "find" command is a powerful tool for searching and locating files and directories in
a directory hierarchy.
find
“talent” does not have a specific technical meaning. The concept of talent is related to
individuals, skills, and abilities rather than the OS itself.
telnet
NSlookup is a command-line tool that allows you to query DNS servers and
retrieve information about domain names, IP addresses, and other DNS-
related data.
nslookup
the "df" command is used to display information about the disk space usage on the
system. It provides details about the filesystems, their capacity, usage, and available
df space
The "du" command in the operating system is used to display disk usage statistics for
files and directories.
du
The "free" command in the operating system is used to display information about the
system's memory usage and availability.
free
The "top" command in the operating system is used to monitor real-time system
performance, including CPU, memory, and process usage.
top
The "ps" command in the operating system is used to list currently running processes.
ps
The "kill" command in the operating system is used to terminate or signal processes,
allowing you to stop running programs or manage their behavior.
kill
4. Explain the concept of process termination and the role of the exit() system call.
Process termination refers to the end of a process's execution. The "exit()" system call is used by a
process to indicate its termination and return an exit status to its parent process, allowing for
clean resource cleanup and status reporting.
5. What is the purpose of the fork() system call in the process API?
The "fork()" system call is used to create a new process in the process API, effectively duplicating
the calling process, allowing for concurrent execution and multi-processing.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Aim/Objective:
The objective of using file operations is to provide a way to manage and manipulate files stored on storage devices
such as hard drives, solid-state drives, or network drives. System calls in Unix are used for file system control, process
control, inter-process communication etc. Access to the Unix kernel is only available through these system calls.
Generally, system calls are like function calls, the only difference is that they remove the control from the user
process.
Description:
File operations in operating systems refer to the various actions or tasks that can be performed on files within a
file system. These operations are essential for managing files and manipulating their contents.
Pre-Requisites:
● Creation of a new file (fopen with attributes as “a” or “a+” or “w” or “w++”)
● Opening an existing file (fopen) and Reading from a file (fscanf, fgets or fgetc)
● Writing to a file int fputc, fputs
● Moving to a specific location in a file (fseek, rewind) and closing a file(fclose)
● Basic system calls on files.
3 getc()
5 fscanf() The "fscanf()" function in C is used to read formatted data from an open file.
6 fprintf() The "fprintf()" function in C is used to write formatted data to an open file.
7 gets() The "gets()" function in C is used to read a line of text from the standard input
(stdin).
8 puts() The "puts()" function in C is used to write a line of text to the standard output
(stdout).
9 fseek() The "fseek()" function is used to set the file position indicator within a file in C
programming.
10 ftell() The "ftell()" function in C is used to get the current file position indicator's
offset within an open file.
11 rewind() The "rewind()" function in C is used to move the file position indicator to the
beginning of an open file.
13 chdir() The "chdir()" function is used to change the current working directory in C
programming.
14 chmod() The "chmod()" function is used to change the file permissions or access mode
of a file in Unix-like operating systems.
15 chown() The "chown()" function is used to change the ownership of a file or directory
in Unix-like operating systems.
16 kill() The "kill()" system call in Unix-like operating systems is used to send a signal
to a process, which can be used to terminate or control the process.
17 link() The "link()" function is used to create a hard link to a file in Unix-like
operating systems.
18 open() The "open()" function is used to open a file or create a new file in C
programming.
19 pause() The "pause()" function is used to make a process pause its execution until it
receives a signal.
20 exit() The "exit()" function is used to terminate a C program or process and return
an exit status to the operating system.
21 alarm() The "alarm()" function is used to set a timer that generates a signal after a
specified time period in Unix-like operating systems.
22 fork() The "fork()" system call is used to create a new process in Unix-like operating
systems, duplicating the calling process.
In lab task
1. Writea C program that reads file.txt line by line and prints the first 10-digit number in the given file (digits
should be continuous), If not found then print the first 10 characters excluding numbers.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
int main() {
FILE *file = fopen("file.txt", "r");
if (file == NULL) {
printf("File not found or could not be opened.\n");
return 1;
}
char line[1024];
while (fgets(line, sizeof(line), file)) {
char *ptr = line;
if (result_index == 10) {
result[10] = '\0';
printf("First 10-digit number: %s\n", result);
break;
}
}
if (feof(file)) {
// No 10-digit number found, print the first 10 non-digit characters
fseek(file, 0, SEEK_SET);
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 15 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
char first_10_chars[11];
int char_index = 0;
while (char_index < 10 && (first_10_chars[char_index] = fgetc(file)) != EOF) {
if(!isdigit(first_10_chars[char_index])) {
char_index++;
}
}
first_10_chars[char_index] = '\0';
printf("First 10 non-digit characters: %s\n", first_10_chars);
}
fclose(file);
return 0;
}
2. Writea C program that saves 10 random numbers to a file, using own “rand.h” header file which
contains your own random () function.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() {
// Initialize the random number generator with the current time
srand(time(NULL));
1.Write commands/code in the space provided for each of the questions below:
a. Use the cut command on the output of along directory listing in order to display only the
file permissions. Then pipe this output to sort and unique to filter out any double lines.
Then use the wcto count the different permission types in this directory.
Ans.
ls -l | cut -d ' ' -f 1 | sort | uniq | wc -l
c. Create a new Directory LABTEMP and Copy the files from /var/log into
it and display the files whose first alphabet is consonant that do not
begin with upper caseletters that has an extension of exactly three
characters.
Ans.
mkdir LABTEMP
cp /var/log/* LABTEMP/
ls LABTEMP/ | grep '^[^A-Z][a-z]\{2\}\.[a-z]\{3\}$'
d. Find how many hours has the system been
running?
Ans. uptime -p
/
|-- bin
|-- boot
|-- dev
|-- etc
f. Create a file using cat and find the number oflines, words and characters
in it.
Ans.
➔ cat > mytextfile.txt
➔ wc -l mytextfile.txt
➔ wc -w mytextfile.txt
➔ wc -m mytextfile.txt
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
j. What happens when you enter a shell meta character * with the echo
command.
Ans. echo *.txt
This means the * will be replaced with a list of filenames or paths that match the specified pattern.
The result of the command wc infile > newfile will be to count the number of lines, words, and characters in the
file named "infile" and save the count results in a new file called "newfile."
c. Redirect standard output and standard error streams for cat command with an example
in one step.
Ans.
b. Zip a group of files (ERROR, new file, in file, passwd, group) and unzip
them
Ans. zip myarchive.zip ERROR "new file" "in file" passwd group
unzip myarchive.zip
file3.txt
unzip myfiles.zip
n. Create a file called "hello.txt" in your home directory using the command.
cat-u>hello.txt.
Ask your partner to change into your home directory and
run tail -f hello.txt.
Now type sever allies into hello.txt. What appears on your partner's screen?
Ans. If you run this command to create "hello.txt" in your home directory, your partner, after changing to
your home directory and running tail -f hello.txt, will see the text "server allies" on their screen as soon as you
type it into the "hello.txt" file in your home directory. The -f option with tail is used to follow the file in real-time,
so any changes made to the file will be immediately displayed on your partner's screen.
o. Change the unmask value and identify the difference with the earlier using
touch, ls–l
Ans. Umask
umask 0002
touch newfile.txt
ls -l newfile.txt
create a new file using the touch command
Use the ls -l command to list the file and observe the permissions
p. Save the output of the who command in a file, display it, display lines count on the
terminal.
Ans. who > who_output.txt
cat who_output.txt
wc -l who_output.txt
who > who_output.txt && cat who_output.txt && wc -l who_output.txt
q. Two or more command scan be combined, and the aggregate output can send to an output file. How
to perform it. Write a sample command line.
r. Display all files in the current directory that begins with "a", "b" or "c" and are at least 5
characters long.
s. Display all files in the current directory that begin and with don't end
with"x", "y" or "z"
Ans. ls | grep -E '^[^xyz].*[^xyz]$'
t. Display all files in the current directory that begin with the letter D and have three
more characters.
Ans. ls | grep -E '^D...'
File operations in an operating system include file creation, reading, writing, deletion, and
management of permissions and attributes. These operations enable users and applications to create,
access, modify, and manage files. They are fundamental for effective file management in the system.
Operating systems provide the necessary tools and system calls to perform these actions on files.
File creation in an operating system involves checking available space, setting file metadata, allocating
data blocks, and creating a directory entry. The process ensures a new file is established with its
attributes, storage allocation, and accessibility within the file system.
File writing in an operating system involves data transfer from memory to storage, file pointer
management, data update, and metadata updates. This operation enables users and applications to
modify file contents while ensuring data integrity and consistency.
5 . What is the role of buffering in file operations, and how does it affect performance?
Buffering in file operations involves temporarily storing data in memory buffers to
reduce costly disk access. It improves performance by batching I/O operations, enabling
asynchronous I/O, and acting as a cache for frequently accessed data. However,
excessive buffering can increase memory usage, and a balance between memory
consumption and performance is necessary for optimal file operations.
File operations are actions that involve creating, accessing, modifying, and managing files within
a computer's file system, including tasks like reading, writing, and setting permissions. They are
essential for data storage and retrieval in computing.
• Differentiate between system call and library call?
System calls are low-level requests for kernel services that require a privilege level change, while
library calls are higher-level functions provided by user-level libraries that operate in user mode,
abstracting and simplifying common tasks.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Aim/Objective:
The objective of Process API is to provide a set of functions and tools that allow programmers to manage
and control processes within the operating system environment.
Description:
The Process API typically includes functions for creating new processes, terminating existing processes,
querying information about processes, managing process attributes (such as process ID, parent process ID,
and process state), and controlling process execution.
Pre-Requisites:
Pre-Lab:
1.Write brief description and prototypes in the space given below for the following process
subsystem call EX: -“$man <system call name>”
1. fork()
`fork()` is a system call in Unix-like operating systems used to create a new process (child
process) that is a copy of the calling process (parent process).
`exit()` is a system call in Unix-like operating systems used to terminate the calling process and return an
exit status code to the parent process.
4. shmget()
`shmget()` is a system call in Unix-like operating systems used to create or access a System
V shared memory segment by specifying a key and various flags.
5. wait()
`wait()` is a system call in Unix-like operating systems used to make a parent process wait
for the termination of its child processes and retrieve their exit status.
6. sleep()
`sleep()` is a system call in Unix-like operating systems used to pause the execution of a
process for a specified number of seconds.
7. exec()
`exec()` is a system call in Unix-like operating systems used to replace the current
process's code and memory with a new program, typically used to run another program
from within the current process.
8. waitpid()
`waitpid()` is a system call in Unix-like operating systems used to make a parent process
wait for the termination of a specific child process identified by its process ID (PID) and
retrieve the child process's exit status.
9. _exit()
`_exit()` is a system call in Unix-like operating systems used to terminate the calling process
immediately without performing any standard cleanup or atexit handlers.
10. Opendir()
`opendir()` is a system call in Unix-like operating systems used to open and read
directories. It is often used to list the contents of a directory in a C/C++ program.
11. Readdir()
`readdir()` is a system call in Unix-like operating systems used to read the contents of an open
directory, typically used in combination with `opendir()` to list the files and subdirectories
within a directory.
`execlp()`, `execvp()`, `execv()`, `execl()`, and `execv()` are system calls in Unix-like operating systems used to
execute a new program by replacing the current process's code and memory with the code of the new
program, and they are typically used with different argument-passing conventions and path resolution
methods.
In Lab:
1. write a program for implementing process management using the following system calls of
UNIX operating system: fork, exec, getpid, exit, wait, close.
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t child_pid;
int status;
if (child_pid < 0) {
perror("Fork failed");
return 1;
}
if (child_pid == 0) {
// This code runs in the child process
printf("Child process: My PID is %d\n", getpid());
// If execl fails
perror("Exec failed");
return 1;
} else {
// This code runs in the parent process
printf("Parent process: My PID is %d, Child PID is %d\n", getpid(), child_pid);
return 0;
}
1.To write a program for implementing Directory management using the following system calls of UNIX
operating system: opendir, readdir
#include <stdio.h>
#include <stdlib.h>
#include <dirent.h>
int main() {
DIR *dir;
struct dirent *entry;
if (dir == NULL) {
perror("opendir");
return 1;
}
return 0;
}.
2 Write a program for implementing process management using the following system calls of UNIX
operating system: fork, exec, getpid, exit, wait, close.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t child_pid;
int status;
if (child_pid < 0) {
perror("Fork failed");
return 1;
}
if (child_pid == 0) {
// This code runs in the child process
printf("Child process: My PID is %d\n", getpid());
// If execl fails
perror("Exec failed");
return 1;
} else {
// This code runs in the parent process
printf("Parent process: My PID is %d, Child PID is %d\n", getpid(), child_pid);
3 T -series creates a text document (song.txt) that contains lyrics of a song. They want to know how many
lines and words are present in the song.txt. They want to utilize Linux directions and system calls to
accomplish their objective. Help T -series to finish their task by utilizing a fork system call. Print the
number of lines in song.txt using the parent process and print the number of words in it using the child
process.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
int main() {
pid_t child_pid;
int status;
if (child_pid < 0) {
perror("Fork failed");
return 1;
}
if (child_pid == 0) {
// This code runs in the child process
FILE *file = fopen("song.txt", "r");
if (file == NULL) {
perror("Failed to open song.txt");
exit(1);
}
int wordCount = 0;
char ch;
int inWord = 0;
fclose(file);
} else {
// This code runs in the parent process
wait(&status);
if (WIFEXITED(status)) {
printf("Parent process: Child process exited with status %d\n", WEXITSTATUS(status));
} else {
printf("Parent process: Child process did not exit normally\n");
}
if (file == NULL) {
perror("Failed to open song.txt");
exit(1);
}
int lineCount = 0;
char ch;
fclose(file);
}
return 0;
}
POST LAB
1. Write a program to display user id, group id, parent id, process id.
#include <stdio.h>
#include <unistd.h>
int main() {
uid_t uid = getuid(); // User ID
gid_t gid = getgid(); // Group ID
pid_t ppid = getppid(); // Parent Process ID
pid_t pid = getpid(); // Process ID
return 0;
}
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Before forking: This is the parent process (PID: %d)\n", getpid());
if (child_pid < 0) {
perror("Fork failed");
return 1;
}
if (child_pid == 0) {
// This code runs in the child process
printf("In the child process (PID: %d), after forking\n", getpid());
} else {
// This code runs in the parent process
printf("In the parent process (PID: %d), after forking child process (Child PID: %d)\n", getpid(), child_pid);
}
return 0;
}
3.Write a program to display child process id, parent process id, process id before and after forking.
#include <stdio.h>
#include <unistd.h>
int main() {
printf("Before forking: This is the process (PID: %d) with parent (PPID: %d)\n", getpid(), getppid());
if (child_pid < 0) {
perror("Fork failed");
return 1;
}
if (child_pid == 0) {
// This code runs in the child process
printf("In the child process (PID: %d) with parent (PPID: %d) after forking\n", getpid(), getppid());
} else {
// This code runs in the parent process
printf("In the parent process (PID: %d) with child (Child PID: %d) after forking\n", getpid(), child_pid);
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
int main() {
pid_t child_pid;
if (child_pid < 0) {
perror("Fork failed");
return 1;
}
if (child_pid == 0) {
// This code runs in the child process
printf("Child process (PID: %d) sleeping for 5 seconds...\n", getpid());
// Sleep for a short time to ensure the child process starts sleeping
sleep(1);
printf("Parent process: Killed the child process (Child PID: %d)\n", child_pid);
}
return 0;
}
#include <stdio.h>
#include <unistd.h>
int main() {
pid_t child_pid;
if (child_pid < 0) {
perror("Fork failed");
return 1;
}
if (child_pid == 0) {
// This code runs in the child process
printf("Child process (PID: %d) is running\n", getpid());
} else {
// This code runs in the parent process
printf("Parent process (PID: %d) created a child process (Child PID: %d)\n", getpid(), child_pid);
}
return 0;
}
A Process Control Block (PCB) stores essential information about a process, including its state, program counter,
and resource allocation, enabling the operating system to manage and switch between processes efficiently.
A process in the context of an operating system is an independent program in execution, including its code, data,
and resources, managed and scheduled by the OS.
4. Explain the concept of process termination and the role of the exit() system call.
Process termination is the ending of a process's execution. The `exit()` system call is used to terminate a process,
and it performs cleanup tasks, releases resources, and returns an exit status to the parent process, indicating the
result of the execution.
5. What is the purpose of the fork() system call in the process API?
The `fork()` system call in the process API is used to create a new process (child process) that is a copy of the
calling process (parent process). This allows parallel execution of code and is a fundamental mechanism for
creating new processes in Unix-like operating systems.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Aim/Objective:
The objective is to efficiently utilize the available system resources and ensure fair and timely execution
of processes. Process scheduling involves determining which process should be allocated the CPU (Central
Processing Unit) at any given time, considering factors such as priority, fairness, and efficiency.
Description:
The primary objective of process scheduling is to make the best possible use of the CPU resources
available in the system. The scheduling algorithm aims to keep the CPU busy by constantly assigning it to
a process for execution. By minimizing idle time and maximizing CPU utilization, the system can achieve
optimal performance and throughput.
Pre-Requisites:
Pre-Lab:
SCHEDULING FUNCTIONALITY
ALGORITHMS
The Most Frequently Used (MFU) algorithm aims to replace the page that has
been referenced most frequently in the past, with the idea of retaining pages in
memory that are still frequently accessed.
First Come First
Scheduling
The Most Frequently Used (MFU) algorithm replaces the page that has been
referenced most frequently in the past, aiming to retain frequently accessed pages
in memory.
Shortest Job First
Scheduling
Optimal Page Replacement replaces the page that won't be used for the longest
Shortest Remaining time in the future, while Least Recently Used (LRU) replaces the page that hasn't
Time First been used for the longest time in the past.
Scheduling
Swapping involves moving an entire process in and out of main memory, while
paging moves individual pages or blocks of a process between main memory and
secondary storage, offering finer-grained control over memory allocation.
Priority Scheduling
In-Lab:
#include <stdio.h>
struct Process {
int processID;
int arrivalTime;
int burstTime;
};
int main() {
int n;
completionTime += processes[i].burstTime;
float waitingTime = completionTime - processes[i].arrivalTime - processes[i].burstTime;
totalWaitingTime += waitingTime;
return 0;
}
#include <stdio.h>
struct Process {
int processID;
int arrivalTime;
int burstTime;
int waitingTime;
int turnaroundTime;
int completed;
};
int main() {
int n;
int currentTime = 0;
int completedProcesses = 0;
if (shortestJob == -1) {
currentTime++;
} else {
int p = shortestJob;
processes[p].waitingTime = currentTime - processes[p].arrivalTime;
processes[p].turnaroundTime = processes[p].waitingTime + processes[p].burstTime;
currentTime += processes[p].burstTime;
processes[p].completed = 1;
completedProcesses++;
return 0;
}
#include <stdio.h>
struct Process {
int processID;
int burstTime;
int remainingTime;
int waitingTime;
};
int main() {
int n, timeQuantum;
int currentTime = 0;
int completedProcesses = 0;
return 0;
}
#include <stdio.h>
struct Process {
int processID;
int burstTime;
int priority;
int waitingTime;
int turnaroundTime;
};
int main() {
int n;
sortProcesses(processes, n);
int currentTime = 0;
return 0;
}
I can provide a sample set of data and the expected result for the Priority process
scheduling program:
**Sample Data:**
- Number of processes: 4
- Process details:
1. Process P1 - Burst Time: 5, Priority: 3
2. Process P2 - Burst Time: 4, Priority: 2
3. Process P3 - Burst Time: 6, Priority: 4
4. Process P4 - Burst Time: 2, Priority: 1
**Expected Result:**
```
Process Burst Time Priority Waiting Time Turnaround Time
P4 2 1 0 2
P2 4 2 2 6
P1 5 3 10 15
P3 6 4 21 27
```
In the output, you can see the processes sorted by priority, and their respective waiting
times and turnaround times are calculated based on the Priority scheduling algorithm. The
waiting time is the time each process spends waiting before execution, and the turnaround
time is the total time from arrival to completion.
- The user inputs the number of processes and their respective burst times and priorities.
- The processes are sorted based on priority in ascending order to determine their execution order.
- Waiting times and turnaround times are calculated for each process.
- Waiting time is the time a process waits before execution, and turnaround time is the total time from arrival to
completion.
- The program correctly prioritizes processes with lower priority values for execution.
- It provides valuable insights into the scheduling of processes based on their priorities, helping to optimize
system performance and resource allocation.
The analysis and inferences indicate that this program successfully implements the Priority scheduling algorithm,
an essential concept in operating systems for task prioritization.
#include <stdio.h>
#include <stdlib.h>
struct Process {
int processID;
int burstTime;
int priority;
};
int main() {
int n, quantum1, quantum2;
return 0;
}
In a Multi-Level Feedback Queue (MLFQ) CPU scheduling simulation program, the data and results can be
generated as follows:
**Sample Data:**
- Number of processes: 5
- Time quantum for the first queue: 4
- Time quantum for the second queue: 8
- Process details:
1. Process P1 - Burst Time: 10
2. Process P2 - Burst Time: 5
3. Process P3 - Burst Time: 7
4. Process P4 - Burst Time: 3
5. Process P5 - Burst Time: 6
**Expected Results:**
The program will simulate the execution of processes using the MLFQ algorithm and provide the order of
completion. The order might look like the following:
```
P1 (Queue 1) completed at time 4
P2 (Queue 1) completed at time 8
P3 (Queue 1) completed at time 12
P4 (Queue 2) completed at time 20
P5 (Queue 1) completed at time 24
```
In this example, processes with shorter burst times are expected to be completed in the first queue, while those
with longer burst times may be moved to the second queue after priority promotion. The completion times may
vary based on the given burst times and time quantum values.
The provided Multi-Level Feedback Queue (MLFQ) CPU scheduling program simulates a simplified two-level
feedback queue scheduling algorithm and provides some analysis and inferences:
- The program allows the user to input the number of processes, time quantum for the first and second queues,
and burst times for each process.
- It simulates process execution using two queues, where processes start in the first queue and are moved to the
second queue upon priority promotion.
- Processes in the first queue are executed using a shorter time quantum, while those in the second queue are
given a longer time quantum.
- The program prints the order in which processes are completed and at what time.
- Processes with shorter burst times are expected to be completed in the first queue, while those with longer
burst times may be moved to the second queue after priority promotion.
The analysis and inferences from this simplified program provide an understanding of how a basic two-level
feedback queue scheduling algorithm functions. In a real-world scenario, MLFQ algorithms can be more complex
with additional rules for process promotion and demotion between queues to optimize system performance and
resource allocation.
#include <stdio.h>
#include <stdlib.h>
struct Process {
int processID;
int burstTime;
int priority;
};
int main() {
int n;
printf("Enter the number of processes: ");
scanf("%d", &n);
int front1 = -1, rear1 = -1; // Initialize front and rear for queue 1
int front2 = -1, rear2 = -1; // Initialize front and rear for queue 2
if (processes[i].priority == 1) {
if (front1 == -1) {
front1 = 0;
}
rear1++;
queue1[rear1] = processes[i];
} else {
if (front2 == -1) {
front2 = 0;
}
rear2++;
queue2[rear2] = processes[i];
}
}
return 0;
}
In a Multi-Level Queue (MLQ) CPU scheduling program, the data and results can be represented as follows:
**Sample Data:**
- Number of processes: 5
- Process details:
1. Process P1 - Burst Time: 10, Priority: 1 (High Priority)
2. Process P2 - Burst Time: 5, Priority: 1 (High Priority)
3. Process P3 - Burst Time: 7, Priority: 2 (Low Priority)
4. Process P4 - Burst Time: 3, Priority: 2 (Low Priority)
5. Process P5 - Burst Time: 6, Priority: 1 (High Priority)
**Expected Results:**
The program will execute the processes in two different queues based on their priorities:
The program will print the order in which processes are executed in each queue, considering their priority levels.
The results will demonstrate how processes are managed and executed based on their priorities in a multi-level
queue scheduling algorithm. In practice, more queues and complex rules may be applied to optimize system
performance.
The provided Multi-Level Queue (MLQ) CPU scheduling program simulates a simplified two-level queue
scheduling algorithm and provides some analysis and inferences:
- The program allows the user to input the number of processes, their burst times, and their priority levels (high
or low).
- Processes are initially divided into two separate queues, Queue 1 for high-priority processes and Queue 2 for
low-priority processes.
- Processes in Queue 1 are executed before those in Queue 2, considering the higher priority. The program prints
the order of process execution within each queue.
- The program showcases how processes with different priorities are managed and executed in separate queues,
ensuring that high-priority processes are given precedence over low-priority processes.
- In a real-world scenario, a multi-level queue scheduling algorithm may involve more than two queues with
different priority levels and more complex rules for process selection and execution.
- This simplified program provides insights into the concept of multi-level queue scheduling, which is often used
in operating systems to efficiently manage processes with varying priorities and requirements.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_CORES 4
#define NUM_PROCESSES 10
pthread_t cores[NUM_CORES];
pthread_mutex_t mutex;
int main() {
int processIDs[NUM_PROCESSES];
pthread_mutex_init(&mutex, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
In a simplified program for simulating multiprocessor scheduling, the data and results can be represented as
follows:
**Sample Data:**
**Expected Results:**
The program will simulate scheduling the processes on multiple processor cores using a round-robin approach.
Here is an example of expected results:
```
Process P1 is running on Core 1
Process P2 is running on Core 2
Process P3 is running on Core 3
Process P4 is running on Core 0
Process P1 completed on Core 1
Process P2 completed on Core 2
Process P3 completed on Core 3
Process P4 completed on Core 0
Process P5 is running on Core 1
Process P6 is running on Core 2
Process P7 is running on Core 3
Process P8 is running on Core 0
Process P5 completed on Core 1
Process P6 completed on Core 2
Process P7 completed on Core 3
Process P8 completed on Core 0
Process P9 is running on Core 1
Process P10 is running on Core 2
Process P9 completed on Core 1
Process P10 completed on Core 2
```
In this example, the program simulates the execution of ten processes on four available processor cores.
Processes are scheduled in a round-robin manner on the cores, and the order in which they run and complete is
shown.
Real multiprocessor scheduling algorithms in operating systems consider more complex factors such as process
priorities, load balancing, and resource allocation to optimize system performance.
The provided Multi-Level Queue (MLQ) CPU scheduling program simulates a simplified two-level queue
scheduling algorithm and provides some analysis and inferences:
- The program allows the user to input the number of processes, their burst times, and their priority levels (high
or low).
- Processes are initially divided into two separate queues, Queue 1 for high-priority processes and Queue 2 for
low-priority processes.
- Processes in Queue 1 are executed before those in Queue 2, considering the higher priority. The program prints
the order of process execution within each queue.
- The program showcases how processes with different priorities are managed and executed in separate queues,
ensuring that high-priority processes are given precedence over low-priority processes.
- In a real-world scenario, a multi-level queue scheduling algorithm may involve more than two queues with
different priority levels and more complex rules for process selection and execution.
- This simplified program provides insights into the concept of multi-level queue scheduling, which is often used
in operating systems to efficiently manage processes with varying priorities and requirements.
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
return NULL;
}
// If the next process has finished executing, remove it from the queue
if (next_process->burst_time == 0) {
for (int i = 0; i < n; i++) {
if (processes[i].name == next_process->name) {
processes[i] = processes[n - 1];
n--;
break;
}
}
}
}
}
int main() {
int n;
printf("Enter the number of processes: ");
scanf("%d", &n);
assign_lottery_tickets(processes, n);
simulate_lottery_process_scheduling(processes, n);
Process A: 50 tickets
Process B: 30 tickets
Process C: 20 tickets
Scheduling results:
Time | Process
------- | --------
0 |A
1 |A
2 |A
3 |B
4 |B
5 |C
6 |C
The Lottery Process Scheduling algorithm is a probabilistic algorithm, which means that
the likelihood of a process being selected for execution is proportional to the number of
lottery tickets it contains. This allows for a more equitable distribution of resources among
processes than other scheduling algorithms, such as FIFO or Round Robin.
Here is an analysis of the Lottery Process Scheduling algorithm and its results:
Advantages:
• Fairness: The Lottery Process Scheduling algorithm is fair because it gives all
processes a chance to run, regardless of their priority.
• Efficiency: The Lottery Process Scheduling algorithm is efficient because it does not
require any complex calculations or data structures.
• Simplicity: The Lottery Process Scheduling algorithm is simple to implement and
understand.
Disadvantages:
Overall, the Lottery Process Scheduling algorithm is a good choice for systems where
fairness and efficiency are important. It is relatively simple to implement and does not
require any complex calculations or data structures.
Results:
The results of the Lottery Process Scheduling algorithm are generally good. It is a fair and
efficient algorithm that can be used to schedule a wide variety of workloads. However, it is
important to be aware of the overhead and security implications of using this algorithm.
This is a desirable outcome because it ensures that the most important processes are
given the highest priority. However, it is important to note that the Lottery Process
Scheduling algorithm is probabilistic, which means that there is a small chance that
Process C may be scheduled to run more often than Process A.
Overall, the Lottery Process Scheduling algorithm is a good choice for systems where
fairness and efficiency are important. It is relatively simple to implement and does not
require any complex calculations or data structures.
FCFS schedules processes in the order they arrive, while SJF schedules processes in
order of shortest burst time.
A priority scheduling algorithm schedules processes based on their priorities, with higher
priority processes being scheduled first.
3. What are the difference between primitive and non-primitive scheduling algorithms?
Aim/Objective:
The aim and objectives of memory management in operating systems are focused on effectively
managing the computer's memory resources to optimize system performance, enable efficient
execution of processes, and provide a secure and stable environment for running applications.
Description:
Memory management in operating systems refers to the management and organization of computer
memory resources to efficiently allocate and control memory for processes and applications. It involves
various techniques, algorithms, and data structures to optimize memory utilization, ensure data
integrity, provide protection between processes, and enhance overall system performance. Here's a
description of the key aspects of memory management in operating systems:
1. Memory Organization:
2. Memory Allocation:
3. Memory Protection and Isolation:
4. Virtual Memory Management:
5. Memory Deallocation:
6. Memory Fragmentation Management:
7. Memory Swapping and Page Replacement:
Pre-Requisites:
Pre-Lab Task:
Memory Variable MVT (Memory Variable Partitioning Technique) divides physical memory
Partitioning Technique into variable-sized partitions for process allocation, providing flexibility but
(MVT) with increased management complexity.
External Fragmentation External fragmentation is the condition in which free memory is divided into
small, non-contiguous blocks, making it challenging to allocate large blocks
of memory to processes efficiently.
Dynamic Memory Dynamic memory allocation is a process in which a program requests and
Allocation releases memory during its execution, allowing for flexible and efficient
utilization of memory resources.
Static Memory Allocation Static memory allocation is a method where memory is allocated to variables
and data structures at compile-time, with fixed memory sizes that do not
change during program execution.
In-Lab
#include <stdio.h>
#include <stdlib.h>
void initializeMemory() {
for (int i = 0; i < partitionCount; i++) {
partitions[i] = -1; // Initialize all partitions as unallocated
}
}
int main() {
initializeMemory();
return 0;
}
#include <stdio.h>
#include <stdlib.h>
Partition memory[MEMORY_SIZE];
void initializeMemory() {
for (int i = 0; i < MEMORY_SIZE; i++) {
memory[i].size = 0;
memory[i].isAllocated = 0; // Initialize all partitions as unallocated
}
}
int main() {
initializeMemory();
return 0;
}
Post – Lab:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("Enter the number of integers you want to allocate: ");
scanf("%d", &n);
if (dynamicArray == NULL) {
printf("Memory allocation failed. Exiting...\n");
return 1;
}
return 0;
}
**Program Analysis:**
1. The program dynamically allocates memory for an array of integers based on the user's input for the
number of integers to allocate.
2. It checks if the memory allocation was successful (checks if `malloc` returned a valid pointer).
3. It allows the user to input integer values into the dynamically allocated array.
5. Finally, it releases (frees) the dynamically allocated memory to prevent memory leaks.
**Inferences:**
1. Dynamic Memory Allocation: The program demonstrates dynamic memory allocation using `malloc`,
which allows you to allocate memory as needed during program execution. This is useful when the memory
requirements are not known in advance.
2. User Interaction: The program interacts with the user to determine how much memory to allocate and to
input data. This user interaction makes the program flexible and user-friendly.
3. Memory Management: Proper memory management is crucial. The program uses `malloc` to allocate
memory and `free` to release it. This prevents memory leaks and ensures efficient memory usage.
4. Error Handling: The program checks for memory allocation errors and provides an error message if the
5. Data Processing: The program collects, processes, and displays user input, showing a practical application
of dynamic memory allocation.
6. Scalability: The program can handle different numbers of integers based on user input, making it scalable
and adaptable to various scenarios.
Overall, this program serves as a basic example of dynamic memory allocation in C, showcasing how to
allocate and release memory as needed while interacting with the user. Dynamic memory allocation is a
fundamental concept in C programming, and this program provides a starting point for more complex
memory management tasks.
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("Enter the number of integers you want to allocate: ");
scanf("%d", &n);
if (dynamicArray == NULL) {
printf("Memory allocation failed. Exiting...\n");
return 1;
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
printf("Enter the number of integers you want to allocate: ");
scanf("%d", &n);
if (dynamicArray == NULL) {
printf("Memory allocation failed. Exiting...\n");
return 1;
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, newSize;
printf("Enter the initial number of integers you want to allocate: ");
scanf("%d", &n);
if (dynamicArray == NULL) {
printf("Memory allocation failed. Exiting...\n");
return 1;
}
if (dynamicArray == NULL) {
printf("Memory reallocation failed. Exiting...\n");
return 1;
}
The Most Frequently Used (MFU) algorithm aims to replace the page that has been referenced most frequently in
the past, with the idea of retaining pages in memory that are still frequently accessed.
The Most Frequently Used (MFU) algorithm replaces the page that has been referenced most frequently in the
past, aiming to retain frequently accessed pages in memory.
Optimal Page Replacement replaces the page that won't be used for the longest time in the future, while Least
Recently Used (LRU) replaces the page that hasn't been used for the longest time in the past.
Demand Paging is a memory management scheme where data is loaded into memory only when it is demanded,
reducing the initial memory requirements and allowing efficient utilization of memory resources.
Swapping involves moving an entire process in and out of main memory, while paging moves individual pages or
blocks of a process between main memory and secondary storage, offering finer-grained control over memory
allocation.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Aim/Objective:
Efficiently allocate and manage memory resources to optimize system performance and facilitate the
execution of processes and applications.
Description:
Memory allocation techniques in operating systems refer to the methods used to allocate and manage
memory resources for processes and applications. These techniques aim to optimize memory utilization,
ensure efficient allocation, and provide a fair and balanced distribution of memory among processes.
Pre-Requisites:
Pre-Lab:
In-Lab:
#include <stdio.h>
#include <stdlib.h>
int main() {
int n;
return 0;
}
2. write a C program to implement Memory Management concept using the technique Best fit
algorithms.
#include <stdio.h>
#include <stdlib.h>
MemoryBlock memory[MEMORY_SIZE];
void initializeMemory() {
for (int i = 0; i < MEMORY_SIZE; i++) {
memory[i].size = 0;
memory[i].allocated = 0;
}
}
if (bestFitIndex != -1) {
memory[bestFitIndex].allocated = 1;
printf("Allocated %d bytes at index %d.\n", blockSize, bestFitIndex);
int main() {
initializeMemory();
// Deallocate a block
deallocate(1);
return 0;
}
3. write a C program to implement Memory Management concept using the technique worst fit
algorithms.
#include <stdio.h>
#include <stdlib.h>
MemoryBlock memory[MEMORY_SIZE];
void initializeMemory() {
for (int i = 0; i < MEMORY_SIZE; i++) {
memory[i].size = 0;
memory[i].allocated = 0;
}
}
if (worstFitIndex != -1) {
memory[worstFitIndex].allocated = 1;
printf("Allocated %d bytes at index %d.\n", blockSize, worstFitIndex);
} else {
printf("No suitable block found for allocation.\n");
int main() {
initializeMemory();
// Deallocate a block
deallocate(1);
return 0;
}
4. write a C program to implement Memory Management concept using the technique first fit
algorithms.
#include <stdio.h>
#include <stdlib.h>
MemoryBlock memory[MEMORY_SIZE];
void initializeMemory() {
for (int i = 0; i < MEMORY_SIZE; i++) {
memory[i].size = 0;
memory[i].allocated = 0;
}
}
if (firstFitIndex != -1) {
memory[firstFitIndex].allocated = 1;
printf("Allocated %d bytes at index %d.\n", blockSize, firstFitIndex);
} else {
printf("No suitable block found for allocation.\n");
}
int main() {
initializeMemory();
// Deallocate a block
deallocate(1);
return 0;
}
int page_table[NUM_PAGES];
char memory[MEMORY_SIZE];
char disk[MEMORY_SIZE];
void initializeMemory() {
// Initialize page table
for (int i = 0; i < NUM_PAGES; i++) {
page_table[i] = -1; // No page loaded initially
}
page_table[pageNumber] = frameNumber;
}
if (frameNumber == -1) {
printf("Page fault! Page %d is not in memory.\n", pageNumber);
return 0; // Return a null character for simplicity
}
int main() {
initializeMemory();
return 0;
}
Post-Lab:
1. Demonstrate Allocating Memory on the Heap with your own implementation of malloc() and
free() using free list and UNIX system calls.
#include <unistd.h>
#include <stddef.h>
if (!free_list) {
// First call to malloc: initialize the free list with the entire heap
free_list = sbrk(0); // Get the current end of the heap
if (sbrk(HEAP_SIZE) == (void*)-1) {
return NULL; // Out of memory
}
free_list->size = HEAP_SIZE;
free_list->next = NULL;
}
while (current) {
if (current->size >= size) {
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 87 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
if (current->size > size + sizeof(Block)) {
// Split the block if it's large enough
Block* new_block = (Block*)((char*)current + size);
new_block->size = current->size - size;
new_block->next = current->next;
current->size = size;
current->next = new_block;
}
if (prev) {
prev->next = current->next;
} else {
free_list = current->next;
}
2. Develop a program to illustrate the effect of free() on the program break. This program allocates
multiple blocks of memory and then frees some or all of them, depending on its (optional)
command-line arguments. The first two command-line arguments specify the number and size of
blocks to allocate. The third command-line argument specifies the loop step unit to be used when
freeing memory blocks. If we specify 1 here (which is also the default if this argument is omitted),
then the program frees every memory block; if 2, then every second allocated block; and so on.
The fourth and fifth command-line arguments specify the range of blocks that we wish to free. If
these arguments are omitted, then all allocated blocks (in steps given by the third command-line
argument) are freed. Find the present address of the program break using sbrk() and expand the
program break by the size 1000000 using brk().
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
if (argc > 3) {
step = atoi(argv[3]);
}
if (argc > 4) {
start = atoi(argv[4]);
}
if (num_blocks <= 0 || block_size <= 0 || step <= 0 || start < 0 || end < start || end > num_blocks) {
printf("Invalid arguments.\n");
return 1;
}
printf("Freeing memory blocks from %d to %d with a step of %d.\n", start, end, step);
for (int i = start; i < end; i += step) {
free(blocks[i]);
blocks[i] = NULL;
}
if (brk(sbrk(0) + 1000000) == 0) {
printf("Program break expanded by 1,000,000 bytes.\n");
} else {
perror("brk");
}
return 0;
}
2. Differentiate between Best Fit, First Fit and Worst Fit Strategies?
Best Fit minimizes waste by selecting the smallest available memory block. First Fit is simple and quick
but can result in moderate fragmentation. Worst Fit assigns the largest available block, suitable for
large allocations but less efficient in preventing fragmentation.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Aim/Objective:
Efficiently allocate and manage page replacement algorithms and resources to optimize system
performance and facilitate the execution of processes and applications. Paging is a memory management
technique that allows non-contiguous memory allocations to process and avoids the problem of external
fragmentation. Most modern operating systems use paging. With paging, the physical memory is divided
into frames, and the virtual address space of a process is divided into logical pages. Memory is allocated
at the granularity of pages. When a process requires a new page, the OS finds a free frame to map this
page into and inserts a mapping between the page number and frame number in the page table of the
process.
Description:
FIFO (First In First Out) is the simplest page replacement algorithm. With FIFO, logical pages assigned to
processes are placed in a FIFO queue. New pages are added at the tail. When a new page must be mapped,
the page at the head of the queue is evicted. This way, the page brought into the memory earliest is
swapped out. However, this oldest page maybe a piece of code that is heavily used, and may cause a page
fault very soon, so FIFO does not always make good choices, and may have a higher than optimal page
fault rate. The FIFO policy also suffers from Belady’s anomaly, i.e., the page fault rate may not be
monotonically decreasing with the total available memory, which would have been the expectation with
a sane page replacement algorithm. (Because FIFO doesn’t care for popularity of pages, it may so happen
that some physical memory sizes lead you to replace a heavily used page, while some don’t, resulting in
the anomaly.) The FIFO is the simplest page replacement algorithm, the idea behind this is “Replace a
page that page is the oldest page of all the pages of the main memory” or “Replace the page that has been
in memory longest”.
What is the optimal page replacement algorithm? One must ideally replace a page that will not be used
for the longest time in the future. However, since one cannot look into the future, this optimal algorithm
cannot be realized in practice. The optimal page replacement has the lowest page fault rate of all
algorithms. The criteria of this algorithm is “Replace a page that will not be used for the longest period of
time”.
The LRU (least recently used) policy replaces the page that has not be used for the longest time in the past
and is somewhat of an approximation to the optimal policy. It doesn’t suffer from Belady’s anomaly (the
ordering of least recently used pages won’t change based on how much memory you have) and is one of
the more popular policies. To implement LRU, one must maintain the time of access of each page, which
is an expensive operation if done in software by the kernel. Another way to implement LRU is to store the
pages in a stack, move a page to the top of the stack when accessed, and evict from the bottom of the
stack. However, this solution also incurs a lot of overhead (changing stack pointers) for every memory
access.
Pre-Requisites:
Pre-Lab:
LRU (Least Recently Used) is a page replacement algorithm that selects the page
that hasn't been accessed for the longest time for replacement. It optimizes
memory usage by retaining recently accessed pages but can be complex to
LRU
implement efficiently due to the need to track access history for all pages. LRU
is widely used in virtual memory systems.
The Optimal page replacement algorithm selects pages for replacement based on
future usage, minimizing potential future page faults. It is ideal in theory but
impractical for real systems due to the need for future access knowledge.
Optimal is used as a benchmark for evaluating the effectiveness of other page
OPTIMAL replacement algorithms.
In - Lab Task:
1. write a C program to implement FIFO page replacement algorithm.
#include <stdio.h>
int main() {
int pageFrames[MAX_FRAMES];
int pageReferenceString[] = {2, 3, 2, 1, 5, 2, 4, 5, 3, 2, 5, 2};
int pageFaults = 0;
int frameIndex = 0;
pageFaults++;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main() {
int pageFrames[MAX_FRAMES];
int pageReferenceString[] = {2, 3, 2, 1, 5, 2, 4, 5, 3, 2, 5, 2};
int pageFaults = 0;
int frameIndex = 0;
pageFaults++;
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 96 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
return 0;
}
Post Lab:
1. Write a C program to simulate Optimal page replacement algorithms.
#include <stdio.h>
int main() {
int pageFrames[MAX_FRAMES];
int pageReferenceString[] = {1, 2, 3, 4, 2, 1, 5, 6, 2, 1, 2, 3, 7};
int pageFaults = 0;
// Page fault: Replace the page that won't be used for the longest time
if (!pageFound) {
int optimalPageIndex = -1;
int farthestDistance = -1;
// Find the page in memory that will be used farthest in the future
for (int j = 0; j < MAX_FRAMES; j++) {
int nextPageIndex = i + 1;
while (nextPageIndex < 13) {
if (pageReferenceString[nextPageIndex] == pageFrames[j]) {
if (nextPageIndex > farthestDistance) {
farthestDistance = nextPageIndex;
optimalPageIndex = j;
}
break;
}
nextPageIndex++;
}
pageFrames[optimalPageIndex] = currentPage;
pageFaults++;
return 0;
}
#include <stdio.h>
typedef struct {
int page;
int frequency;
} PageFrame;
int main() {
PageFrame pageFrames[MAX_FRAMES];
int pageReferenceString[] = {1, 2, 3, 4, 2, 1, 5, 6, 2, 1, 2, 3, 7};
int pageFaults = 0;
pageFrames[minFrequencyIndex].page = currentPage;
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 100 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
pageFrames[minFrequencyIndex].frequency = 1;
pageFaults++;
return 0;
}
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Aim/Objective:
Description:
Deadlock is a situation where more than one process is blocked because it is holding a resource and also requires
some resource that is acquired by some other process. There are Four necessary conditions in deadlock situation
to occur are mutual execution, hold and wait, no-pre-emption and circular wait.
Prerequisite:
● Basic functionality of Deadlocks.
● Complete idea of Deadlock avoidance and Prevention
Pre-Lab Task:
Deadlock Conditions FUNCTIONALITY
Mutual exclusion is a condition for deadlock, where resources can only be used
by one process at a time, leading to resource contention. In a multi-process
system, when processes compete for exclusive access to resources and hold
Mutual Exclusion resources while waiting for others, deadlock potential arises. Ensuring mutual
exclusion for critical resources is essential to prevent deadlocks.
In Lab Task:
1. Write a C program to simulate the Bankers Algorithm for Deadlock Avoidance.
#include <stdio.h>
int main() {
int processes, resources;
printf("Enter the number of processes: ");
scanf("%d", &processes);
printf("Enter the number of resources: ");
scanf("%d", &resources);
int allocation[processes][resources];
int maximum[processes][resources];
int need[processes][resources];
int available[resources];
int finish[processes];
// Banker's Algorithm
int work[resources];
for (int i = 0; i < resources; i++) {
work[i] = available[i];
}
int count = 0;
while (count < processes) {
int found = 0;
for (int p = 0; p < processes; p++) {
if (finish[p] == 0) {
int canAllocate = 1;
for (int r = 0; r < resources; r++) {
if (need[p][r] > work[r]) {
canAllocate = 0;
break;
}
}
if (canAllocate) {
for (int r = 0; r < resources; r++) {
work[r] += allocation[p][r];
}
safeSeq[safeSeqIdx] = p;
safeSeqIdx++;
finish[p] = 1;
found = 1;
}
}
}
if (found == 0) {
printf("The system is not in a safe state.\n");
break;
}
count++;
}
if (safeSeqIdx == processes) {
printf("Safe sequence: ");
for (int i = 0; i < processes; i++) {
printf("%d", safeSeq[i]);
if (i < processes - 1) {
printf(" -> ");
}
}
printf("\n");
}
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 105 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
return 0;
}
#include <stdio.h>
int main() {
int processes, resources;
int allocation[processes][resources];
int max[processes][resources];
int need[processes][resources];
int available[resources];
int work[resources];
int finish[processes];
for (int i = 0; i < processes; i++) {
finish[i] = 0;
}
int safeSeq[processes];
int safeSeqIdx = 0;
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 110 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
int count = 0;
while (count < processes) {
int found = 0;
for (int i = 0; i < processes; i++) {
if (finish[i] == 0) {
int canAllocate = 1;
for (int j = 0; j < resources; j++) {
if (need[i][j] > work[j]) {
canAllocate = 0;
break;
}
}
if (canAllocate) {
for (int j = 0; j < resources; j++) {
work[j] += allocation[i][j];
}
safeSeq[safeSeqIdx] = i;
safeSeqIdx++;
finish[i] = 1;
found = 1;
}
}
}
if (found == 0) {
printf("The system is not in a safe state. Deadlock detected.\n");
break;
}
count++;
}
if (safeSeqIdx == processes) {
printf("Safe sequence: ");
for (int i = 0; i < processes; i++) {
printf("%d", safeSeq[i]);
if (i < processes - 1) {
printf(" -> ");
}
}
printf("\n");
}
return 0;
}
Post Lab:
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 113 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
int main() {
int shmid, semid;
int *shared_data;
int count = 0;
return 0;
}
#include <stdio.h>
#include <pthread.h>
#define NUM_THREADS 3
#define NUM_ITERATIONS 5
int shared_counter = 0;
pthread_mutex_t mutex;
int main() {
pthread_t threads[NUM_THREADS];
int thread_ids[NUM_THREADS];
pthread_mutex_init(&mutex, NULL);
pthread_mutex_destroy(&mutex);
return 0;
}
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 116 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
Mutual exclusion is a concurrency control property that ensures that only one process can access a shared
resource at a time. It is used to prevent race conditions and ensure that programs are reliable and efficient.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Description:
Concurrency is the execution of the multiple instruction sequences at the same time.
It happens in the operating system when there are several process threads running in parallel.
The running process threads always communicate with each other through shared memory
or message passing. Concurrency results in sharing of resources result in problems like
deadlocks and resources starvation.
Prerequisite:
● Basic idea on concurrent data structures Linked lists and queues
● Basic idea on concurrent hash tables
● Producer and consumer problems
● Dining-Philosophers problem
Pre-Lab Task:
Concept FUNCTIONALITY
Concept FUNCTIONALITY
In Lab Task:
1. Write a C program to implement the Producer – Consumer problem.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define BUFFER_SIZE 10
// Producer thread
void *producer(void *arg) {
while (1) {
// Produce an item
int item = rand() % 100;
// Consumer thread
void *consumer(void *arg) {
while (1) {
// Wait for the buffer to have a full slot
sem_wait(&full_count);
int main() {
// Initialize the semaphores
sem_init(&empty_count, 0, BUFFER_SIZE);
sem_init(&full_count, 0, 0);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define NUM_PHILOSOPHERS 5
// Philosopher thread
void *philosopher(void *arg) {
int philosopher_id = (int) arg;
while (1) {
// Think
// Eat
int main() {
// Initialize the semaphores
for (int i = 0; i < NUM_PHILOSOPHERS; i++) {
sem_init(&chopsticks[i], 0, 1);
}
return 0;
}
Post Lab:
1. Write a Program to implement the Sleeping Barber problem in C.
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define NUM_CUSTOMERS 10
#define NUM_CHAIRS 5
// Semaphores to control access to the barber chair and the waiting room
sem_t barber_chair;
sem_t waiting_room;
// Barber thread
void *barber(void *arg) {
while (1) {
// Wait for a customer to arrive
sem_wait(&customer_counter_mutex);
while (customer_counter == 0) {
sem_post(&customer_counter_mutex);
sem_wait(&barber_chair);
}
customer_counter--;
sem_post(&customer_counter_mutex);
// Customer thread
void *customer(void *arg) {
// Wait for the waiting room to have an empty slot
sem_wait(&waiting_room);
int main() {
// Initialize the semaphores and mutex
sem_init(&barber_chair, 0, 1);
sem_init(&waiting_room, 0, NUM_CHAIRS);
pthread_mutex_init(&customer_counter_mutex, NULL);
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <semaphore.h>
#define NUM_READERS 5
#define NUM_WRITERS 2
// Semaphores to control access to the shared resource and the number of readers
sem_t read_count;
sem_t write_mutex;
// Reader thread
void *reader(void *arg) {
while (1) {
// Acquire the read mutex
sem_wait(&read_count);
// If there are no more readers accessing the shared resource, signal to the writer that they can access the
shared resource
if (reader_count == 0) {
sem_post(&write_mutex);
}
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 129 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
}
}
// Writer thread
void *writer(void *arg) {
while (1) {
// Wait for all readers to finish accessing the shared resource
sem_wait(&write_mutex);
// Signal to all readers that they can access the shared resource
sem_post(&write_mutex);
}
}
int main() {
// Initialize the semaphores
sem_init(&read_count, 0, 1);
sem_init(&write_mutex, 0, 1);
return 0;
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 1210 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
}
Concurrency is a powerful tool, but it can also be complex and difficult to debug. It can also lead to
deadlocks and race conditions. Developers should carefully consider the benefits and drawbacks of
concurrency before using it in a system.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 1213 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
Aim/Objective: Student should be able to understand the concepts of Disk Scheduling. It helps in
techniques like coordinating execution of First Come First Serve (FCFS) Disk Scheduling, Shortest Seek
Time First (SSTF) Disk Scheduling, SCAN Disk Scheduling, LOOK Disk Scheduling, C-SCAN Disk
Scheduling.
Description:
Disc scheduling is an important process in operating systems that determines the order in which disk
access requests are serviced. The objective of disc scheduling is to minimize the time it takes to access
data on the disk and to minimize the time it takes to complete a disk access request. Disk access time
is determined by two factors: seek time and rotational latency. Seek time is the time it takes for the
disk head to move to the desired location on the disk, while rotational latency is the time taken by
the disk to rotate the desired data sector under the disk head. Disk scheduling algorithms are an
essential component of modern operating systems and are responsible for determining the order in
which disk access requests are serviced. The primary goal of these algorithms is to minimize disk
access time and improve overall system performance.
Prerequisite:
● Basic functionality of Disk Scheduling Algorithms.
● Complete idea of FCFS, SCAN and C-SCAN.
Pre-Lab Task:
Disk Scheduling Parameters FUNCTIONALITY
Seek time Seek time is a critical parameter in disk scheduling.It represents the time
taken for the disk arm to move to the desired track where the requested
data is located.Minimizing seek time is the primary goal of disk
scheduling algorithms to improve overall disk performance.
Transfer time The functionality of "Transfer Time" in disk operations is to represent the
duration required for data to be read from or written to the disk once the
read/write head is appropriately positioned. It indicates the speed at
which data can be transferred to or from the disk surface once the head is
in the correct track, without specifying the factors affecting it.
In Lab Task:
1. Write a C program to implement FCFS Disk Scheduling Algorithm.
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main() {
int n, i;
int requests[n];
total_seek_time = 0;
// FCFS algorithm, simply process requests in the order they are received
for (i = 0; i < n; i++) {
int seek_distance = abs(current_head - requests[i]);
total_seek_time += seek_distance;
printf("Move from %d to %d (seek time: %d)\n", current_head, requests[i], seek_distance);
current_head = requests[i];
}
return 0;
}
int main() {
int n, i, current_head;
int requests[n];
int total_seek_time = 0;
int direction;
printf("Enter the direction (0 for left, 1 for right): ");
scanf("%d", &direction);
if (direction == 0) {
// Scan left
for (i = current_head; i >= 0; i--) {
printf("Move from %d to %d (seek time: %d)\n", current_head, i, abs(current_head - i));
total_seek_time += abs(current_head - i);
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 135 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
current_head = i;
}
return 0;
}
int main() {
int n, i, current_head;
int requests[n];
int total_seek_time = 0;
return 0;
}
Post Lab:
1. Write a Program C-LOOK Disk Scheduling Algorithm in C
#include <stdio.h>
#include <stdlib.h>
int main() {
int n, i, current_head;
int requests[n];
int total_seek_time = 0;
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
return nearest_index;
}
int main() {
int n, i, current_head;
int requests[n];
int total_seek_time = 0;
int visited[n];
if (nearest_index != -1) {
int distance = abs(requests[nearest_index] - current_head);
total_seek_time += distance;
visited[nearest_index] = 1; // Mark the request as visited
current_head = requests[nearest_index];
return 0;
}
2. Initialize 'total_seek_time' to 0.
4. If 'direction' is 0 (left):
a. Iterate from 'current_head' to track 0:
i. For each track in the range:
- Check if there is a request in 'requests' at that track.
- If there is a request:
- Add the request to 'seek_sequence'.
- Calculate the seek time as the absolute difference between 'current_head' and the request track.
- Update 'current_head' to the request track.
b. Reverse the direction (set 'direction' to 1).
5. If 'direction' is 1 (right):
a. Iterate from 'current_head' to the maximum track number:
i. For each track in the range:
- Check if there is a request in 'requests' at that track.
- If there is a request:
- Add the request to 'seek_sequence'.
- Calculate the seek time as the absolute difference between 'current_head' and the request track.
- Update 'current_head' to the request track.
b. Reverse the direction (set 'direction' to 0).
8. Return 'total_seek_time' as the total seek time incurred while servicing the requests.
End of Algorithm
RAID (Redundant Array of Independent Disks) is a data storage technology that combines multiple physical hard
drives into a single logical unit. Different RAID levels offer varying levels of performance and redundancy. RAID 0
enhances performance but lacks redundancy, while RAID 1 provides redundancy through mirroring. RAID 5
combines striping and parity for a balance of performance and redundancy. RAID 6 offers higher fault tolerance
with double parity, and RAID 10 combines mirroring and striping for both performance and redundancy. RAID
configurations are used to improve data reliability and performance in various applications.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Prerequisite:
● Basic functionality of IPC.
● Complete idea of different methods like shmget, segptr.
● Basic functionality of threading and synchronization concepts.
Pre-Lab Task:
IPC terms FUNCTIONALITY
Semaphores Semaphores in IPC are synchronization tools with two key operations:
"Wait" (P) decreases the semaphore value, possibly blocking the process,
while "Signal" (V) increases it and unblocks waiting processes. They help
prevent race conditions, control access to shared resources, and coordinate
processes efficiently. Semaphores can be binary or count-based, making
them essential for synchronization in multi-process environments.
Signals in computing are software interrupts used for process control and
communication. They notify a process about events, errors, or exceptional
Signals conditions. Each signal has a specific meaning and can be customized with
signal handlers to define how processes respond. Common signals include
SIGTERM for termination and SIGINT for interrupt. Signals are crucial for
managing and communicating with processes in Unix-like operating
systems.
In lab task
1. Write a C program to implement IPC using shared memory.
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main() {
int shmid;
key_t key;
char *shm, *s;
// Attach the shared memory segment to the address space of this process
shm = shmat(shmid, NULL, 0);
if (shm == (char *)-1) {
perror("shmat");
exit(1);
}
if (pid == -1) {
perror("fork");
exit(1);
} else if (pid == 0) {
// Child process (consumer): Read data from the shared memory
shm = shmat(shmid, NULL, 0);
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 150 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
if (shm == (char *)-1) {
perror("shmat (child)");
exit(1);
}
s = shm;
printf("Consumer: Received data from shared memory: %s\n", s);
return 0;
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
return NULL;
}
return NULL;
}
int main() {
pthread_t threads[NUM_THREADS];
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
return 0;
}
2. Write C program that demonstrates the Multiple Threads with Global and Local Variables
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#define NUM_THREADS 2
int main() {
pthread_t threads[NUM_THREADS];
printf("Main Thread: Global Variable = %d, Local Variable = %d\n", global_variable, local_variable);
return 0;
}
IPC implementations: Pipes, sockets, message queues, semaphores, mutexes, shared memory.
"Multicast" IPC, on the other hand, involves sending data from one sender to multiple receivers
simultaneously. It's a one-to-many or many-to-many communication method, often used for
broadcasting data to multiple recipients in a network, such as streaming multimedia content to
multiple clients or distributing updates to a group of subscribers.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Aim/Objective: The student should be able to understand, how the file system manages the storage
and retrieval of data on a physical storage device such as a hard drive, solid-state drive, or flash
drive. Also concentrates on File Structure and different file models such as Ordinary Files, Directory
Files and Special Files.
Description:
The most common form of file structure is the sequential file in this type of file, a fixed format is used
for records. All records (of the system) have the same length, consisting of the same number of fixed
length fields in a particular order because the length and position of each field are known, only the
values of fields need to be stored, the field name and length for each field are attributes of the file
structure.
Prerequisite:
● Basic functionality of Files.
● Complete idea of file structure, file types, file access mechanisms.
Pre-Lab Task:
File Organization terms FUNCTIONALITY
File structure File structure refers to the organization and format of data within a
computer file. Common types include flat files for simple storage, text files
for human-readable text, binary files for non-textual data, database files for
structured data in tables, and structured formats like XML and JSON for
hierarchical data storage. The choice of file structure depends on the nature
of the data and its intended use in computer applications.
"Ordinary files" in computer file systems are regular data files that store
user information, program code, or binary data. They are distinct from
Ordinary files special files like directories and device files. These files can be categorized
as regular, text, binary, or executable files, depending on their content and
purpose. Ordinary files are a core component of file systems and are
manipulated using standard file operations and commands in operating
systems.
Special files in computer systems are files that represent devices or system
Special files resources rather than user data. There are two main types: device files and
symbolic links (symlinks). Special files are essential for system
administration and device communication.
Single -Level Directory In a "Single-Level Directory" file organization, all files are stored in a
single directory without subdirectories. Each file is uniquely identified by
its name within this directory. It's a straightforward method for file storage
but can become unwieldy with a large number of files. This structure lacks
hierarchy and limits the ability to categorize or organize files efficiently. It's
suitable for simple file management but may not scale well for complex
data organization
In lab task
1. Write a C program to organize the file using single level directory.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX_FILES 50
#define MAX_NAME_LENGTH 50
struct File {
char name[MAX_NAME_LENGTH];
char data[MAX_NAME_LENGTH];
};
struct Directory {
struct File files[MAX_FILES];
int fileCount;
};
int main() {
struct Directory directory;
directory.fileCount = 0;
int choice;
do {
printf("\nSingle-Level Directory Menu:\n");
printf("1. Create a file\n");
printf("2. List all files\n");
printf("3. Read a file\n");
printf("4. Update a file\n");
printf("5. Delete a file\n");
printf("6. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
if (directory.fileCount < MAX_FILES) {
printf("Enter the name of the file: ");
scanf("%s", directory.files[directory.fileCount].name);
printf("Enter the data for the file: ");
scanf("%s", directory.files[directory.fileCount].data);
directory.fileCount++;
printf("File created successfully.\n");
} else {
printf("Directory is full. Cannot create more files.\n");
}
break;
case 2:
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 156 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
if (directory.fileCount == 0) {
printf("Directory is empty.\n");
} else {
printf("List of files in the directory:\n");
for (int i = 0; i < directory.fileCount; i++) {
printf("%s\n", directory.files[i].name);
}
}
break;
case 3:
if (directory.fileCount == 0) {
printf("Directory is empty.\n");
} else {
char searchName[MAX_NAME_LENGTH];
printf("Enter the name of the file to read: ");
scanf("%s", searchName);
int found = 0;
for (int i = 0; i < directory.fileCount; i++) {
if (strcmp(searchName, directory.files[i].name) == 0) {
printf("Data in %s: %s\n", searchName, directory.files[i].data);
found = 1;
break;
}
}
if (!found) {
printf("File not found.\n");
}
}
break;
case 4:
if (directory.fileCount == 0) {
printf("Directory is empty.\n");
} else {
char updateName[MAX_NAME_LENGTH];
printf("Enter the name of the file to update: ");
scanf("%s", updateName);
int found = 0;
for (int i = 0; i < directory.fileCount; i++) {
if (strcmp(updateName, directory.files[i].name) == 0) {
printf("Enter new data for %s: ", updateName);
scanf("%s", directory.files[i].data);
printf("File updated successfully.\n");
found = 1;
break;
}
}
if (!found) {
printf("File not found.\n");
}
}
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 156 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
break;
case 5:
if (directory.fileCount == 0) {
printf("Directory is empty.\n");
} else {
char deleteName[MAX_NAME_LENGTH];
printf("Enter the name of the file to delete: ");
scanf("%s", deleteName);
int found = 0;
for (int i = 0; i < directory.fileCount; i++) {
if (strcmp(deleteName, directory.files[i].name) == 0) {
for (int j = i; j < directory.fileCount - 1; j++) {
strcpy(directory.files[j].name, directory.files[j + 1].name);
strcpy(directory.files[j].data, directory.files[j + 1].data);
}
directory.fileCount--;
printf("File %s deleted successfully.\n", deleteName);
found = 1;
break;
}
}
if (!found) {
printf("File not found.\n");
}
}
break;
case 6:
printf("Exiting the program.\n");
break;
default:
printf("Invalid choice. Please enter a valid option.\n");
break;
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_FILES 50
#define MAX_NAME_LENGTH 50
struct File {
char name[MAX_NAME_LENGTH];
char data[MAX_NAME_LENGTH];
};
struct Directory {
char name[MAX_NAME_LENGTH];
struct File files[MAX_FILES];
int fileCount;
};
int main() {
struct Directory rootDirectory;
rootDirectory.fileCount = 0;
strcpy(rootDirectory.name, "root");
int choice;
do {
printf("\nTwo-Level Directory Menu:\n");
printf("1. Create a directory\n");
printf("2. Create a file\n");
printf("3. List files in a directory\n");
printf("4. Read a file\n");
printf("5. Update a file\n");
printf("6. Delete a file\n");
printf("7. Exit\n");
printf("Enter your choice: ");
scanf("%d", &choice);
switch (choice) {
case 1:
if (rootDirectory.fileCount < MAX_FILES) {
char newDirectoryName[MAX_NAME_LENGTH];
printf("Enter the name of the new directory: ");
scanf("%s", newDirectoryName);
struct Directory newDirectory;
newDirectory.fileCount = 0;
strcpy(newDirectory.name, newDirectoryName);
rootDirectory.files[rootDirectory.fileCount++] = newDirectory;
printf("Directory '%s' created successfully.\n", newDirectoryName);
} else {
printf("Maximum directory limit reached.\n");
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 156 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
}
break;
case 2:
if (rootDirectory.fileCount < MAX_FILES) {
char directoryName[MAX_NAME_LENGTH];
printf("Enter the name of the directory to create the file in: ");
scanf("%s", directoryName);
int found = 0;
for (int i = 0; i < rootDirectory.fileCount; i++) {
if (strcmp(directoryName, rootDirectory.files[i].name) == 0) {
if (rootDirectory.files[i].fileCount < MAX_FILES) {
char newFileName[MAX_NAME_LENGTH];
printf("Enter the name of the new file: ");
scanf("%s", newFileName);
struct File newFile;
strcpy(newFile.name, newFileName);
printf("Enter data for the file: ");
scanf("%s", newFile.data);
rootDirectory.files[i].files[rootDirectory.files[i].fileCount++] = newFile;
printf("File '%s' created successfully in directory '%s'.\n", newFileName, directoryName);
} else {
printf("Maximum file limit reached in directory '%s'.\n", directoryName);
}
found = 1;
break;
}
}
if (!found) {
printf("Directory '%s' not found.\n", directoryName);
}
} else {
printf("Maximum directory limit reached.\n");
}
break;
case 3:
printf("List of directories in the root directory:\n");
for (int i = 0; i < rootDirectory.fileCount; i++) {
printf("Directory: %s\n", rootDirectory.files[i].name);
}
break;
case 4:
printf("Enter the name of the directory containing the file: ");
char searchDirectoryName[MAX_NAME_LENGTH];
scanf("%s", searchDirectoryName);
printf("Enter the name of the file to read: ");
char searchFileName[MAX_NAME_LENGTH];
scanf("%s", searchFileName);
int found = 0;
for (int i = 0; i < rootDirectory.fileCount; i++) {
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 156 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
if (strcmp(searchDirectoryName, rootDirectory.files[i].name) == 0) {
struct Directory directory = rootDirectory.files[i];
for (int j = 0; j < directory.fileCount; j++) {
if (strcmp(searchFileName, directory.files[j].name) == 0) {
printf("Data in %s/%s: %s\n", searchDirectoryName, searchFileName, directory.files[j].data);
found = 1;
break;
}
}
}
}
if (!found) {
printf("File not found.\n");
}
break;
case 5:
printf("Enter the name of the directory containing the file to update: ");
char updateDirectoryName[MAX_NAME_LENGTH];
scanf("%s", updateDirectoryName);
printf("Enter the name of the file to update: ");
char updateFileName[MAX_NAME_LENGTH];
scanf("%s", updateFileName);
found = 0;
for (int i = 0; i < rootDirectory.fileCount; i++) {
if (strcmp(updateDirectoryName, rootDirectory.files[i].name) == 0) {
struct Directory directory = rootDirectory.files[i];
for (int j = 0; j < directory.fileCount; j++) {
if (strcmp(updateFileName, directory.files[j].name) == 0) {
printf("Enter new data for %s/%s: ", updateDirectoryName, updateFileName);
scanf("%s", directory.files[j].data);
printf("File '%s/%s' updated successfully.\n", updateDirectoryName, updateFileName);
found = 1;
break;
}
}
}
}
if (!found) {
printf("File not found.\n");
}
break;
case 6:
printf("Enter the name of the directory containing the file to delete: ");
char deleteDirectoryName[MAX_NAME_LENGTH];
scanf("%s", deleteDirectoryName);
printf("Enter the name of the file to delete: ");
char deleteFileName[MAX_NAME_LENGTH];
scanf("%s", deleteFileName);
found = 0;
for (int i = 0; i < rootDirectory.fileCount; i++) {
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 156 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
if (strcmp(deleteDirectoryName, rootDirectory.files[i].name) == 0) {
struct Directory directory = rootDirectory.files[i];
for (int j = 0; j < directory.fileCount; j++) {
if (strcmp(deleteFileName, directory.files[j].name) == 0) {
for (int k = j; k < directory.fileCount - 1; k++) {
strcpy(directory.files[k].name, directory.files[k + 1].name);
strcpy(directory.files[k].data, directory.files[k + 1].data);
}
directory.fileCount--;
printf("File '%s/%s' deleted successfully.\n", deleteDirectoryName, deleteFileName);
found = 1;
break;
}
}
}
}
if (!found) {
printf("File not found.\n");
}
break;
case 7:
printf("Exiting the program.\n");
break;
default:
printf("Invalid choice. Please enter a valid option.\n");
break;
}
return 0;
}
a) Sequential
#include <stdio.h>
#include <stdlib.h>
int disk[MAX_BLOCKS];
int main() {
int fileSize;
int fileStartBlock;
fileStartBlock = allocateSequential(fileSize);
if (fileStartBlock != -1) {
printf("File allocated at blocks %d to %d.\n", fileStartBlock, fileStartBlock + fileSize - 1);
} else {
printf("File allocation failed. Not enough space.\n");
}
return 0;
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 156 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
b) Indexed
#include <stdio.h>
#include <stdlib.h>
struct IndexTable {
int dataBlock[MAX_BLOCKS];
};
struct File {
int indexBlock;
int fileSize;
};
int main() {
int fileSize;
int fileIndexBlock;
fileIndexBlock = allocateIndexed(fileSize);
if (fileIndexBlock != -1) {
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 156 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
printf("File allocated with index block: %d\n", fileIndexBlock);
} else {
printf("File allocation failed. Not enough space.\n");
}
return 0;
}
c)Linked
#include <stdio.h>
#include <stdlib.h>
struct Block {
int data;
int nextBlock;
};
int main() {
int fileSize;
int fileStartBlock;
fileStartBlock = allocateLinked(fileSize);
if (fileStartBlock != -1) {
printf("File allocated starting from block: %d\n", fileStartBlock);
} else {
printf("File allocation failed. Not enough space.\n");
}
return 0;
}
6. Explain in detail about Sequential File system and Indexed File System
A Sequential File System stores data in a linear, sequential order, suitable for continuous data like log
files. It requires reading or writing records from the beginning to the end, making it inefficient for
random access. Searches often involve scanning through records, which can be slow for large files.An
Indexed File System, on the other hand, maintains a separate index structure alongside the data file.
This index enables direct, rapid access to records based on specific keys or attributes, making it
suitable for databases and applications requiring efficient random access to data. Indexed systems
optimize searches, allowing quick retrieval without the need to scan the entire file.
File access mechanisms in an operating system encompass sequential access, random access, file
pointers, file permissions, and buffering.
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.
Aim/Objective: The student should be able to understand, how to write Shell Scripts, uses of Shell
Scripts, different shells available, shell comment and the Shell Variables.
Description:
The A shell script is a type of computer program developed to be executed by a Unix shell, which is
also known as a command-line interpreter. Several shell script dialects are treated as scripting
languages. Classic operations implemented by shell scripts contain printing text, program execution,
and file manipulation. A script configures the environment, executes the program.
Prerequisite:
● Basic functionality of Unix Commands.
● Complete idea of Disk Operating System and Batch Files
Pre-Lab Task:
Shell variables are used to store data and values in shell scripts and
command-line sessions. They are assigned values with the "=" operator and
Shell Variables accessed using a "$" sign. Variable names are case-sensitive and follow
certain naming conventions. Shell scripts also utilize special variables and
environment variables for specific purposes. Understanding how to use and
manipulate shell variables is essential in scripting and command-line
operations.
Common shell types include Bash, Sh, Csh, Ksh, and Zsh. Each shell type
Shell Types has its own features and use cases in Unix-like operating systems.
Shell comments in scripts use the "#" symbol at the beginning of a line to
Shell Comments provide explanations or documentation. They enhance code readability,
serve as notes for the script's author and readers, and can also be used to
temporarily disable code during debugging or testing.
In Lab
#!/bin/bash
#!/bin/bash
#!/bin/bash
#!/bin/bash
#!/bin/bash
POST LAB
1. Write a Shell Script to accept a year and find Leap Year or Not
#!/bin/bash
#!/bin/bash
if [ $1 -le 2 ]; then
return 0 # Prime
fi
return 0 # Prime
}
A shell script is a text file containing a sequence of commands and instructions, executed by a
shell or command-line interpreter. It automates tasks, interacts with the operating system, and
can perform file manipulation, conditional actions, and more.
2. Explain in detail about Advantages of Shell Script?
Shell scripts offer automation, customization, integration, simplicity, and cost-efficiency
benefits, making them valuable tools for various tasks and environments.
3. What are the different variables available in the shell script?
Shell scripts utilize five main variable types: local, environment, positional parameters, special
variables, and user-defined variables.
# Commands to be repeated
Done
while [ condition ]; do
# Commands to be repeated
done
if [ condition1 ]
then
if [ condition2 ]
then
else
fi
else
fi
Course Title OPERATING SYSTEMS ACADEMIC YEAR: 2023-24
Course Code(s) 22CS2104A & 22CS2104P Page 180 of 227
Experiment # <TO BE FILLED BY STUDENT> Student ID <TO BE FILLED BY STUDENT>
Date <TO BE FILLED BY STUDENT> Student Name <TO BE FILLED BY STUDENT>
Note: Evaluator MUST ask Viva-voce prior to signing and posting marks for each experiment.