OS Lab Manual Programs
OS Lab Manual Programs
Aim:
To Study the basic commands in Linux.
Files
• ls ---lists your files
ls -l --- lists your files in 'long format', which contains lots of useful information, e.g.
the exact size of the file, who owns the file and who has the right to look at it, and
when it was last modified.
ls -a --- lists all files, including the ones whose filenames begin in a dot, which you do
not always want to see.
There are many more options, for example to list files by size, by date, recursively etc.
• more filename --- shows the first part of a file, just as much as will fit on one screen.
Just hit the space bar to see more or q to quit. You can use /pattern to search for a
pattern.
• emacs filename --- is an editor that lets you create and edit a file. mv filename1
filename2 --- moves a file (i.e. gives it a different name, or moves it into a different
directory (see below)
• cp filename1 filename2 --- copies a file
• rm filename --- removes a file. It is wise to use the option rm -i, which will ask you
for confirmation before actually deleting anything.
• diff filename1 filename2 --- compares files, and shows where they differ
• wc filename --- tells you how many lines, words, and characters there are in a file
• chmod options filename --- lets you change the read, write, and execute permissions
on your files. The default is that only you can look at them and change them, but you
may sometimes want to change these permissions. For example, chmod
o+r filename will make the file readable for everyone, and chmod o-r filename will
make it unreadable for others again. Note that for someone to be able to actually look
at the file the directories it is in need to be at least executable
• File Compression
o gzip filename --- compresses files, so that they take up much less space.
Usually text files compress to about half their original size, but it depends very
much on the size of the file and the nature of the contents. There are other
tools for this purpose, too (e.g. compress), but gzip usually gives the highest
compression rate. Gzip produces files with the ending '.gz' appended to the
original filename.
o gunzip filename --- uncompresses files compressed by gzip.
o gzcat filename --- lets you look at a gzipped file without actually having to
gunzip it (same as gunzip -c). You can even print it directly,
using gzcat filename | lpr
• printing
o lpr filename --- print. Use the -P option to specify the printer name if you
want to use a printer other than your default printer. For example, if you want
to print double-sided, use 'lpr -Pvalkyr-d', or if you're at CSLI, you may want
to use 'lpr -Pcord115-d'. See 'help printers' for more information about printers
and their locations.
o lpq --- check out the printer queue, e.g. to get the number needed for removal,
or to see how many other files will be printed before yours will come out
o lprm jobnumber --- remove something from the printer queue. You can find
the job number by using lpq. Theoretically you also have to specify a printer
2
name, but this isn't necessary as long as you use your default printer in the
department.
Directories
Directories, like folders on a Macintosh, are used to group files together in a hierarchical
structure.
• mkdir dirname --- make a new directory
• cd dirname --- change directory. You basically 'go' to another directory, and you will
see the files in that directory when you do 'ls'. You always start out in your 'home
directory', and you can get back there by typing 'cd' without arguments. 'cd ..' will get
you one level up from your current position
• pwd --- tells you where you currently are.
Finding things
• ff --- find files anywhere on the system. This can be extremely useful if you've
forgotten in which directory you put a file, but do remember the name. In fact, if you
use ff -p you don't even need the full name, just the beginning. This can also be useful
for finding other things on the system, e.g. documentation.
• grep string filename(s) --- looks for the string in the files. This can be useful a lot of
purposes, e.g. finding the right file among many, figuring out which is the right
version of something, and even doing serious corpus work. grep comes in several
varieties (grep, egrep, and fgrep) and has a lot of very flexible options. Check out the
man pages if this sounds good to you.
About other people
• w --- tells you who's logged in, and what they're doing. Especially useful: the 'idle'
part. This allows you to see whether they're actually sitting there typing away at their
keyboards right at the moment.
• who --- tells you who's logged on, and where they're coming from. Useful if you're
looking for someone who's actually physically in the same building as you, or in some
other particular location.
• finger username --- gives you lots of information about that user, e.g. when they last
read their mail and whether they're logged in. Often people put other practical
information, such as phone numbers and addresses, in a file called .plan. This
information is also displayed by 'finger'.
• last -1 username --- tells you when the user last logged on and off and from where.
Without any options, last will give you a list of everyone's logins.
• talk username --- lets you have a (typed) conversation with another user
• write username --- lets you exchange one-line messages with another user
About your (electronic) self
• whoami --- returns your username. Sounds useless, but isn't. You may need to find out
who it is who forgot to log out somewhere, and make sure *you* have logged out.
• finger & .plan files
of course you can finger yourself, too. That can be useful e.g. as a quick check
whether you got new mail. Try to create a useful .plan file soon. Look at other
people's .plan files for ideas. The file needs to be readable for everyone in order to be
visible through 'finger'. Do 'chmod a+r .plan' if necessary. You should realize that this
information is accessible from anywhere in the world, not just to other people on
turing.
• passwd --- lets you change your password, which you should do regularly (at least
once a year).
• ps -u yourusername --- lists your processes. Contains lots of information about them,
including the process ID, which you need if you have to kill a process. Normally,
when you have been kicked out of a dialin session or have otherwise managed to get
3
yourself disconnected abruptly, this list will contain the processes you need to kill.
Those may include the shell (tcsh or whatever you're using), and anything you were
running, for example emacs or elm. Be careful not to kill your current shell - the one
with the number closer to the one of the ps command you're currently running. But if
it happens, don't panic. Just try again :) If you're using an X-display you may have to
kill some X processes before you can start them again. These will show only when
you use ps -efl, because they're root processes.
• kill PID --- kills (ends) the processes with the ID you gave. This works only for your
own processes, of course. Get the ID by using ps. If the process doesn't 'die' properly,
use the option -9. But attempt without that option first, because it doesn't give the
process a chance to finish possibly important business before dying. You may need to
kill processes for example if your modem connection was interrupted and you didn't
get logged out properly, which sometimes happens.
• du filename --- shows the disk usage of the files and directories in filename (without
argument the current directory is used). du -s gives only a total.
• last yourusername --- lists your last logins. Can be a useful memory aid for when you
were where, how long you've been working for, and keeping track of your phonebill if
you're making a non-local phonecall for dialling in.
Connecting to the outside world
• nn --- allows you to read news. It will first let you read the news local to turing, and
then the remote news. If you want to read only the local or remote news, you can
use nnl or nnr, respectively. To learn more about nn type nn, then \tty{:man}, then
\tty{=.*}, then \tty{Z}, then hit the space bar to step through the manual.
rlogin hostname --- lets you connect to a remote host
• telnet hostname --- also lets you connect to a remote host. Use rlogin whenever
possible.
• ftp hostname --- lets you download files from a remote host which is set up as an
ftp-server. This is a common method for exchanging academic papers and drafts. If
you need to make a paper of yours available in this way, you can (temporarily) put a
copy in /user/ftp/pub/TMP. For more permanent solutions, ask Emma. The most
important commands within ftp are get for getting files from the remote machine,
and put for putting them there (mget and mput let you specify more than one file at
once). Sounds straightforward, but be sure not to confuse the two, especially when
your physical location doesn't correspond to the direction of the ftp connection you're
making. ftp just overwrites files with the same filename. If you're transferring
anything other than ASCII text, use binary mode.
• lynx --- lets you browse the web from an ordinary terminal. Of course you can see
only the text, not the pictures. You can type any URL as an argument to
the G command. When you're doing this from any Stanford host you can leave out
the .stanford.edu part of the URL when connecting to Stanford URLs. Type H at any
time to learn more about lynx, and Q to exit.
Shell Programming
Aim:
Algorithm:
read num
read num
0] then
else
fi
Output:
Result:
Aim :
Algorithm :
Program:
read a b
if [ $a -gt $b]
then
echo "A is
big" else
echo "B is
big" fi
Output:
23 67
B is Big.
Result:
11
6
Aim:
read a b c
$c] then
else if [ $b -gt
$c ] then
echo "B is
big" else
echo "C is
big" fi
fi
Output:
ENTER THREE
NUMBERS: 23 54 78
C IS BIG.
Result:
Aim:
Step 3: Initialize I as 1.
Step 5: Multiply the value of I and fact and assign to fact increment the value of I by 1.
read n
fact=1
i=1
while [ $i -le
$n ] do
fact=`expr $i \*
$fact` i=`expr $i + 1`
done
Aim :
Algorithm:
Program:
n1=0
n2=1
var=0
echo "$n2"
] do
n1=`expr $n2 `
9
n2=`expr $n3 `
var=`expr $var + 1 `
echo "$n2"
done
Output:
Fibonacci: 5
01123
Result:
PROCESS SCHEDULING
Priority
o Process that has higher priority is processed first. Prioirty can be
preemptive or non–preemptive
o When two processes have same priority, FCFS is used to break the tie.
o Can result in starvation, since low priority processes may not be
processed.
Round Robin
o All processes are processed one by one as they have arrived, but in
rounds. Each process cannot take more than the time slice per round.
o Round robin is a fair preemptive scheduling algorithm.
o A process that is yet to complete in a round is preempted after the time
slice and put at the end of the queue.
o When a process is completely processed, it is removed from the queue.
11
Aim
To schedule snapshot of processes queued according to FCFS (First Come First
Serve) scheduling.
Algorithm
1. Define an array of structure process with members pid, btime, wtime & ttime.
2. Get length of the ready queue, i.e., number of process (say n)
3. Obtain btime for each process.
4. The wtime for first process is 0.
5. Compute wtime and ttime for each process as:
a. wtimei+1 = wtimei + btimei
b. ttimei = wtimei + btimei
1 Compute average waiting time awat and average turnaround time atur
2 Display the btime, ttime and wtime for each process.
3 Display GANTT chart for the above scheduling
4 Display awat time and atur
5 Stop
Program
/* FCFS Scheduling - fcfs.c */
#include <stdio.h>
struct process
{
int pid; int
btime; int
wtime; int
ttime;
} p[10];
main()
{
int i,j,k,n,ttur,twat; float
awat,atur;
printf("Enter no. of process : "); scanf("%d",
&n);
for(i=0; i<n; i++)
{
printf("Burst time for process P%d (in ms) : ",(i+1)); scanf("%d",
&p[i].btime);
p[i].pid = i+1;
12
}
p[0].wtime = 0; for(i=0;
i<n; i++)
{
p[i+1].wtime = p[i].wtime + p[i].btime; p[i].ttime =
p[i].wtime + p[i].btime;
}
ttur = twat = 0; for(i=0;
i<n; i++)
{
ttur += p[i].ttime; twat +=
p[i].wtime;
}
awat = (float)twat / n; atur =
(float)ttur / n;
printf("\nFCFS Scheduling\n\n");
for(i=0; i<28; i++)
printf("-");
printf("\nProcess B-Time T-Time W-Time\n"); for(i=0;
i<28; i++)
printf("-"); for(i=0;
i<n; i++)
printf("\nP%d\t%4d\t%3d\t%2d",p[i].pid,p[i].btime,p[i].ttime,p[i].wtime);
printf("\n"); for(i=0; i<28; i++)
printf("-");
printf("\n\nGANTT Chart\n"); printf("-");
for(i=0; i<(p[n-1].ttime + 2*n); i++) printf("-");
printf("\n");
printf("|"); for(i=0; i<n; i++)
{
k = p[i].btime/2; for(j=0;
j<k; j++) printf(" ");
printf("P%d",p[i].pid);
for(j=k+1; j<p[i].btime; j++)
printf(" ");
printf("|");
}
printf("\n");
printf("-");
for(i=0; i<(p[n-1].ttime + 2*n); i++) printf("-");
printf("\n");
printf("0"); for(i=0; i<n;
i++)
{
for(j=0; j<p[i].btime; j++) printf(" ");
printf("%2d",p[i].ttime);
}
printf("\n\nAverage waiting time : %5.2fms", awat);
13
Output
$ gcc fcfs.c
$./a.out
Enter no. of process: 4
Burst time for process P1 (in ms) : 10 Burst time for
process P2 (in ms) : 4 Burst time for process P3 (in
ms) : 11 Burst time for process P4 (in ms) : 6
FCFS Scheduling
----------------------------
Process B-Time T-Time W-Time
----------------------------
P1 10 10 0
P2 4 14 10
P3 11 25 14
P4 6 31 25
----------------------------
GANTT Chart
--------------------------------------------------------------
| P1 | P2 | P3 | P4 |
--------------------------------------------------------------
0 10 14 25 31
Average waiting time : 12.25ms
Average turn around time : 20.00ms
Result :
Thus waiting time & turnaround time for processes based on FCFS scheduling was
computed and the average waiting time was determined.
Aim
To schedule snapshot of processes queued according to SJF (Shortest Job First)
scheduling.
Algorithm
1. Define an array of structure process with members pid, btime, wtime & ttime.
2. Get length of the ready queue, i.e., number of process (say n)
3. Obtain btime for each process.
4. Sort the processes according to their btime in ascending order.
a. If two process have same btime, then FCFS is used to resolve the tie.
5. The wtime for first process is 0.
6. Compute wtime and ttime for each process as:
a. wtimei+1 = wtimei + btimei
b. ttimei = wtimei + btimei
7. Compute average waiting time awat and average turn around time atur.
8. Display btime, ttime and wtime for each process.
9. Display GANTT chart for the above scheduling
10. Display awat and atur
11. Stop
Program
/* SJF Scheduling – sjf.c */
#include <stdio.h>
struct process
{
int pid; int
btime; int
wtime; int
ttime;
} p[10], temp;
main()
{
int i,j,k,n,ttur,twat; float
awat,atur;
printf("Enter no. of process : "); scanf("%d",
&n);
for(i=0; i<n; i++)
{
printf("Burst time for process P%d (in ms) : ",(i+1)); scanf("%d",
&p[i].btime);
p[i].pid = i+1;
15
}
for(i=0; i<n-1; i++)
{
for(j=i+1; j<n; j++)
{
if((p[i].btime > p[j].btime) ||
(p[i].btime == p[j].btime && p[i].pid > p[j].pid))
{
temp = p[i]; p[i]
= p[j]; p[j] =
temp;
}}}
p[0].wtime = 0; for(i=0;
i<n; i++)
{
p[i+1].wtime = p[i].wtime + p[i].btime; p[i].ttime =
p[i].wtime + p[i].btime;
}
ttur = twat = 0;
for(i=0; i<n; i++)
{
ttur += p[i].ttime; twat +=
p[i].wtime;
}
awat = (float)twat / n; atur =
(float)ttur / n;
printf("\n SJF Scheduling\n\n"); for(i=0; i<28; i++)
printf("-");
printf("\nProcess B-Time T-Time W-Time\n"); for(i=0;
i<28; i++)
printf("-"); for(i=0;
i<n; i++)
printf("\n P%-4d\t%4d\t%3d\t%2d",
p[i].pid,p[i].btime,p[i].ttime,p[i].wtime);
printf("\n"); for(i=0; i<28;
i++)
printf("-");
printf("\n\nGANTT Chart\n");
printf("-");
for(i=0; i<(p[n-1].ttime + 2*n); i++) printf("-");
printf("\n|"); for(i=0;
i<n; i++)
{
k = p[i].btime/2; for(j=0;
j<k; j++) printf(" ");
printf("P%d",p[i].pid); for(j=k+1;
j<p[i].btime; j++)
printf(" ");
16
printf("|");
}
printf("\n-");
for(i=0; i<(p[n-1].ttime + 2*n); i++) printf("-");
printf("\n0"); for(i=0;
i<n; i++)
{
for(j=0; j<p[i].btime; j++) printf(" ");
printf("%2d",p[i].ttime);
}
printf("\n\nAverage waiting time : %5.2fms", awat);
printf("\nAverage turn around time : %5.2fms\n", atur);
}
Output
$ gcc sjf.c
$./a.out
Enter no. of process : 5
Burst time for process P1 (in ms) : 10 Burst time for
process P2 (in ms) : 6 Burst time for process P3 (in
ms) : 5 Burst time for process P4 (in ms) : 6 Burst
time for process P5 (in ms) : 9
SJF Scheduling
----------------------------
Process B-Time T-Time W-Time
----------------------------
P3 5 5 0
P2 6 11 5
P4 6 17 11
P5 9 26 17
P1 10 36 26
----------------------------
GANTT Chart
-------------------------------------------------------------------------------
| P3 | P2 | P4 | P5 | P1 |
-------------------------------------------------------------------------------
0 5 11 17 26 36
Average waiting time : 11.80ms
Average turn around time : 19.00ms
Result
Thus waiting time & turnaround time for processes based on SJF scheduling was
computed and the average waiting time was determined.
Exp# 3c Priority Scheduling
Aim
To schedule snapshot of processes queued according to Priority scheduling.
Algorithm
1. Define an array of structure process with members pid, btime, pri, wtime &
ttime.
2. Get length of the ready queue, i.e., number of process (say n)
3. Obtain btime and pri for each process.
4. Sort the processes according to their pri in ascending order.
a. If two process have same pri, then FCFS is used to resolve the tie.
5. The wtime for first process is 0.
6. Compute wtime and ttime for each process as:
a. wtimei+1 = wtimei + btimei
b. ttimei = wtimei + btimei
7. Compute average waiting time awat and average turn around time atur
8. Display the btime, pri, ttime and wtime for each process.
9. Display GANTT chart for the above scheduling
10. Display awat and atur
11. Stop
Program
/* Priority Scheduling - pri.c */
#include <stdio.h>
struct process
{
int pid; int
btime; int pri;
int wtime; int
ttime;
} p[10], temp;
main()
{
int i,j,k,n,ttur,twat;
float awat,atur;
printf("Enter no. of process : "); scanf("%d", &n);
for(i=0; i<n; i++)
{
printf("Burst time for process P%d (in ms) : ", (i+1));
scanf("%d", &p[i].btime);
printf("Priority for process P%d : ", (i+1));
scanf("%d", &p[i].pri);
p[i].pid = i+1;
}
for(i=0; i<n-1; i++)
{
for(j=i+1; j<n; j++)
{
if((p[i].pri > p[j].pri) ||
(p[i].pri == p[j].pri && p[i].pid > p[j].pid) )
{
temp = p[i]; p[i]
= p[j]; p[j] =
temp;
}}}
p[0].wtime = 0; for(i=0;
i<n; i++)
{
p[i+1].wtime = p[i].wtime + p[i].btime; p[i].ttime =
p[i].wtime + p[i].btime;
}
ttur = twat = 0; for(i=0;
i<n; i++)
{
ttur += p[i].ttime; twat +=
p[i].wtime;
}
awat = (float)twat / n; atur = (float)ttur / n;
printf("\n\t Priority Scheduling\n\n"); for(i=0; i<38; i++)
printf("-");
printf("\nProcess B-Time Priority T-Time W-Time\n"); for(i=0; i<38; i++)
printf("-");
for (i=0; i<n; i++)
printf("\nP%-4d\t%4d\t%3d\t%4d\t
%4d",p[i].pid,p[i].btime,p[i].pri,p[i].ttime,p[i].wtime);
printf("\n"); for(i=0; i<38; i++)
printf("-");
printf("\n\nGANTT Chart\n"); printf("-");
for(i=0; i<(p[n-1].ttime + 2*n); i++) printf("-");
printf("\n|"); for(i=0; i<n; i++)
{
k = p[i].btime/2; for(j=0;
j<k;j++) printf(" ");
printf("P%d",p[i].pid);
for(j=k+1; j<p[i].btime; j++)
printf(" ");
printf("|");
}
printf("\n-");
for(i=0; i<(p[n-1].ttime + 2*n); i++) printf("-");
printf("\n0"); for(i=0; i<n; i++)
{
for(j=0; j<p[i].btime; j++) printf(" ");
printf("%2d",p[i].ttime);
}
printf("\n\nAverage waiting time : %5.2fms", awat);
printf("\nAverage turn around time : %5.2fms\n", atur);}
OUTPUT :
$ gcc pri.c
$ ./a.out
Enter no. of process : 5
Burst time for process P1 (in ms) : 10
Priority for process P1 : 3
Burst time for process P2 (in ms) : 7
Priority for process P2 : 1
Burst time for process P3 (in ms) : 6
Priority for process P3 : 3
Burst time for process P4 (in ms) : 13
Priority for process P4 : 4
Burst time for process P5 (in ms) : 5
Priority for process P5 : 2
Priority Scheduling
---------------------------------------------------------------------
Process B-Time Priority T-Time W-Time
-----------------------------------------------------------------------
P2 7 1 7 0
P5 5 2 12 7
P1 10 3 22 12
P3 6 3 28 22
P4 13 4 41 28
----------------------------------------------------------------------------
GANTT Chart
---------------------------------------------------------------------------------------
| P2 | P5 | P1 | P3 | P4 |
---------------------------------------------------------------------------------------
0 7 12 22 28 41
Result
Thus waiting time & turnaround time for processes based on Priority scheduling
was computed and the average waiting time was determined.
Ex.No:3d Round Robin Scheduling Algorithm
Aim:
Algorithm:
7.Time waits to start the execution, is the waiting time(WT) of each processor
n) avg_TAT = tot_TAT/num_of_proc
p) avg_WT = tot_WT/num_of_proc
#include<stdio.h>
#include<conio.>
int TRUE = 0;
{
int i,j; clrscr();
for(i=0;i<n;i++)
tbt[i] = bt[i];
wt[i] = tat[i] = 0;
lmore = TRUE;
while(lmore== TRUE)
lmore= FALSE;
for(i=0;i<n;i++)
if(bt[i] != 0)
wt[i] = wt[i] + (time - tat[i]);
tqt = 1;
lmore = TRUE;
bt[i] = bt[i]
-1; tqt++;
time++;
tat[i] = time;
}}}
printf("\nProcessorID\tBurstTime\tTurnAroundTime\tWaitingTime\);
for(i=0;i<n;i++)
printf("Processor%d\t\t%d\t\t%d\t\t%d\n",i+1,tbt[i],tat[i],wt[i]);
t_tat = t_tat + tat[i]; t_wt = t_wt + wt[i];
AroundTime:%d",t_tat/n);
getch();
1 21 84 63
2 18 72 54
3 12 48 36
4 30 96 66
5 15 81 66
Result:
Thus the program to implement the Round Robin CPU scheduling Algorithm was
a) Sequential
b) Indexed
c) Linked
Theory:
Files are normally stored on the disks. So the main problem is how to allocate space
to those files. So that disk space is utilized effectively and files can be accessed quickly.
Three major strategies of allocating disc space are in wide use. Sequential, indexed and
linked.
a Sequential allocation :
In this allocation strategy, each file occupies a set of
contiguously blocks on the disk. This strategy is best suited. For
sequential files. The file allocation table consists of a single entry for
each file. It shows the filenames, staring block of the file and size of
the file. The main problem of this strategy is, it is difficult to find the
contiguous free blocks in the disk and some free blocks could happen
between two files.
b Indexed allocation :
Indexed allocation supports both sequential and direct access
files. Te file indexes are not physically stored as a part of the file
allocation table. Whenever the file size increases, we can easily add
some more blocks to the index. In this strategy, the file allocation table
contains a single entry for each file. The entry consisting of one index
block, the index blocks having the pointers to the other blocks. No
external fragmentation.
c Linked allocation :
It is easy to allocate the files, because allocation is on an
individual block basis. Each block contains a pointer to the next free
block in the chain. Here also the file allocation table consisting of a
single entry for each file. Using this strategy any free block can be
added to a chain very easily. There is a link between one block to
another block, that’s why it is said to be linked allocation. We can
avoid the external fragmentation.
EX.No:4a Sequential File allocation
Aim:
To write a program to implement the sequential file allocation
Algorithm:
Program:
#include<stdio.h>
#include<conio.h>
#include<process.h>
struct sequence
{
char n[20];
int i;
}s[20];
int create(int);
int del(int);
void display(int);
void main()
{
int x=0,j=0;
clrscr();
while(1)
{
printf("1.creation\n2.delete\n3.display\n4.exit");
printf("\nenter one option");
scanf("%d",&x);
switch(x)
{
case 1: j=create(j);
break;
case 2: j=del(j);
break;
case 3: display(j);
break;
case 4: exit(1);
default : printf("wrong option");
} }}
int create(int j)
{
int m,v;
j++;
w:printf("\nenter the file name:");
scanf("%s",&s[j].n);
m=1;
while(m<j)
{
v=strcmp(s[j].n,s[m].n);
if(v==0)
{
printf("file is already exist\nplease enter another name");
goto w;
}
m++;
}
printf("\nenter field:");
scanf("%d",&s[j].i);
return(j);
}
int del(int j)
{
j--;
return(j);
}
void display(int j)
{
int l;
printf("filename\tfield");
for(l=1;l<=j;l++)
printf("\n%s\t\t%d\n",s[l].n,s[l].i);
}
Output:
1.creation
2.delete
3.display
4.exit
enter one option1
enter the file name:1.c
enter field:1
1.creation
2.delete
3.display
4.exit
enter one option1
enter field:2
1.creation
2.delete
3.display
4.exit
enter one option3
filename field
1.c 1
2.c 2
1.creation
2.delete
3.display
4.exit
enter one option4
Result :
Thus a program to implement sequential file allocation is implemented and verified using
sample inputs
Algorithm:
Source code:
#include<stdio.h>
#include<conio.h>
#include<string.h>
struct file
{
char n[20];
int fld,ind;
}s[20];
int no,i=-1,a,b,f,j=-1,fe,t;
char tem[20];
void create();
void display();
void del();
void main()
{
clrscr();
while(1)
{
printf("\n\nmenu");
printf("\n1.create\n2.display\n3.delete\n4.exit");
printf("enter ur choice:");
scanf("%d",&no);
switch(no)
{
case 1: create();
break;
case 2: display();
break;
case 3: del();
break;
case 4: exit(0);
default: printf("wrong choice");
}
}
}
void create()
{
i++;
printf("\nenter the name of the recoed:");
scanf("%s",&s[i].n);
printf("\nenter the index no:");
scanf("%d",&s[i].ind);
printf("\nenter the field no:");
scanf("%d",&s[i].fld);
j++;
}
void display()
{
for(a=0;a<i;a++)
{
for(b=0;b<i;b++)
{
if(s[b].ind>s[b+1].ind)
{
t=s[b].ind;
s[b].ind=s[b+1].ind;
s[b+1].ind=t;
strcpy(tem,s[b].n);
strcpy(s[b].n,s[b+1].n);
strcpy(s[b+1].n,tem);
t=s[b].fld;
s[b].fld=s[b+1].fld;
s[b+1].fld=t;
}
else
continue;
}
}
printf("\n ---------------------------------");
printf("\n\t Index Recordname FieldNo");
for(i=0;i<=j;i++)
{
printf("\n\t%d\t",s[i].ind);
printf("\t%s",s[i].n);
printf("\t%d",s[i].fld);
}
i--;
printf("\n -----------------------------------\n");
}
void del()
{
int de,index=-1,k=0,l;
if(i!=-1)
{
printf("enter index no to be deleted");
scanf("%d",&de);
index=de;
while(s[k].ind!=de)
{
k++;
printf("\n\t\t\t%d",k);
}
for(l=k;l<=j;l++)
s[l]=s[l+1];
i--;
j--;
printf("\nindex no %d file is deleted",index);
}
}
Output:
menu
1.create
2.display
3.delete
4.exitenter ur choice:1
menu
1.create
2.display
3.delete
4.exitenter ur choice:2
---------------------------------
Index Recordname FieldNo
0 a.java 1
1 b.c 2
-----------------------------------
menu
1.create
2.display
3.delete
4.exitenter ur choice:4
Result :
Thus a program to implement indexed file allocation is implemented and verified using
sample inputs
Ex.No:4c
Linked File Allocation
Aim:
To write a program to implement the Linked file allocation.
Algorithm:
Source code:
#include<stdio.h>
#include<stdlib.h>
typedef struct
{
int bno,flag,next;
}block;
block b[200],b1;
void main()
{
int rnum();
int i,n,s,s1,p[30],r,k[20];
clrscr();
printf("\nEnter number of programs:");
scanf("%d",&n);
printf("\nEnter the memory block request");
for(i=1;i<=n;i++)
{
printf("\nEnter program requirement");
scanf("%d",&p[i]);
}
for(i=1;i<=n;i++)
{
s=rnum();
b[s].bno=0;
b[s].flag=1;
k[i]=0;
r=p[i]-1;
while(r!=0)
{
s1=rnum();
b[s].next=s1;
b[s1].flag=1;
b[s1].bno=0;
s=s1;
r=r-1;
}
b[s1].next=NULL;
}
printf("\n Starting blocks for program");
for(i=1;i<=n;i++)
printf("\n%5d%5d",i,k[i]);
printf("\n allocated blocks");
for(i=1;i<=200;i++)
{
if(b[i].flag==1)
printf("\n%5d%5d",b[i].bno,b[i].next);
}
}
int rnum()
{
int k,i;
for(i=1;i<=200;i++)
{
k=rand()%200;
if(b[i].flag!=1)
break;
}
return k;
}
Output:
Enter number of programs:2
Result :
Thus a program to implement Linked file allocation is implemented and verified using
sample inputs
Ex.No:5 Producer-Consumer problems Using Semaphores
Aim
To synchronize producer and consumer processes using semaphore.
Algorithm
1. Create a shared memory segment BUFSIZE of size 1 and attach it.
2. Obtain semaphore id for variables empty, mutex and full using semget function.
3. Create semaphore for empty, mutex and full as follows:
a. Declare semun, a union of specific commands.
b. The initial values are: 1 for mutex, N for empty and 0 for full
c. Use semctl function with SETVAL command
4. Create a child process using fork system call.
a. Make the parent process to be the producer
b. Make the child process to the consumer
5. The producer produces 5 items as follows:
a. Call wait operation on semaphores empty and mutex using semop function.
b. Gain access to buffer and produce data for consumption
c. Call signal operation on semaphores mutex and full using semop function.
6. The consumer consumes 5 items as follows:
a. Call wait operation on semaphores full and mutex using semop function.
b. Gain access to buffer and consume the available data.
c. Call signal operation on semaphores mutex and empty using semop function.
7. Remove shared memory from the system using shmctl with IPC_RMID argument
8. Stop
Program
/* Producer-Consumer problem using semaphore – pcsem.c */
Output
$ gcc pcsem.c
$ ./a.out
Enter data for producer to produce : 5
Enter data for producer to produce : 8
Consumer consumes data 5
Enter data for producer to produce : 4
Consumer consumes data 8
Enter data for producer to produce : 2
Consumer consumes data 4
Enter data for producer to produce : 9
Consumer consumes data 2
Consumer consumes data 9
Result
Thus synchronization between producer and consumer process for access to a shared
memory segment is implemented.
18
Ex.No:6 File Organization Techniques
Theory:
The directory contains information about the files, including attributes, location and
ownership. Sometimes the directories consisting of subdirectories also. The directory is itself a file,
owned by the o.s and accessible by various file management routines.
a)Single Level Directories: It is the simplest of all directory structures, in this the directory system
having only one directory, it consisting of the all files. Sometimes it is said to be root directory. The
following dig. Shows single level directory that contains four files (A, B, C, D).
Root
Directory
A B C D
It has the simplicity and ability to locate files quickly. it is not used in the multi-user system, it is used
on small embedded system.
b) Two Level Directory: The problem in single level directory is different users may be accidentally
using the same names for their files. To avoid this problem, each user need a private directory. In this
way names chosen by one user don’t interface with names chosen by a different user. The following
dig 2-level directory
Root
Directory
c) Hierarchical Directory: The two level directories eliminate name conflicts among users but it is
not satisfactory for users but it is not satisfactory for users with a large no of files. To avoid this, create
the subdirectory and load the same type of the files into the subdirectory. So, in this method each can
have as many directories are needed.
Root
Directory
A B C D
This directory structure looks like tree, that’s why it is also said to be tree-level directory
structure
d) General graph Directory: When we add links to an existing tree structured directory, the
tree structure is destroyed, resulting in a simple graph structure. This structure is used to
traversing is easy and file sharing also possible.
Root
Directory
A B C D
Ex.No:6a Single Level Directory
Aim:
To write a program to implement a single level directory structure.
Algorithm:
Source Code:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
#include<graphics.h>
void main()
{
int gd=DETECT,gm,count,i,j,mid,cir_x;
char fname[10][20];
clrscr();
initgraph(&gd,&gm,"c:\\tc\\bgi");
cleardevice();
setbkcolor(GREEN);
puts("Enter no of files do u have?");
scanf("%d",&count);
for(i=0;i<count;i++)
{
cleardevice();
setbkcolor(GREEN);
printf("Enter file %d name",i+1);
scanf("%s",fname[i]);
setfillstyle(1,MAGENTA);
mid=640/count;
cir_x=mid/3;
bar3d(270,100,370,150,0,0);
settextstyle(2,0,4);
settextjustify(1,1);
outtextxy(320,125,"Root Directory");
setcolor(BLUE);
for(j=0;j<=i;j++,cir_x+=mid)
{
line(320,150,cir_x,250);
fillellipse(cir_x,250,30,30);
outtextxy(cir_x,250,fname[j]);
}
getch();
}}
Output:
Enter no of files do u have?
3
Root Directory
1.c
Root Directory
1.c
2.c
Root Directory
Result:
Thus a program to implement the single level directory is implemented, verified using
sample inputs
Ex.No:6b Two Level Directory
Aim:
To write a program to implement the two level directory structure
Algorithm:
SLD
Tld
bin
obj
hir dag exe
Result:
Thus a program to implement the two level directories is implemented, verified using
sample inputs
Ex.No:6c Hierarchical Directory
Aim:
To write a program to implement the single hierarchical directory
Algorithm:
Source Code:
#include<stdio.h>
#include<graphics.h>
struct tree_element
{
char name[20];
int x,y,ftype,lx,rx,nc,level;
struct tree_element *link[5];
};
typedef struct tree_element node;
void main()
{
int gd=DETECT,gm;
node *root;
root=NULL;
clrscr();
create(&root,0,"root",0,639,320);
clrscr();
initgraph(&gd,&gm,"c:\\tc\\BGI");
display(root);
getch();
closegraph();
}
create(node **root,int lev,char *dname,int lx,int rx,int x)
{
int i,gap;
if(*root==NULL)
{
(*root)=(node *)malloc(sizeof(node));
printf("Enter name of dir/file(under %s) : ",dname);
fflush(stdin);
gets((*root)->name);
printf("enter 1 for Dir/2 for file :");
scanf("%d",&(*root)->ftype);
(*root)->level=lev;
(*root)->y=50+lev*50;
(*root)->x=x;
(*root)->lx=lx;
(*root)->rx=rx;
for(i=0;i<5;i++)
(*root)->link[i]=NULL;
if((*root)->ftype==1)
{
printf("No of sub directories/files(for %s):",(*root)->name);
scanf("%d",&(*root)->nc);
if((*root)->nc==0)
gap=rx-lx;
else
gap=(rx-lx)/(*root)->nc;
for(i=0;i<(*root)->nc;i++)
create(&((*root)->link[i]),lev+1,
(*root)->name,lx+gap*i,lx+gap*i+gap,lx+gap*i+gap/2);
}
else
(*root)->nc=0;
}
}
display(node *root)
{
int i;
settextstyle(2,0,4);
settextjustify(1,1);
setfillstyle(1,BLUE);
setcolor(14);
if(root !=NULL)
{
for(i=0;i<root->nc;i++)
{
line(root->x,root->y,root->link[i]->x,root->link[i]->y);
}
if(root->ftype==1)
bar3d(root->x-20,root->y-10,root->x+20,root->y+10,0,0);
else
fillellipse(root->x,root->y,20,20);
outtextxy(root->x,root->y,root->name);
for(i=0;i<root->nc;i++)
{
display(root->link[i]);
} } }
Output:
Enter Name of dir/file (under root): ROOT
Enter 1 for Dir / 2 For File : 1
No of subdirectories / files (for ROOT) :2
Enter Name of dir/file (under ROOT): USER 1
Enter 1 for Dir /2 for file:1
No of subdirectories /files (for USER 1): 1
Enter Name of dir/file (under USER 1):SUBDIR
Enter 1 for Dir /2 for file:1
No of subdirectories /files (for SUBDIR): 2
Enter Name of dir/file (under USER 1):JAVA
Enter 1 for Dir /2 for file:1
No of subdirectories /files (for JAVA): 0
Enter Name of dir/file (under SUBDIR):VB
Enter 1 for Dir /2 for file:1
No of subdirectories /files (for VB): 0
Enter Name of dir/file (under ROOT):USER2
Enter 1 for Dir /2 for file:1
No of subdirectories /files (for USER2): 2
Enter Name of dir/file (under ROOT):A
Enter 1 for Dir /2 for file:2
Enter Name of dir/file (under USER2):SUBDIR 2
Enter 1 for Dir /2 for file:1
No of subdirectories /files (for SUBDIR 2): 2
Enter Name of dir/file (under SUBDIR2):PPL
Enter 1 for Dir /2 for file:1
No of subdirectories /files (for PPL): 2
Enter Name of dir/file (under PPL):B
Enter 1 for Dir /2 for file:2
Enter Name of dir/file (under PPL):C
Enter 1 for Dir /2 for file:2
Enter Name of dir/file (under SUBDIR):AI
Enter 1 for Dir /2 for file:1
No of subdirectories /files (for AI): 2
Enter Name of dir/file (under AI):D
Enter 1 for Dir /2 for file:2
Enter Name of dir/file (under AI):E
Enter 1 for Dir /2 for file:2
Output: ROOT
USER 1 USER 2
SUBDIR1
A SUBDIR2
JAVA
VB
PPL AL
B C E
D
Result:
Thus a program to implement Hierarchical directory is implemented, verified using
sample inputs
Ex.No:6d DAG Directory
Aim:
To write a program to implement a DAG Directory structure
Algorithm:
Source Code:
#include<stdio.h>
#include<conio.h>
#include<graphics.h>
#include<string.h>
struct tree_element
{
char name[20];
int x,y,ftype,lx,rx,nc,level;
struct tree_element *link[5];
};
typedef struct tree_element node;
typedef struct
{
char from[20];
char to[20];
}link;
link L[10];
int nofl;
node * root;
void main()
{
int gd=DETECT,gm;
root=NULL;
clrscr();
create(&root,0,"root",0,639,320);
read_links();
clrscr();
initgraph(&gd,&gm,"c:\\tc\\BGI");
draw_link_lines();
display(root);
getch();
closegraph();
}
read_links()
{
int i;
printf("how many links");
scanf("%d",&nofl);
for(i=0;i<nofl;i++)
{
printf("File/dir:");
fflush(stdin);
gets(L[i].from);
printf("user name:");
fflush(stdin);
gets(L[i].to);
}
}
draw_link_lines()
{
int i,x1,y1,x2,y2;
for(i=0;i<nofl;i++)
{
search(root,L[i].from,&x1,&y1);
search(root,L[i].to,&x2,&y2);
setcolor(LIGHTGREEN);
setlinestyle(3,0,1);
line(x1,y1,x2,y2);
setcolor(YELLOW);
setlinestyle(0,0,1);
}
}
search(node *root,char *s,int *x,int *y)
{
int i;
if(root!=NULL)
{
if(strcmpi(root->name,s)==0)
{
*x=root->x;
*y=root->y;
return;
}
else
{
for(i=0;i<root->nc;i++)
search(root->link[i],s,x,y);
}
}
}
create(node **root,int lev,char *dname,int lx,int rx,int x)
{
int i,gap;
if(*root==NULL)
{
(*root)=(node *)malloc(sizeof(node));
printf("enter name of dir/file(under %s):",dname);
fflush(stdin);
gets((*root)->name);
printf("enter 1 for dir/ 2 for file:");
scanf("%d",&(*root)->ftype);
(*root)->level=lev;
(*root)->y=50+lev*50;
(*root)->x=x;
(*root)->lx=lx;
(*root)->rx=rx;
for(i=0;i<5;i++)
(*root)->link[i]=NULL;
if((*root)->ftype==1)
{
printf("no of sub directories /files (for %s):",(*root)->name);
scanf("%d",&(*root)->nc);
if((*root)->nc==0)
gap=rx-lx;
else
gap=(rx-lx)/(*root)->nc;
for(i=0;i<(*root)->nc;i++)
create( & ( (*root)->link[i] ) , lev+1 ,
(*root)->name,lx+gap*i,lx+gap*i+gap,lx+gap*i+gap/2);
}
else
(*root)->nc=0;
}
}
/* displays the constructed tree in graphics mode */
display(node *root)
{
int i;
settextstyle(2,0,4);
settextjustify(1,1);
setfillstyle(1,BLUE);
setcolor(14);
if(root !=NULL)
{
for(i=0;i<root->nc;i++)
{
line(root->x,root->y,root->link[i]->x,root->link[i]->y);
}
if(root->ftype==1)
bar3d(root->x-20,root->y-10,root->x+20,root->y+10,0,0);
else
fillellipse(root->x,root->y,20,20);
outtextxy(root->x,root->y,root->name);
for(i=0;i<root->nc;i++)
{
display(root->link[i]);
}}}
Output:
Result:
Thus a program to implement a DAG directory is implemented, and verified
using the sample inputs.
Aim:
To implement deadlock avoidance & Prevention by using Banker’s Algorithm.
Deadlock avoidance & Dead Lock Prevention
Banker’s Algorithm:
When a new process enters a system, it must declare the maximum number of
instances of each resource type it needed. This number may exceed the total number of
resources in the system. When the user request a set of resources, the system must
determine whether the allocation of each resources will leave the system in safe state. If
it will the resources are allocation; otherwise the process must wait until some other
process release the resources.
Data structures
• N-Number of process, m-number of resource types.
• Available: Available[j]=k, k – instance of resource type Rj is available.
• Max: If max[i, j]=k, Pi may request at most k instances resource Rj.
• Allocation: If Allocation [i, j]=k, Pi allocated to k instances of resource Rj
• Need: If Need[I, j]=k, Pi may need k more instances of resource type Rj,
Need[I, j]=Max[I, j]-Allocation[I, j];
Safety Algorithm
1. Work and Finish be the vector of length m and n respectively, Work=Available
and Finish[i] =False.
2. Find an i such that both
• Finish[i] =False
• Need<=Work
If no such I exists go to step 4.
3. work=work+Allocation, Finish[i] =True;
4. if Finish[1]=True for all I, then the system is in safe state.
Let Request i be request vector for the process Pi, If request i=[j]=k, then
process Pi wants k instances of resource type Rj.
1. if Request<=Need I go to step 2. Otherwise raise an error condition.
2. if Request<=Available go to step 3. Otherwise Pi must since the resources are
available.
3. Have the system pretend to have allocated the requested resources to process Pi
by modifying the state as follows;
Available=Available-Request I;
Allocation I =Allocation+Request I;
Need i=Need i-Request I;
If the resulting resource allocation state is safe, the transaction is completed and process
Pi is allocated its resources. However if the state is unsafe, the Pi must wait for Request
i and the old resource-allocation state is restored.
ALGORITHM:
1. Start the program.
2. Get the values of resources and processes.
3. Get the avail value.
4. After allocation find the need value.
5. Check whether it’s possible to allocate.
6. If it is possible then the system is in safe state.
7. Else system is not in safety state.
8. If the new request comes then check that the system is in safety. or not if we
allow the request.
9. Stop the program.
* BANKER’S ALGORITHM */
#include<stdio.h>
#include<conio.h>
struct da
{
int max[10],a1[10],need[10],before[10],after[10];
}p[10];
void main()
{
int i,j,k,l,r,n,tot[10],av[10],cn=0,cz=0,temp=0,c=0;
clrscr();
printf("\n ENTER THE NO. OF PROCESSES:");
scanf("%d",&n);
printf("\n ENTER THE NO. OF RESOURCES:");
scanf("%d",&r);
for(i=0;i<n;i++)
{
printf("PROCESS %d \n",i+1);
for(j=0;j<r;j++)
{
printf("MAXIMUM VALUE FOR RESOURCE %d:",j+1);
scanf("%d",&p[i].max[j]);
}
for(j=0;j<r;j++)
{
printf("ALLOCATED FROM RESOURCE %d:",j+1);
scanf("%d",&p[i].a1[j]);
p[i].need[j]=p[i].max[j]-p[i].a1[j];
}
}
for(i=0;i<r;i++)
{
printf("ENTER TOTAL VALUE OF RESOURCE %d:",i+1);
scanf("%d",&tot[i]);
}
for(i=0;i<r;i++)
{
for(j=0;j<n;j++)
temp=temp+p[j].a1[i];
av[i]=tot[i]-temp;
temp=0;
}
printf("\n\t RESOURCES ALLOCATED NEEDED TOTAL AVAIL");
for(i=0;i<n;i++)
{
printf("\n P%d \t",i+1);
for(j=0;j<r;j++)
printf("%d",p[i].max[j]);
printf("\t");
for(j=0;j<r;j++)
printf("%d",p[i].a1[j]);
printf("\t");
for(j=0;j<r;j++)
printf("%d",p[i].need[j]);
printf("\t");
for(j=0;j<r;j++)
{
if(i==0)
printf("%d",tot[j]);
}
printf(" ");
for(j=0;j<r;j++)
{
if(i==0)
printf("%d",av[j]);
}
}
printf("\n\n\t AVAIL BEFORE\T AVAIL AFTER ");
for(l=0;l<n;l++)
{
for(i=0;i<n;i++)
{
for(j=0;j<r;j++)
{
if(p[i].need[j] >av[j])
cn++;
if(p[i].max[j]==0)
cz++;
}
if(cn==0 && cz!=r)
{
for(j=0;j<r;j++)
{
p[i].before[j]=av[j]-p[i].need[j];
p[i].after[j]=p[i].before[j]+p[i].max[j];
av[j]=p[i].after[j];
p[i].max[j]=0;
}
printf("\n P %d \t",i+1);
for(j=0;j<r;j++)
printf("%d",p[i].before[j]);
printf("\t");
for(j=0;j<r;j++)
printf("%d",p[i].after[j]);
cn=0;
cz=0;
c++;
break;
}
else
{
cn=0;cz=0;
}
}
}
if(c==n)
printf("\n THE ABOVE SEQUENCE IS A SAFE SEQUENCE");
else
printf("\n DEADLOCK OCCURED");
getch();
}
Output:
//TEST CASE 1:
//TEST CASE:2
Result:
Thus a program to implement the Banker’s algorithm for deadlock avoidance
and prevention is implemented and verified using sample inputs.
Aim
To implement demand paging for a reference string using FIFO method.
Algorithm
1. Get length of the reference string, say l.
2. Get reference string and store it in an array, say rs.
3. Get number of frames, say nf.
4. Initalize frame array upto length nf to -1.
5. Initialize position of the oldest page, say j to 0.
6. Initialize no. of page faults, say count to 0.
7. For each page in reference string in the given order, examine:
a. Check whether page exist in the frame array
b. If it does not exist then
i. Replace page in position j.
ii. Compute page replacement position as (j+1) modulus nf.
iii. Increment count by 1.
iv. Display pages in frame array.
8. Print count.
9. Stop
Program
/* FIFO page replacement - fifopr.c */
#include <stdio.h>
main()
{
int i,j,l,rs[50],frame[10],nf,k,avail,count=0;
printf("Enter length of ref. string : "); scanf("%d", &l);
printf("Enter reference string :\n"); for(i=1; i<=l; i+
+)
scanf("%d", &rs[i]); printf("Enter number of
frames : "); scanf("%d", &nf);
for(i=0; i<nf; i++)
frame[i] = -1;
j = 0;
printf("\nRef. str Page frames"); for(i=1; i<=l;
i++)
{
printf("\n%4d\t", rs[i]); avail = 0;
for(k=0; k<nf; k++) if(frame[k]
== rs[i])
avail = 1;
if(avail == 0)
{
frame[j] = rs[i]; j =
(j+1) % nf; count++;
for(k=0; k<nf; k++) printf("%4d",
frame[k]);
}
}
printf("\n\nTotal no. of page faults : %d\n",count);
}
Output
$ gcc fifopr.c
$ ./a.out
Enter length of ref. string : 20 Enter
reference string :
1 2 3 4 2 1 5 6 2 1 2 3 7 6 3 2 1 2 3 6 Enter number of
frames : 5
Ref. str Page frames
1 1 -1 -1 -1 -1
2 1 2 -1 -1 -1
3 1 2 3 -1 -1
4 1 2 3 4 -1
2
1
5 1 2 3 4 5
6 6 2 3 4 5
2
1 6 1 3 4 5
2 6 1 2 4 5
3 6 1 2 3 5
7 6 1 2 3 7
6
3
2
1
2
3
6
Total no. of page faults: 10
Result
Thus page replacement was implemented using FIFO algorithm.
Aim
To implement demand paging for a reference string using LFU method.
Algorithm
1. Get length of the reference string, say len.
2. Get reference string and store it in an array, say rs.
3. Get number of frames, say nf.
4. Create access array to store counter that indicates a measure of recent usage.
5. Create a function arrmin that returns position of minimum of the given array.
6. Initalize frame array upto length nf to -1.
7. Initialize position of the page replacement, say j to 0.
8. Initialize freq to 0 to track page frequency
9. Initialize no. of page faults, say count to 0.
10. For each page in reference string in the given order, examine:
a. Check whether page exist in the frame array.
b. If page exist in memory then
i. Store incremented freq for that page position in access array.
c. If page does not exist in memory then
i. Check for any empty frames.
ii. If there is an empty frame,
Assign that frame to the page
Store incremented freq for that page position in access
array. Increment count.
iii. If there is no free frame then
Determine page to be replaced using arrmin function.
Store incremented freq for that page position in access
array. Increment count.
iv. Display pages in frame array.
11. Print count.
12. Stop
Program
/* LFU page replacement - lfupr.c */
#include<stdio.h>
int arrmin(int[],int);
main()
{
int i,j,len,rs[50],frame[10],nf,k,avail,count=0;
int access[10],freq=0,dm;
printf("length of reference string:");
scanf("%d",&len);
printf("enter reference string:\n");
for(i=1;i<=len;i++)
scanf("%d",&rs[i]);
printf("enter no of frames:");
scanf("%d",&nf);
for(i=0;i<nf;i++)
frame[i]=-1;
j=0;
printf("\n ref.str page frames");
for(i=1;i<=len;i++)
{
printf("\n%4d\t",rs[i]);
avail=0;
for(k=0;k<nf;k++)
{
if(frame[k]==rs[i])
{
avail=1;
access[k]=++freq;
break;
}
}
if(avail==0)
{
dm=0;
for(k=0;k<nf;k++)
{
if(frame[k]==-1)
{
dm=k;
break;
}}
if(dm!=0)
{
k=dm;
frame[k]=rs[i];
access[k]=++freq;
count++;
}
else
{
j=arrmin(access,nf);
frame[j]=rs[i];
access[j]=++freq;
count++;
}
for(k=0;k<nf;k++)
printf("%4d",frame[k]);
}
}
printf("\n\n total no of page faults:%d\n",count);
}
int arrmin(int a[],int n)
{
int i,min=a[0];
for(i=1;i<n;i++)
if(min>a[i])
min=a[i];
for(i=0;i<n;i++)
if(min==a[i])
return i ;
}
Output
$ gcc lfupr.c
$ ./a.out
Length of Reference string : 20 Enter
reference string :
123421562123763 2 1 2 3 6 Enter no. of
frames : 5
Ref. str Page frames
1 1 -1 -1 -1 -1
2 1 2 -1 -1 -1
3 1 2 3 -1 -1
4 1 2 3 4 -1
2
1
5 1 2 3 4 5
6 1 2 6 4 5
2
1
2
3 1 2 6 3 5
7 1 2 6 3 7
6
3
2
1
2
3
6
Total no. of page faults : 8
Result
Thus page replacement was implemented using LFU algorithm.
Ex.No:9c LRU PAGE REPLACEMENT
Aim:
To write a program to implement a LRU page replacement
Algorithm:
FileName: LRU.c
Source code:
#include<stdio.h>
main()
{
int q[20],p[50],c=0,c1,d,f,i,j,k=0,n,r,t,b[20],c2[20];
clrscr();
printf("Enter no of pages:");
scanf("%d",&n);
printf("Enter the reference string:");
for(i=0;i<n;i++) scanf("%d",&p[i]);
printf("Enter no of frames:");
scanf("%d",&f);
q[k]=p[k]; printf("\n\t%d\n",q[k]);
c++;
k++;
for(i=1;i<n;i++)
{
c1=0;
for(j=0;j<f;j++)
{
if(p[i]!=q[j])
c1++;
}
if(c1==f)
{
c++;
if(k<f)
{
q[k]=p[i];
k++;
for(j=0;j<k;j++)
printf("\t%d",q[j]);
printf("\n");
}
else
{
for(r=0;r<f;r++)
{
c2[r]=0;
for(j=i-1;j<n;j--)
{
if(q[r]!=p[j])
c2[r]++;
else
break;
}
}
for(r=0;r<f;r++)
b[r]=c2[r];
for(r=0;r<f;r++)
{
for(j=r;j<f;j++)
{
if(b[r]<b[j])
{
t=b[r];
b[r]=b[j];
b[j]=t;
}
}
}
for(r=0;r<f;r++)
{
if(c2[r]==b[0])
q[r]=p[i];
printf("\t%d",q[r]);
}
printf("\n");
}
}
} printf("\nThe no of page faults is %d",c);
getch(); return 0;
}
Output:
Result:
Thus a program to implement the LRU page replacement algorithm is
written,and verified using sample inputs.
INTERPROCESS COMMUNICATION
Shared memory
• Two or more processes share a single chunk of memory to communicate
randomly.
• Semaphores are generally used to avoid race condition amongst
processes. Fastest amongst all IPCs as it does not require any system call.
• It avoids copying data unnecessarily.
Message Queue
• A message queue is a linked list of messages stored within the
kernel A message queue is identified by a unique identifier
• Every message has a positive long integer type field, a non-negative length, and
the actual data bytes.
• The messages need not be fetched on FCFS basis. It could be based on type
field.
Semaphores
• A semaphore is a counter used to synchronize access to a shared data amongst
multiple processes.
• To obtain a shared resource, the process should:
• Test the semaphore that controls the resource.
• If value is positive, it gains access and decrements value of semaphore.
o If value is zero, the process goes to sleep and awakes when value is > 0.
• When a process relinquishes resource, it increments the value of semaphore by
1.
Producer-Consumer problem
• Producer process produces information to be consumed by a consumer process
A producer can produce one item while the consumer is consuming another one.
With bounded-buffer size, consumer must wait if buffer is empty, whereas
producer must wait if buffer is full.
• The buffer can be implemented using any IPC facility.
Exp#10a Fibonacci & Prime Number
Aim
To generate 25 fibonacci numbers and determine prime amongst them using pipe.
Algorithm
Program
/* Fibonacci and Prime using pipe - fibprime.c */
$ gcc fibprime.c
$ ./a.out
Child process generates Fibonacci series
0 1 1 2 3 5 8 13
21 34 55 89 144 233 377 610
987 1597 2584 4181 6765 10946 17711 28657
46368
Parent prints Fibonacci that are Prime
2 3 5 13 89 233 1597 28657
Result
Thus fibonacci numbers that are prime is determined using IPC pipe.
Exp# 10b who | wc -l
Aim
To determine number of users logged in using pipe.
Algorithm
1. Decalre a array pfd with two elements for pipe descriptors.
2. Create pipe on pfd using pipe function
call. a. If return value is -1 then stop
3. Using fork system call, create a child process.
4. Free the standard output (1) using close system call to redirect the output to
pipe.
5. Make a copy of write end of the pipe using dup system call.
6. Execute who command using execlp system call.
7. Free the standard input (0) using close system call in the other process.
8. Make a close of read end of the pipe using dup system call.
9. Execute wc –l command using execlp system call.
10. Stop
Program
/* No. of users logged - cmdpipe.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int pfds[2];
pipe(pfds);
if (!fork())
{
close(1);
dup(pfds[1]);
close(pfds[0]); execlp("who", "who",
NULL);
}
else
{
close(0);
dup(pfds[0]);
close(pfds[1]);
execlp("wc", "wc", "-l", NULL);
}
}
Output
$ gcc cmdpipe.c
$ ./a.out 15
Result
Thus standard output of who is connected to standard input of wc using pipe to
compute number of users logged in.
Exp# 10c Chat Messaging
Aim
To exchange message between server and client using message queue.
Algorithm
Server
1. Decalre a structure mesgq with type and text fields.
2. Initialize key to 2013 (some random value).
3. Create a message queue using msgget with key & IPC_CREAT as parameter.
a. If message queue cannot be created then stop.
4. Initialize the message type member of mesgq to 1.
5. Do the following until user types Ctrl+D
a. Get message from the user and store it in text member.
b. Delete the newline character in text member.
c. Place message on the queue using msgsend for the client to read.
d. Retrieve the response message from the client using msgrcv function
e. Display the text contents.
6. Remove message queue from the system using msgctl with IPC_RMID as
parameter.
7. Stop
Client
1. Decalre a structure mesgq with type and text fields.
2. Initialize key to 2013 (same value as in server).
3. Open the message queue using msgget with key as parameter.
a. If message queue cannot be opened then stop.
4. Do while the message queue exists
a.Retrieve the response message from the server using msgrcv function
b.Display the text contents.
c.Get message from the user and store it in text member.
d.Delete the newline character in text member.
e. Place message on the queue using msgsend for the server to read.
5. Print "Server Disconnected".
6. Stop
Program
Server
$ ./srvmsg
Enter text, ^D to quit: hi
From Client: "hello" Where
r u?
From Client: "I'm where i am" bye
From Client: "ok" ^D
Client
$ gcc climsg.c -o climsg
Aim
To demonstrate communication between process using shared memory.
Algorithm
Server
1. Initialize size of shared memory shmsize to 27.
2. Initialize key to 2013 (some random value).
3. Create a shared memory segment using shmget with key & IPC_CREAT as parameter.
a. If shared memory identifier shmid is -1, then stop.
4. Display shmid.
5. Attach server process to the shared memory using shmmat with shmid as parameter.
a. If pointer to the shared memory is not obtained, then stop.
6. Clear contents of the shared region using memset function.
7. Write a–z onto the shared memory.
8. Wait till client reads the shared memory contents
9. Detatch process from the shared memory using shmdt system call.
10. Remove shared memory from the system using shmctl with IPC_RMID argument
11. Stop
Client
1. Initialize size of shared memory shmsize to 27.
2. Initialize key to 2013 (same value as in server).
3. Obtain access to the same shared memory segment using same key.
a. If obtained then display the shmid else print "Server not started"
4. Attach client process to the shared memory using shmmat with shmid as parameter.
a. If pointer to the shared memory is not obtained, then stop.
5. Read contents of shared memory and print it.
6. After reading, modify the first character of shared memory to '*'
7. Stop
Program
Server
/* Shared memory server - shms.c */
Client
main()
{
int shmid;
key_t key = 2013; char *shm,
*s;
if ((shmid = shmget(key, shmsize, 0666)) < 0)
{
printf("Server not started\n"); exit(1);
}
else
printf("Accessing shared memory id : %d\n",shmid);
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1)
{
perror("shmat");
exit(1);
}
printf("Shared memory contents:\n"); for (s = shm; *s !
= '\0'; s++)
putchar(*s);
putchar('\n');
*shm = '*';
}
Output
Server
$ gcc shms.c -o shms
$ ./shms
Shared memory id : 196611 Writing (a-z) onto
shared memory Client finished reading
Client
$ gcc shmc.c -o shmc
$ ./shmc
Accessing shared memory id : 196611 Shared memory
contents: abcdefghijklmnopqrstuvwxyz
Result
Thus contents written onto shared memory by the server process is read by the client
process.
Algorithm:
Program:
#include <stdio.h>
#include <conio.h>
struct pstruct
{
int fno;
int pbit;
}ptable[10];
int pmsize,lmsize,psize,frame,page,ftable[20],frameno;
void info()
{
printf("\n\nMEMORY MANAGEMENT USING PAGING\n\n");
printf("\n\nEnter the Size of Physical memory: ");
scanf("%d",&pmsize);
printf("\n\nEnter the size of Logical memory: ");
scanf("%d",&lmsize);
printf("\n\nEnter the partition size: ");
scanf("%d",&psize);
frame = (int) pmsize/psize;
page = (int) lmsize/psize;
printf("\nThe physical memory is divided into %d no.of frames\n",frame);
printf("\nThe Logical memory is divided into %d no.of pages",page);
}
void assign()
{
int i;
for (i=0;i<page;i++)
{
ptable[i].fno = -1;
ptable[i].pbit= -1;
}
for(i=0; i<frame;i++)
ftable[i] = 32555;
for (i=0;i<page;i++)
{
printf("\n\nEnter the Frame number where page %d must be placed: ",i);
scanf("%d",&frameno);
ftable[frameno] = i;
if(ptable[i].pbit == -1)
{
ptable[i].fno = frameno;
ptable[i].pbit = 1;
}
}
getch();
// clrscr();
printf("\n\nPAGE TABLE\n\n");
printf("PageAddress FrameNo. PresenceBit\n\n");
for (i=0;i<page;i++)
printf("%d\t\t%d\t\t%d\n",i,ptable[i].fno,ptable[i].pbit);
printf("\n\n\n\tFRAME TABLE\n\n");
printf("FrameAddress PageNo\n\n");
for(i=0;i<frame;i++)
printf("%d\t\t%d\n",i,ftable[i]);
}
void cphyaddr()
{
int laddr,paddr,disp,phyaddr,baddr;
getch();
// clrscr();
printf("\n\n\n\tProcess to create the Physical Address\n\n");
printf("\nEnter the Base Address: ");
scanf("%d",&baddr);
printf("\nEnter theLogical Address: ");
scanf("%d",&laddr);
Output:
MEMORY MANAGEMENT USING PAGING
Enter the Size of Physical memory: 16
PAGE TABLE
0 5 1
1 6 1
2 7 1
3 2 1
FRAME TABLE
FrameAddress PageNo
0 32555
1 32555
2 3
3 32555
4 32555
5 0
6 1
7 2
Process to create the Physical Address
Enter the Base Address: 1000
Enter theLogical Address: 3
Result:
Thus a program to implement paging technique is written and verified using sample
inputs.
Ex.No:11b Segmentation
Aim:
To implement the memory management policy-segmentation.
Algorithm:
Program:
/*MEMORY SEGMENT TABLE*/
#include <stdio.h>
#include <conio.h>
#include <math.h>
int sost;
void gstinfo();
void ptladdr();
struct segtab
{
int sno;
int baddr;
int limit;
int val[10];
}st[10];
void gstinfo()
{
int i,j;
printf("\n\tEnter the size of the segment table: ");
scanf("%d",&sost);
for(i=1;i<=sost;i++)
{
printf("\n\tEnter the information about segment: %d",i);
st[i].sno = i;
printf("\n\tEnter the base Address: ");
scanf("%d",&st[i].baddr);
printf("\n\tEnter the Limit: ");
scanf("%d",&st[i].limit);
for(j=0;j<st[i].limit;j++)
{
printf("Enter the %d address Value: ",(st[i].baddr + j));
scanf("%d",&st[i].val[j]); }}}
void ptladdr()
{
int i,swd,d=0,n,s,disp,paddr;
clrscr();
printf("\n\n\t\t\t SEGMENT TABLE \n\n");
printf("\n\t SEG.NO\tBASE ADDRESS\t LIMIT \n\n");
for(i=1;i<=sost;i++)
printf("\t\t%d \t\t%d\t\t%d\n\n",st[i].sno,st[i].baddr,st[i].limit);
printf("\n\nEnter the logical Address: ");
scanf("%d",&swd);
n=swd;
while (n != 0)
{
n=n/10;
d++;
}
s = swd/pow(10,d-1);
disp = swd%(int)pow(10,d-1);
if(s<=sost)
{
if(disp < st[s].limit)
{
paddr = st[s].baddr + disp;
printf("\n\t\tLogical Address is: %d",swd);
printf("\n\t\tMapped Physical address is: %d",paddr);
printf("\n\tThe value is: %d",( st[s].val[disp] ) );
}
else
printf("\n\t\tLimit of segment %d is high\n\n",s);
}
else
printf("\n\t\tInvalid Segment Address \n");
}
void main()
{
char ch;
clrscr();
gstinfo();
do
{
ptladdr();
printf("\n\t Do U want to Continue(Y/N)");
flushall();
scanf("%c",&ch);
}while (ch == 'Y' || ch == 'y' );
getch(); }
Output:
SEGMENT TABLE
SEG.NO BASE ADDRESS LIMIT
1 4 5
2 5 4
3 3 4
SEGMENT TABLE
SEG.NO BASE ADDRESS LIMIT
1 4 5
2 5 4
3 3 4
Result:
Thus a program to implement the memory management technique – segmentation is
written, implemented and verified using sample inputs.
Ex.No:12 Threading And Synchronization Application
Aim:
To write a program to implement the threading and synchronization application.
Algorithm1:
1. Start the program
2. Declare all the necessary variables
3. Two threads (jobs) are created and in the start function of these threads, a counter
is maintained through which user gets the logs about job number which is started
and when it is completed.
4. Stop the program.
pthread_t tid[2];
int counter;
for(i=0; i<(0xFFFFFFFF);i++);
printf("\n Job %d finished\n", counter);
return NULL;
}
int main(void)
{
int i = 0;
int err;
while(i < 2)
{
err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
i++;
}
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
return 0;
}
Output 1:
$ ./tgsthreads
Job 1 started
Job 2 started
Job 2 finished
Job 2 finished
If you focus on the last two logs, you will see that the log ‘Job 2 finished’ is repeated twice
while no log for ‘Job 1 finished’ is seen.
Now, if you go back at the code and try to find any logical flaw, you’ll probably not find any
flaw easily. But if you’ll have a closer look and visualize the execution of the code, you’ll
find that :
• The log ‘Job 2 started’ is printed just after ‘Job 1 Started’ so it can easily be
concluded that while thread 1 was processing the scheduler scheduled the thread 2.
• If the above assumption was true then the value of the ‘counter’ variable got
incremented again before job 1 got finished.
• So, when Job 1 actually got finished, then the wrong value of counter produced the
log ‘Job 2 finished’ followed by the ‘Job 2 finished’ for the actual job 2 or vice versa
as it is dependent on scheduler.
• So we see that its not the repetitive log but the wrong value of the ‘counter’ variable
that is the problem.
The actual problem was the usage of the variable ‘counter’ by second thread when the first
thread was using or about to use it. In other words we can say that lack of synchronization
between the threads while using the shared resource ‘counter’ caused the problems or in one
word we can say that this problem happened due to ‘Synchronization problem’ between two
threads.
Mutexes
Now since we have understood the base problem, lets discuss the solution to it. The most
popular way of achieving thread synchronization is by using Mutexes.
A Mutex is a lock that we set before using a shared resource and release after using it. When
the lock is set, no other thread can access the locked region of code. So we see that even if
thread 2 is scheduled while thread 1 was not done accessing the shared resource and the code
is locked by thread 1 using mutexes then thread 2 cannot even access that region of code. So
this ensures a synchronized access of shared resources in the code.
Internally it works as follows :
• Suppose one thread has locked a region of code using mutex and is executing that
piece of code.
• Now if scheduler decides to do a context switch, then all the other threads which are
ready to execute the same region are unblocked.
• Only one of all the threads would make it to the execution but if this thread tries to
execute the same region of code that is already locked then it will again go to sleep.
• Context switch will take place again and again but no thread would be able to execute
the locked region of code until the mutex lock over it is released.
• Mutex lock will only be released by the thread who locked it.
• So this ensures that once a thread has locked a piece of code then no other thread can
execute the same region until it is unlocked by the thread who locked it.
• Hence, this system ensures synchronization among the threads while working on
shared resources.
A mutex is initialized and then a lock is achieved by calling the following two functions :
int pthread_mutex_init(pthread_mutex_t *restrict mutex, const pthread_mutexattr_t *restrict
attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
The first function initializes a mutex and through second function any critical region in the
code can be locked.
The mutex can be unlocked and destroyed by calling following functions :
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
The first function above releases the lock and the second function destroys the lock so that it
cannot be used anywhere in future.
A Practical Example
Lets see a piece of code where mutexes are used for thread synchronization
#include<stdio.h>
#include<string.h>
#include<pthread.h>
#include<stdlib.h>
#include<unistd.h>
pthread_t tid[2];
int counter;
pthread_mutex_t lock;
unsigned long i = 0;
counter += 1;
printf("\n Job %d started\n", counter);
for(i=0; i<(0xFFFFFFFF);i++);
int main(void)
{
int i = 0;
int err;
if (pthread_mutex_init(&lock, NULL) != 0)
{
printf("\n mutex init failed\n");
return 1;
}
while(i < 2)
{
err = pthread_create(&(tid[i]), NULL, &doSomeThing, NULL);
if (err != 0)
printf("\ncan't create thread :[%s]", strerror(err));
i++;
}
pthread_join(tid[0], NULL);
pthread_join(tid[1], NULL);
pthread_mutex_destroy(&lock);
return 0;
}
In the code above:
• A mutex is initialized in the beginning of the main function.
• The same mutex is locked in the ‘doSomeThing()’ function while using the shared
resource ‘counter’
• At the end of the function ‘doSomeThing ()’ the same mutex is unlocked.
• At the end of the main function when both the threads are done, the mutex is
destroyed.
Now if we look at the output, we find:
$ ./threads
Job 1 started
Job 1 finished
Job 2 started
Job 2 finished
So we see that this time the start and finish logs of both the jobs were present. So thread
synchronization took place by the use of Mutex.
Result:
a.) Sockets
b.) Pipes
c.) Shared memory
d.) Signals
e.) Message Queues
17. What is a semaphore?
- A semaphore is a hardware or a software tag variable whose value indicates the status of a
common resource.
- Its purpose is to lock the common resource being used. A process which needs the resource
will check the semaphore to determine the status of the resource followed by the decision for
proceeding.
- In multitasking operating systems, the activities are synchronized by using the semaphore
techniques.
18. What kind of operations are possible on a semaphore?
Two kind of operations are possible on a semaphore - 'wait' and 'signal'.
19. What is context switching?
- Context is associated with each process encompassing all the information describing the
current execution state of the process
- When the OS saves the context of program that is currently running and restores the context
of the next ready to run process, it is called as context switching.
- It is important for multitasking OS.
- Mutex
- Semaphores
- Monitors
- Condition variables
- Critical regions
- Read/ Write locks
23. What is the basic difference between pre-emptive and non-pre-emptive scheduling.
Pre-emptive scheduling allows interruption of a process while it is executing and taking the
CPU to another process while non-pre-emptive scheduling ensures that a process keeps the
CPU under control until it has completed execution.
24. Is non-pre-emptive scheduling frequently used in a computer? Why?
No, it is rarely used for the reasons mentioned below:
- It can not ensure that each user gets a share of CPU regularly.
- The idle time with this increases reducing the efficiency and overall performance of the
system.
- It allows program to run indefinitely which means that other processes have to wait for very
long.
25. Explain condition variable.
- These are synchronization objects which help threads wait for particular conditions to
occur.
- Without condition variable, the thread has to continuously check the condition which is very
costly on the resources.
- Condition variable allows the thread to sleep and wait for the condition variable to give it a
signal.
The set of dispatch able processes is in a safe state if there exists at least one temporal order
in which all processes can be run to completion without resulting in a deadlock.
We encounter cycle stealing in the context of Direct Memory Access (DMA). Either
the DMA controller can use the data bus when the CPU does not need it, or it may force the
CPU to temporarily suspend operation. The latter technique is called cycle stealing. Note that
cycle stealing can be done only at specific break points in an instruction cycle.
47. What is busy waiting?
The repeated execution of a loop of code while waiting for an event to occur is called
busy-waiting.The CPU is not engaged in any real productive activity during this period, and
the process does not progress toward completion.
48. What are local and global page replacements?
Local replacement means that an incoming page is brought in only to the relevant
process address space. Global replacement policy allows any page frame from any process to
be replaced. The latter is applicable to variable partitions model only.
49. Define latency, transfer and seek time with respect to disk I/O.
Seek time is the time required to move the disk arm to the required track. Rotational
delay or latency is the time it takes for the beginning of the required sector to reach the head.
Sum of seek time (if any) and latency is the access time. Time taken to actually transfer a
span of data is transfer time.
50. What are rings in Windows NT?
In Windows NT, executive refers to the operating system code that runs in kernel mode.
53. What are DDks? Name an operating system that includes this feature.
DDks are device driver kits, which are equivalent to SDKs for writing device drivers.
Windows NT includes DDks.
C2 level security.