100% found this document useful (1 vote)
2K views43 pages

CS2257

The document describes the CS 2257 Operating Systems Laboratory course. It outlines 10 exercises including: 1) Writing programs using Unix system calls like fork, exec, wait etc. 2) Simulating Unix commands. 3) Implementing scheduling algorithms and calculating metrics. 4) Developing applications using IPC. 5) Implementing memory management schemes. The document also provides examples and pseudocode for exercises 8 and 9 on implementing free space and memory allocation using linked lists. Hardware requirements include 30 PCs and the software required is Linux which can be loaded on individual PCs or a single server.

Uploaded by

ramauma
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
100% found this document useful (1 vote)
2K views43 pages

CS2257

The document describes the CS 2257 Operating Systems Laboratory course. It outlines 10 exercises including: 1) Writing programs using Unix system calls like fork, exec, wait etc. 2) Simulating Unix commands. 3) Implementing scheduling algorithms and calculating metrics. 4) Developing applications using IPC. 5) Implementing memory management schemes. The document also provides examples and pseudocode for exercises 8 and 9 on implementing free space and memory allocation using linked lists. Hardware requirements include 30 PCs and the software required is Linux which can be loaded on individual PCs or a single server.

Uploaded by

ramauma
Copyright
© Attribution Non-Commercial (BY-NC)
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOC, PDF, TXT or read online on Scribd
You are on page 1/ 43

CS 2257 - Operating Systems Laboratory

CS 2257 OPERATING SYSTEMS LAB 0 0 3 2


(Common to CSE & IT)

(Implement the following on LINUX or other Unix like platform. Use C for high level
language implementation)

1. Write programs using the following system calls of UNIX operating system:
fork, exec, getpid, exit, wait, close, stat, opendir, readdir

2. Write programs using the I/O system calls of UNIX operating system (open, read,
write, etc)

3. Write C programs to simulate UNIX commands like ls, grep, etc.

4. Given the list of processes, their CPU burst times and arrival times, display/print
the Gantt chart for FCFS and SJF. For each of the scheduling policies, compute
and print the average waiting time and average turnaround time. (2 sessions)

5. Given the list of processes, their CPU burst times and arrival times, display/print
the Gantt chart for Priority and Round robin. For each of the scheduling policies,
compute and print the average waiting time and average turnaround time. (2
sessions)

6. Developing Application using Inter Process communication (using shared


memory, pipes or message queues)

7. Implement the Producer – Consumer problem using semaphores (using UNIX


system calls).

8. Implement some memory management schemes – I

9. Implement some memory management schemes – II

10. Implement any file allocation technique (Linked, Indexed or Contiguous)

Example for exercises 8 & 9 :

Free space is maintained as a linked list of nodes with each node having the starting byte
address and the ending byte address of a free block. Each memory request consists of the
process-id and the amount of storage space required in bytes. Allocated memory space is
again maintained as a linked list of nodes with each node having the process-id, starting
byte address and the ending byte address of the allocated space. When a process finishes
(taken as input) the appropriate node from the allocated list should be deleted and
this free disk space should be added to the free space list. [Care should be taken to merge
contiguous free blocks into one single block. This results in deleting more than one node
from the free space list and changing the start and end address in the appropriate node]. For
allocation use first fit, worst fit and best fit.

TOTAL: 45

1
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

Hardware and Software required for a batch of 30 students.

HARDWARE:

30 Personal Computers

SOFTWARE:

Linux:

Ubuntu / OpenSUSE / Fedora / Red Hat / Debian / Mint OS


Linux could be loaded in individual PCs.
(OR)
A single server could be loaded with Linux and connected from the individual PCs.

2
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

1. Process , Directory & File Management system calls

Aim :

To write C programs for the fork, exec, getpid, exit, wait, stat, opendir, readdir
system calls of UNIX operating system.

Description

A system call is just what its name implies - a request for the operating system to do
something on behalf of the user's program. The system calls are functions used in the kernel
itself. To the programmer, the system call appears as a normal C function call. However
since a system call executes code in the kernel, there must be a mechanism to change the
mode of a process from user mode to kernel mode. The C compiler uses a predefined library
of functions (the C library)
that have the names of the system calls. The library functions typically invoke an instruction
that changes the process execution mode to kernel mode and causes the kernel to start
executing code for system calls. The instruction that causes the mode change is often
referred to as an "operating system trap" which is a software generated interrupt.
The library routines execute in user mode, but the system call interface is a special case of
an interrupt handler. The library functions pass the kernel a unique number per system call in
a machine dependent way

getpid, getppid
To get the process and parent process identification number.

General Syntax:

pid_t getpid(void);
pid_t getppid(void);

Description

getpid returns the process ID of the current process. (This is often used by routines that
generate unique temporary file names.)
getppid returns the process ID of the parent of the current process.

fork()

causes the UNIX system to create a new process, called the "child process", with a new
process ID. The contents of the child process are identical to the contents of the parent
process.

The prototype for the fork() system call is:

int fork()

3
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

The new process inherits several characteristics of the old process. Among the
characteristics inherited are:

The environment.
All signal settings.
The set user ID and set group ID status.
The time left until an alarm clock signal.
The current working directory and the root directory.
The file creation mask as established with umask().

The child process begins executing and the parent process continues executing at the
return from the fork() system call. This is difficult to understand at first because you only
call fork() once, yet it returns twice -- once per process. To differentiate which process is
which, fork() returns zero in the child process and non-zero (the child's process ID) in the
parent process.

exec system call

The UNIX system calls that transform a executable binary file into a process are the
"exec" family of system calls. The prototypes for these calls are:

int execl(file_name, arg0 [, arg1, ..., argn], NULL)


char *file_name, *arg0, *arg1, ..., *argn;

wait()

You can control the execution of child processes by calling wait() in the parent. wait()
forces the parent to suspend execution until the child is finished. wait() returns the process
ID of a child process that finished.
If the child finishes before the parent gets around to calling wait(), then when wait() is
called by the parent, it will return immediately with the child's process ID. (It is possible to
have more that one child process by simply calling fork() more than once.). The prototype
for the wait() system call is:

int wait(status)
int *status;

where status is a pointer to an integer where the UNIX system stores the value returned by
the child process. wait() returns the process ID of the process that ended.

exit()

The exit() system call ends a process and returns a value to it parent. The prototype for
the exit() system call is:

void exit(status)
int status;
where status is an integer between 0 and 255.

4
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

Note: since wait() returns the exit status multiplied by 256 (contained in
the upper 8 bits), the status value is shifted right 8 bits (divided by 256)
to obtain the correct value.

File Status

stat() ,fstat() , lstat()

The i-node data structure holds all the information about a file except the file's name and
its contents. Sometimes your programs need to use the information in the i-node structure to
do some job. You can access this information with the stat(), lstat() and fstat() system calls.

opendir - open a directory

SYNOPSIS
#include <sys/types.h>
#include <dirent.h>

DIR *opendir(const char *name);

DESCRIPTION
The opendir() function opens a directory stream corresponding to the directory name,
and returns a pointer to the directory stream. The stream is positioned at the first entry in
the directory.

RETURN VALUE
The opendir() function returns a pointer to the directory stream or NULL if an error
occurred.

readdir - read directory entry

readdir reads one dirent structure from the directory pointed at by fd into the memory area
pointed to by dirp. The parameter count is ignored; at most one dirent structure is read.

int readdir(unsigned int fd, struct dirent *dirp, unsigned int count);

closedir - close a directory


int closedir(DIR *dir);

DESCRIPTION
The closedir() function closes the directory stream associated with dir. The directory
stream descriptor dir is not available after this call.

5
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

Exercises:

/* 1. Program to print the process id */

Algorithm:
1. Include necessary header files for using systems calls.
2. Make necessary declaration.
3. Get the process identification number and parent process identification number using
getpid() and getppid() system calls
4. Display the process id’s

#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>

main()
{
int pid,ppid;
pid=getpid();
ppid=getppid();

printf("\n Process Id is %d\n",pid);


printf("\n Parent Process Id is %d\n",ppid);
}
OUTPUT
process ID is 5198
parent process ID is 5129

/* 2. Program using fork system call */


#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>

main()
{
printf("\n This is to demonstrate the fork()");
fork();
printf("\nAfter fork()");
}
OUTPUT
this is to demonstrate fork()
after fork()

/* 3. fork and pid */


#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>

main()

6
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

{
int pid;
pid=fork();
if(pid==0)
{
printf("\n I am the child, my process ID is %d ",getpid());
printf("\n I am the child's parent process ID is %d ",getppid());
}
else
{
printf("\n I am the parent, my process ID is %d ",getpid());
printf("\n I am the parent's parent process ID is %d ",getppid());
}
}
OUTPUT
i am the parent, my process ID is 5273
i am the parent's parent,process ID is 5129
I am the child, my process ID is 5274
I am the child's parent, process ID is 1

/* 4. orphan process */
#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>

main()
{
int pid;
pid=fork();
if(pid==0)
{
printf("\n I am the child, my process ID is %d ",getpid());
printf("\n I am the child's parent process ID is %d ",getppid());
sleep(10);
printf("\n I am the child, my process ID is %d ",getpid());
printf("\n I am the child's parent process ID is %d ",getppid());

}
else
{
printf("\n I am the parent, my process ID is %d ",getpid());
printf("\n I am the parent's parent process ID is %d ",getppid());
}
}
OUTPUT

I am the child, my process ID is 5301


I am the parent, my process id is 5300

7
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

I am the parent's parent, my process ID is 5129


[it2-21@localhost ~]$ I am the
child's parent, my process ID is 5300
I am the child, my process Id is 5301
I am the child's parent, my process ID is 1

/* 5. exec system call */


#include <sys/types.h>
#include<stdio.h>
#include <unistd.h>
main()
{
execl("/bin/ls", "/bin/ls", "-r", "-t", "-l", (char *) 0);
}
OUTPUT
total 384
-rw-rw-r-- 1 it2-21 it2-21 359 Oct 14 08:24 pol.cpp
-rw-rw-r-- 1 it2-21 it2-21 200 Dec 8 11:35 forks.c
-rw-rw-r-- 1 it2-21 it2-21 102 Dec 14 10:48 exec1.c
-rw-rw-r-- 1 it2-21 it2-21 283 Dec 14 11:06 wait.c
-rw-rw-r-- 1 it2-21 it2-21 246 Dec 14 11:22 exit.c
-rw-rw-r-- 1 it2-21 it2-21 214 Dec 14 11:25 exit1.c
-rw-rw-r-- 1 it2-21 it2-21 393 Dec 14 12:12 opre.c
-rw-rw-r-- 1 it2-21 it2-21 367 Dec 14 12:13 fileinfo.c
-rw-rw-r-- 1 it2-21 it2-21 0 Dec 14 12:20 read.cpp
-rw-rw-r-- 1 it2-21 it2-21 1786 Dec 18 09:50 poly.cpp
-rw-rw-r-- 1 it2-21 it2-21 153 Dec 21 11:31 op.c
-rw-rw-r-- 1 it2-21 it2-21 0 Dec 21 11:32 buf,c
-rw-rw-r-- 1 it2-21 it2-21 197 Dec 21 11:32 buf.c
---------x 1 it2-21 it2-21 0 Dec 21 11:33 fn

/* 6. exec system call */


#include <unistd.h>
#include <sys/types.h>
#include<stdio.h>

main()
{
execl("/bin/date", "date", NULL);
}
OUTPUT
Mon Jan 11 11:08:50 UTC 2010

8
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

/* 7. wait system call */


/* process synchronization */
#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>

main()
{
int pid,i=0;
printf("\n Ready to fork");
pid=fork();
if(pid==0)
{
printf("\n Child starts ");
for(i=0;i<1000;i++);

printf("\n Child ends ");


}
else
{
wait(0);
for(i=0;i<1000;i++);

printf("\n Parent process ends ");


}
}
OUTPUT
ready to fork
child starts
child ends
ready to fork
parent process ends

/* 8. Program using exit system call */


#include <sys/types.h>
#include <unistd.h>
#include<stdio.h>
main()
{
int p;
p=fork();
if(p==0)
{
printf("\n Child created ");
exit(0);
printf("\n Process ended ");

9
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

}
if(p<0)
{
printf("\n Cannnot create child ");
exit(-1);
printf("\n Process ended ");
}
}
OUTPUT
child created

/* 9. Program using exit and wait system call */

#include <sys/types.h>
#include <unistd.h>
#include<stdddio.h>
main()
{

unsigned int status;

if ( fork () == 0 ) { /* == 0 means in child */


scanf ("%d", &status);
exit (status);
}
else { /* != 0 means in parent */
wait (&status);
printf("child exit status = %d\n", status > 8);
}
}
OUTPUT
child exit status=1

/* 10. Program using lstat() system call */


#include<stdio.h>
#include<sys/stat.h>
main(int argc,char **argv)
{

struct stat statbuf;


if(lstat(argv[1],&statbuf)==-1)
printf("Error : cannot find file information ");
else
{
printf("\n File %s ", argv[1]);
printf("\n Inode number %d",statbuf.st_ino);
printf("\n UID %d",statbuf.st_uid);

10
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

printf("\n GID %d",statbuf.st_gid);


printf("\n File size in bytes %d",statbuf.st_size);
}
}
OUTPUT
./a.out opre.c
file opre.cI node number 1387260UID 998GID 999file size in bytes 393

/* 11. Program using opendir and readdir system call */


#include<stdio.h>
#include <sys/types.h>
#include <dirent.h>

int main(int argc, char *argv[])


{
DIR *dp;
struct dirent *dirp;
if (argc != 2) {
printf("a single argument (the directory name) is required\n");
exit(1);
}

if ( (dp = opendir(argv[1])) == NULL) {


printf("can't open %s\n",argv[1]);
exit(1);
}

while ( (dirp = readdir(dp)) != NULL)


printf("%s %d\n",dirp->d_name,dirp->d_ino);
closedir(dp);
exit(0);
}
OUTPUT
./a.out
grep.c 1387273
simu.c 1387274
a.out 1387265
. 1387247
hi 1387233
.. 1387211
rem.c 1387276

Result :

Thus C program was written programs using the fork, exec, getpid, exit, wait, stat,
opendir, readdir system calls of UNIX operating system.

11
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

2. File realated system call – open(), read(), write()

Aim :
To write a C program using open(), read(), write and close system calls.

Description
open()

open() lets you open a file for reading, writing, or reading and writing. The prototype for the
open() system call is:
int open(char *file_name, int option_flags int [, mode])
where file_name is a pointer to the character string that names the file, option_flags represent
the type of channel, and mode defines the file's access permissions if the file is being created.

read() write()

The read() system call does all input and the write() system call does all output.When used
together, they provide all the tools necessary to do input and output sequentially.

Both read() and write() take three arguments. Their prototypes are:

int read(int file_descriptor, char * buffer_pointer,unsigned transfer_size)


int write(int file_descriptor,char * buffer_pointer, unsigned transfer_size)

where file_descriptor identifies the I/O channel, buffer_pointer points to the area in memory
where the data is stored for a read() or where the data is taken for a write(), and transfer_size
defines the maximum number of characters transferred between the file and the buffer. read()
and write() return the number of bytes transferred.

close()
To close a channel, use the close() system call. The prototype for the close() system call is:
int close(int file_descriptor)
where file_descriptor identifies a currently open channel. close() fails if file_descriptor does
not identify a currently open channel.

Exercises
/* 1. using creat system call */

#include <stdio.h>
#include <sys/types.h> /* defines types used by sys/stat.h */
#include <sys/stat.h> /* defines S_IREAD & S_IWRITE */

int main()
{
int fd;
fd = creat("datafile.dat", S_IREAD | S_IWRITE);
if (fd == -1)
printf("Error in opening datafile.dat\n");
else

12
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

{
printf("datafile.dat opened for read/write access\n");
printf("datafile.dat is currently empty\n");
}
close(fd);
exit (0);
}

/* 2. using open, write system call */


#include<fcntl.h>
#include<unistd.h>
main()
{
int fd,i;
fd=open("test",O_CREAT|O_RDWR|O_APPEND,0666);
for(i=0;i<100;i++)
write(fd,"A",1);
close(fd);
}
OUTPUT:
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA

/* 3. using - open ,read and write system calls */


/* reading a content from file and displaying it to monitor */
#include<stdio.h>
#include<fcntl.h>
main()
{
char buf[100],fn[10];
int fd,n;
printf("Enter file name ");
scanf("%s",fn);
fd=open(fn,O_RDONLY);
n=read(fd,buf,100);
n=write(1,buf,n);//write to monitor
close(fd);
}
OUTPUT
enter file name open.c
#include<stdio.h>
#include<fcntl.h>
main()
{
char buf[1000],fn1[10],fn2[10];
int fd1,fd2,n;

13
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

/* 4. using - write system calls


writing line of text the file */
#include<stdio.h>
#include<fcntl.h>
#include<string.h>
main()
{
char buf[100],fn[10];
int fd,n;
printf("Enter file name ");
scanf("%s",fn);
printf("\nEnter text ");
gets(buf);
fd=open(fn,O_CREAT|0666);
n=write(fd,buf,strlen(buf));//write file
close(fd);
}
OUTPUT:
enter file name open.c
enter text
HI !
HInclude<stdio.h>
#include<fcntl.h>
main()
{
char buf[1000],fn1[10],fn2[10]; ……
}

/* 5. using - open ,read and write system calls


file copy operation*/
#include<stdio.h>
#include<fcntl.h>
main()
{
char buf[1000],fn1[10],fn2[10];
int fd1,fd2,n;
printf("Enter source file name ");
scanf("%s",fn1);
printf("Enter destination file name ");
scanf("%s",fn2);
fd1=open(fn1,O_RDONLY);
n=read(fd1,buf,1000);
fd2=open(fn2,O_CREAT|0666);
n=write(fd2,buf,n);//write file
close(fd1);
close(fd2);
}

14
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

OUTPUT
enter source file name write.c
enter destination file name read.c

#include<stdio.h>
#include<fcntl.h>
#include<string.h>
main()
{
char buf[100],fn[10];
int fd,n;
printf("enter file name");
scanf("%s",fn);
printf("\n enter text\n");
scanf("%s",buf);
fd=open(fn,O_CREAT|O_WRONLY,0666);
n=write(fd,buf,strlen(buf));
close(fd);
}

Result :
Thus C program was written using open(), read(), write() and close() system calls.

15
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

3. Simulation of Unix Commands


Aim :
To write a C program to simulate basic Unix commands like ls,grep, cp,rm

Description :

UNIX commands can be simulated in the high level language using Unix system calls
and APIs available in the language. In addition, programming language construct can also
be used to avail the UNIX commands.

Exercises :
1. Siumulation of ls command
Algorithm :
1. Include necessary header files for manipulating directory.
2. Declare and initialize required objects.
3. Read the directory name form the user
4. Open the directory using opendir() system call and report error if the directory is
not available
5. Read the entry available in the directory
6. Display the directory entry (ie., name of the file or sub directory.
7. Repeat the step 6 and 7 until all the entries were read.

/* 1. Siumulation of ls command */
#include<dirent.h>
#include<stdio.h>
main()
{
char dirname[10];
DIR *p;
struct dirent *d;
printf("Enter directory name ");
scanf("%s",dirname);
p=opendir(dirname);
if(p==NULL)
{
perror("Cannot find dir.");
exit(-1);
}
while(d=readdir(p))
printf("%s\n",d->d_name);
}
OUTPUT:
enter directory name iii
.
..
f2
f1

16
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

2. Simulation of grep command.


Algorithm :
1. Include necessary header files
2. Make necessary declarations
3. Read the file name from the user and open the file in the read only mode.
4. Read the pattern from the user.
5. Read a line of string from the file and search the pattern in that line.
6. If pattern is available, print the line.
7. Repeat the step 4 to 6 till the end of the file.

/* 2. Simulation of grep command */


#include<stdio.h>
#include<string.h>
main()
{
char fn[10],pat[10],temp[200];
FILE *fp;
printf("\n Enter file name : ");
scanf("%s",fn);
printf("Enter the pattern to be searched : ");
scanf("%s",pat);
fp=fopen(fn,"r");
while(!feof(fp))
{
fgets(temp,1000,fp);
if(strstr(temp,pat))
printf("%s",temp);
}
fclose(fp);
}
OUTPUT:
enter file name: file4
enter the pattern to be searched: roll
roll no percentage grade

3. Simulation of cp command
Algorithm:
1. Include required header file
2. Make necessary declarations
3. Read the source and destination file names from the user.
4. Using read() system call, read the content of the file to the buffer.
5. Uing write() system call, write the buffer content to the destination file.
6. Close the opened files.

17
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

/* using - open ,read and write system calls


file copy operation*/
#include<stdio.h>
#include<fcntl.h>
main()
{
char buf[1000],fn1[10],fn2[10];
int fd1,fd2,n;
printf("Enter source file name ");
scanf("%s",fn1);
printf("Enter destination file name ");
scanf("%s",fn2);
fd1=open(fn1,O_RDONLY);
n=read(fd1,buf,1000);
fd2=open(fn2,O_CREAT|0666);
n=write(fd2,buf,n);//write file
close(fd1);
close(fd1);
}

OUTPUT:
enter source file name
ls.c
enter destination file name
file8
[it2-20@localhost ~]$ cat file8
#include<dirent.h>
#include<stdio.h>
main()
{
char dirname[10];
DIR *p;
struct dirent *d;
printf("enter directory name");
scanf("%s",dirname);
p=opendir(dirname);
if(p==NULL)
{
perror("cannot find directory");
exit(-1);
}
while(d=readdir(p))
printf("%s\n",d->d_name);
}

18
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

/* 4. to remove file or dir. */


Algorithm:
1. Include required header file
2. Make necessary declarations
3. Read the file name from the user.
4. Using remove () system call remove the file from the user.

#include<stdio.h>
#include<fcntl.h>
main()
{
char fn[10];
printf("Enter source file name ");
scanf("%s",fn);
if(remove(fn)==0)
printf("\nFile/Dir removed");
else
printf("\nCannot be removed");
}
OUTPUT:
enter source file name
file10

file/directory removed

Result :
Thus C program was written to simulate some Unix Commands

19
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

4. Process Scheduling – FCFS, SJF

Aim :
To write C program to simulate FCFS and SJF scheduling algorithms.

CPU/Process Scheduling

The assignment of physical processors to processes allows processors to accomplish work. 
The problem of determining when processors should be assigned and to which processes is 
called processor scheduling or CPU scheduling.
When more than one process is runable, the operating system must decide which one first. 
The part of the operating system concerned with this decision is called the scheduler, and 
algorithm it uses is called the scheduling algorithm.

First­Come­First­Served (FCFS) Scheduling

Other names of this algorithm are: 
● First­In­First­Out (FIFO) 
● Run­to­Completion 
● Run­Until­Done 
Perhaps,  First­Come­First­Served algorithm is the simplest scheduling algorithm is the 
simplest scheduling algorithm. Processes are dispatched according to their arrival time on the 
ready queue. Being a nonpreemptive discipline, once a process has a CPU, it runs to 
completion. The FCFS scheduling is fair in the formal sense or human sense of fairness but it 
is unfair in the sense that long jobs make short jobs wait and unimportant jobs make 
important jobs wait. 
FCFS is more predictable than most of other schemes since it offers time. FCFS scheme is 
not useful in scheduling interactive users because it cannot guarantee good response time. 
The code for FCFS scheduling  is simple to write and understand. One of the major drawback 
of this scheme is that the average time is often quite long. 

Shortest­Job­First (SJF) Scheduling

Other name of this algorithm is Shortest­Process­Next (SPN).
Shortest­Job­First (SJF) is a non­preemptive discipline in which waiting job (or process) with 
the smallest estimated run­time­to­completion is run next. In other words, when CPU is 
available, it is assigned to the process that has smallest next CPU burst.
The SJF scheduling is especially appropriate for batch jobs for which the run times are 
known in advance. Since the SJF scheduling algorithm gives the minimum average time for a 
given set of processes, it is probably optimal.
The SJF algorithm favors short jobs (or processors) at the expense of longer ones.
The obvious problem with SJF scheme is that it requires precise knowledge of how long a job 
or process will run, and this information is not usually available.
The best SJF algorithm can do is to rely on user estimates of run times.

20
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

In the production environment where the same jobs run regularly, it may be possible to 
provide reasonable estimate of run time, based on the past performance of the process. But in 
the development environment users rarely know how their program will execute.
Like FCFS, SJF is non preemptive therefore, it is not useful in timesharing environment in 
which reasonable response time must be guaranteed.

FCFS SCHEDULING

#include<stdio.h>
struct process
{
char pName[10];
int ex_time,wt_time,st_time,end_time;
}p[10];
main()
{
int n,i,j,k;
float avgwaittime=0.0,avgTurnAroundTime=0.0;
float totalWaitTime=0.0;
int totalExecTime=0,totalTurnAroundTime=0;
printf("\n enter number of process");
scanf("%d",&n);
p[0].st_time=0;
p[0].wt_time=0;
printf("\n enter process name");
scanf("%s",p[i].pName);
printf("enter Burst time");
scanf("%d",&p[i].ex_time);
if(i==0) p[i].end_time=p[i].ex_time;
else
{
p[i].wt_time=p[i-1].end_time;
p[i].st_time=p[i-1].end_time;
p[i].end_time=p[i].st_time+p[i].ex_time;
}
}
for(j=0;j<n;j++)
{
totalExecTime+=p[j].ex_time;
totalWaitTime+=p[j].wt_time;
}
totalTurnAroundTime=totalExecTime+totalWaitTime;
avgwaittime=(float)totalWaitTime/n;

avgTurnAroundTime=(float)totalTurnAroundTime/n;
printf("\n\n Name Burst Start End Wait Time\n");
for(k=0;k<n;k++)
printf("\n%s \t%d \t%d \t%d \t%d",p[k].pName,p[k].ex_time,p[k].st_time,p[k
].end_time,p[k].wt_time);

21
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

printf("\nAverage Waiting Time %f",avgwaittime);


printf("\n Average Turn Around Time %f",avgTurnAroundTime);
}

SAMPLE INPUT/ OUTPUT:

enter number of process 5

enter process name p1


enter Burst time3

enter process name p2


enter Burst time2

enter process name p3


enter Burst time1

enter process name p4


enter Burst time4

enter process namep5


enter Burst time2

Name Burst Start End Wait Time

p1 3 0 3 0
p2 2 3 5 3
p3 1 5 6 5
p4 4 6 10 6
p5 2 10 12 10
Average Waiting Time 4.800000
Average Turn Around Time 7.200000

Shortest Job First Scheduling

#include<stdio.h>
struct process
{
char pname[10];
int ex_time,wt_time,st_time,end_time;
}p[10],temp;
main()
{
int n,i,j,k;
float avgwaittime=0.0,avgturnaroundtime=0.0;

22
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

float totalwaittime=0.0;
int totalexectime=0,totalturnaroundtime=0;
printf("\n enter the number of process");
scanf("%d",&n);
p[0].st_time=0;
p[0].wt_time=0;
for(i=0;i<n;i++)
{
printf("\n enter process name");
scanf("%s",p[i].pname);
printf("enter burst time");
scanf("%d",&p[i].ex_time);
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
temp=p[i];p[i]=p[j];p[j]=temp;
}
}
p[0].wt_time=0;
p[0].st_time=0;
p[0].end_time=p[0].ex_time;
for(j=0;j<n;j++)
{
if(j>0)

{
p[j].wt_time=p[j-1].end_time;
p[j].st_time=p[j-1].end_time;
p[j].end_time=p[j].st_time+p[j].ex_time;
}
totalexectime+=p[j].ex_time;
totalwaittime+=p[j].wt_time;
}
avgwaittime=(float)totalwaittime/n;
totalturnaroundtime=totalexectime+totalwaittime;
avgturnaroundtime=(float)totalturnaroundtime/n;
printf("\n\nname brust start endwaittime\n");
for(k=0;k<n;k++)
printf("\n%s\t%d\t%d\t%d\t%d",p[k].pname,p[k].ex_time,p[k].st_time,p[k].end_time
,p[k].wt_time);
printf("\naverage waiting time %f",avgwaittime);
printf("\n average turnaroundtime %f",avgturnaroundtime);
}

23
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

SAMPLE INPUT / OUTPUT:


enter the number of process4

enter process namep1


enter burst time3

enter process namep2


enter burst time6

enter process namep3


enter burst time4

enter process namep4


enter burst time2

name burst start end waittime

p4 2 0 2 0
p1 3 2 5 2
p3 4 5 9 5
p2 6 9 15 9

average waiting time 4.000000


average turnaroundtime 7.750000

Result :
Thus C program was written for simulating FCFS and SJF scheduling algorithms.

24
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

5. CPU SCHEDULING PRIPORITY, ROUND ROBIN

Aim :
To write a C program for simulating Priority and Round Robin scheduling algorithms.

Priority Scheduling

The basic idea is straightforward: each process is assigned a priority, and priority is allowed 
to run. Equal­Priority processes are scheduled in FCFS order. The shortest­Job­First (SJF) 
algorithm is a special case of general priority scheduling algorithm.
An SJF algorithm is simply a priority algorithm where the priority is the inverse of the 
(predicted) next CPU burst. That is, the longer the CPU burst, the lower the priority and vice 
versa.
Priority can be defined either internally or externally. Internally defined priorities use some 
measurable quantities or qualities to compute priority of a process.
Examples of Internal priorities are
● Time limits. 
● Memory requirements. 
● File requirements, 
    for example, number of open files. 
● CPU Vs I/O requirements. 
Externally defined priorities are set by criteria that are external to operating system such as
● The importance of process. 
● Type or amount of funds being paid for computer use. 
● The department sponsoring the work. 
● Politics. 
Priority scheduling can be either preemptive or non preemptive
● A preemptive priority algorithm will preemptive the CPU if the priority of the newly 
arrival process is higher than the priority of the currently running process. 
● A non­preemptive priority algorithm will simply put the new process at the head of 
the ready queue. 
A major problem with priority scheduling is indefinite blocking or starvation. A solution to 
the problem of indefinite blockage of the low­priority process is aging. Aging is a technique 
of gradually increasing the priority of processes that wait in the system for a long period of 
time.

Round Robin Scheduling

One of the oldest, simplest, fairest and most widely used algorithm is round robin (RR).
In the round robin scheduling, processes are dispatched in a FIFO manner but are given a 
limited amount of CPU time called a time­slice or a quantum.

25
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

If a process does not complete before its CPU­time expires, the CPU is preempted and given 
to the next process waiting in a queue. The preempted process is then placed at the back of 
the ready list.
Round Robin Scheduling is preemptive (at the end of time­slice) therefore it is effective in 
time­sharing environments in which the system needs to guarantee reasonable response times 
for interactive users.
The only interesting issue with round robin scheme is the length of the quantum. Setting the 
quantum too short causes too many context switches and lower the CPU efficiency. On the 
other hand, setting the quantum too long may cause poor response time and appoximates 
FCFS.
In any event, the average waiting time under round robin scheduling is often quite long.

Priority Scheduling
#include<stdio.h>
struct process
{
char pname[10];
int ex_time,wt_time,st_time,end_time,turn_time,priority;
}p[10],temp;
main()
{
int n,i,j,k;
float avgwaittime=0.0,avgturnaroundtime=0.0;
float totalwaittime=0.0;
int totalexectime=0,totalturnaroundtime=0;
printf("\nenter number of process");
scanf("%d",&n);
p[0].st_time=0;
p[0].wt_time=0;
for(i=0;i<n;i++)
{
printf("\nenter process name");
scanf("%s",p[i].pname);
printf("\nenter process priority 0 with highest priority");
scanf("%d",&p[i].priority);
printf("enter burst time");
scanf("%d",&p[i].ex_time);
}
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(p[i].priority<p[j].priority)
{
temp=p[i];
p[i]=p[j];
p[j]=temp;
}
}

26
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

if(j==0)
{
p[j].wt_time=0;
p[j].st_time=0;
p[j].end_time=p[j].ex_time;
p[j].turn_time=p[j].ex_time+p[j].wt_time;
}
if(j>0)
{
p[j].wt_time=p[j-1].end_time;
p[j].st_time=p[j-1].end_time;
p[j].end_time=p[j].st_time+p[j].ex_time;
p[j].turn_time=p[j].ex_time+p[j].wt_time;
}
totalexectime+=p[j].ex_time;
totalwaittime+=p[j].wt_time;
totalturnaroundtime+=p[j].turn_time;
}
avgwaittime=(float)totalwaittime/n;
avgturnaroundtime=(float)totalturnaroundtime/n;
printf("\n\nname burst start end waittime\n");
for(k=0;k<n;k++)
printf("\n%s\t%d\t%d\t%d\t%d\t%d",p[k].pname,p[k].ex_time,p[k].st_time,p[k].end_
time,p[k].wt_time); 37,1 87%
printf("\naveragewaitingtime%f",avgwaittime);
printf("\naverageturnaroundtime%f",avgturnaroundtime);
}

OUTPUt:

Enter the number of processes 4

Enter process name p1


Enter process priority 0 with highest priority 2
Enter burst time 3

Enter process name p2

Enter process priority 0 with highest priority 4


Enter burst time 6

Enter process name p3


Enter process priority 0 with highest priority 1
Enter burst time4

Enter process name p4


Enter process priority 0 with highest priority3

27
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

Enter burst time2

name burst start end waittime

p3 4 0 4 0
p1 3 4 7 4
p4 2 7 9 7
p2 6 9 15 9

average waiting time 5.000000


average turnaroundtime 8.750000

// ROUND ROBIN SCHEDULING


#include<stdio.h>
struct process
{
char PName[10];
int ex_time,wt_time,st_time,end_time,turn_time;
int rem_time,completed_time;
}p[10],temp;
int quant_time;
main()
{
int n,i,j,k;
float avgWaitTime=0.0,avgTurnAroundTime=0.0;
float totalWaitTime=0.0;
int totalExecTime=0,totalTurnAroundTime=0;
int fs,fe;
printf("\nEnter number of process");
scanf("%d",&n);

for(i=0;i<n;i++)
{
printf("\nEnter process name");
scanf("%s",p[i].PName);
printf("Enter Burst time ");
scanf("%d",&p[i].ex_time);
p[i].rem_time=p[i].ex_time;
p[i].completed_time=0;
}
printf("\nEnter quantum time ");
scanf("%d",&quant_time);
printf("\n name start end busrt rem compl");
/* for first process start and the wait time to be 0 */
j=0;
fs=p[j].st_time=0;
p[j].wt_time=0;
if(p[j].ex_time>quant_time)
{ p[j].end_time=quant_time;

28
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

p[j].completed_time=quant_time;
}
else
{p[j].end_time=p[j].ex_time;
p[j].completed_time=p[j].ex_time;

p[j].wt_time=p[j].end_time-p[j].rem_time;
p[j].turn_time=p[j].wt_time+p[j].ex_time;
}
p[j].rem_time=p[j].ex_time-p[j].completed_time;
printf("\n%s\t%d\t%d\t%d\t%d\t
%d",p[j].PName,p[j].st_time,p[j].end_time,p[j].ex_time,p[j].rem_time,p[j].completed_time);

fe=p[j].end_time;
j++;
while(j<n)
{
p[j].st_time=fe;
if(p[j].rem_time>quant_time)
{
p[j].end_time=p[j].st_time+quant_time;
p[j].rem_time-=quant_time;
p[j].completed_time+=quant_time;
fe+=quant_time;
printf("\n%s\t%d\t%d\t%d\t%d\t
%d",p[j].PName,p[j].st_time,p[j].end_time,p[j].ex_time,p[j].rem_time,p[j].completed_time);
}
else if(p[j].rem_time>0)
{
p[j].end_time=p[j].st_time+p[j].rem_time;
p[j].wt_time=fe-p[j].completed_time;
p[j].completed_time+=p[j].rem_time;
p[j].turn_time=p[j].wt_time+p[j].ex_time;
fe+=p[j].rem_time;
p[j].rem_time=0;

printf("\n%s\t%d\t%d\t%d\t%d\t
%d",p[j].PName,p[j].st_time,p[j].end_time,p[j].ex_time,p[j].rem_time,p[j].completed_time);
}
j++;
if(j==n)
{
for(k=0;k<n;k++)
{
if(p[k].rem_time>0) /*break for the inner for loop */
{ j=k;
break; }
}
if(k>n) /* breaks from the outer while loop */
break;

29
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

}
}
printf("\n Process Name Waiting Time Turn Around Time");
for(i=0;i<n;i++)
{ printf("\n%s\t\t%d\t\t%d",p[i].PName,p[i].wt_time,p[i].turn_time);
totalWaitTime+=p[i].wt_time;
totalTurnAroundTime+=p[i].turn_time;
}
avgWaitTime=(float)totalWaitTime/n;
avgTurnAroundTime=(float)totalTurnAroundTime/n;
printf("\nAverage waiting time %f",avgWaitTime);
printf("\nAverage turn around time %f",avgTurnAroundTime);
}
OUTPUT:
enter number of process4

enter process name p1


enter burst time 3

enter process namep2


enter burst time6

enter process namep3


enter burst time4

enter process namep4


enter burst time2

enter quantum time2

name start end burst rem comp


p1 0 2 3 1 2
p2 2 4 6 4 2
p3 4 6 4 2 2
p4 6 8 2 0 2
p1 8 9 3 0 3
p2 9 11 6 2 4
p3 11 13 4 0 4
p2 13 15 6 0 6
processname waitingtime turnaroundtime
p1 6 9
p2 9 15
p3 9 13
p4 6 8
average waiting time7.500000
average turn around time 11.250000

Result :
Thus C program was written for simulating FCFS and SJF scheduling algorithms.

30
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

6. Inter Process communication (using shared memory, pipes or


message queues

Aim
To write a C program to implement inter-process communication using pipes, shared memory
and message queues.

Description

The Linux IPC (Inter-process communication) facilities provide a method for multiple
processes to communicate with one another.

The types of inter process communication are:

1. Signals - Sent by other processes or the kernel to a specific process to indicate various
conditions.
2. Pipes - Unnamed pipes set up by the shell normally with the "|" character to route
output from one program to the input of another.
3. FIFOS - Named pipes operating on the basis of first data in, first data out.
4. Message queues - Message queues are a mechanism set up to allow one or more
processes to write messages that can be read by one or more other processes.
5. Semaphores - Counters that are used to control access to shared resources. These
counters are used as a locking mechanism to prevent more than one process from
using the resource at a time.
6. Shared memory - The mapping of a memory area to be shared by multiple processes.

Message queues, semaphores, and shared memory can be accessed by the processes if they
have access permission to the resource as set up by the object's creator. The process must
pass an identifier to the kernel to be able to get the access.

PIPES

The Linux IPC (Inter-process communication) facilities provide a method for multiple
processes to communicate with one another. There are several methods of IPC available to
Linux.
Simply put, a pipe is a method of connecting the standard output of one process to the
standard input of another. Pipes are the eldest of the IPC tools, having been around since the
earliest incarnations of the UNIX operating system. They provide a method of one-way
communications (hence the term half-duplex) between processes.

To create a simple pipe with C, we make use of the pipe() system call. It takes a single
argument, which is an array of two integers, and if successful, the array will contain two new
file descriptors to be used for the pipeline. After creating a pipe, the process typically spawns
a new process (remember the child inherits open file descriptors).
PROTOTYPE: int pipe( int fd[2] );

31
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

RETURNS: 0 on success
-1 on error

NOTES: fd[0] is set up for reading, fd[1] is set up for writing

Shared Memory

Shared memory allows one or more processes to communicate via memory that appears in all
of their virtual address spaces. The pages of the virtual memory is referenced by page table
entries in each of the sharing processes' page tables. It does not have to be at the same address
in all of the processes' virtual memory.
SYNOPSIS
#include <sys/ipc.h>
#include <sys/shm.h>

shmget - allocates a shared memory segment


int shmget(key_t key, size_t size, int shmflg);
shmget() returns the identifier of the shared memory segment associ-
ated with the value of the argument key.

void *shmat(int shmid, const void *shmaddr, int shmflg);

The function shmat attaches the shared memory segment identified by shmid to the
address space of the calling process. The attaching address is specified by shmaddr with
one of the following criteria:
int shmdt(const void *shmaddr);

The function shmdt detaches the shared memory segment located at the address
specified by shmaddr from the address space of the calling process.

Message Queues

Message queues can be best described as an internal linked list within the kernel's addressing
space. Messages can be sent to the queue in order and retrieved from the queue in several
different ways. Each message queue (of course) is uniquely identified by an IPC identifier.
Message queues allow one or more processes to write messages, which will be read by one or
more reading processes. Linux maintains a list of message queues, the msgque vector; each
element of which points to a msqid_ds data structure that fully describes the message queue.
When message queues are created a new msqid_ds data structure is allocated from system
memory and inserted into the vector.
NAME
msgget - get a message queue identifier
SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

32
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

int msgget(key_t key, int msgflg);

DESCRIPTION
The function returns the message queue identifier associated with the value of the key
argument.

MSGSND & MSGRCV


To send or receive a message, the calling process allocates a structure of the following
general form:
struct msgbuf {
long mtype; /* message type, must be > 0 */
char mtext[1]; /* message data */
};
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgsnd(int msqid, struct msgbuf *msgp, size_t msgsz, int msgflg);
The msgsnd system call appends a copy of the message pointed to by msgp to the
message queue whose identifier is specified by msqid.

ssize_t msgrcv(int msqid, struct msgbuf *msgp, size_t msgsz, long msg-
typ, int msgflg);

The system call msgrcv reads a message from the message queue specified by msqid
into the msgbuf pointed to by the msgp argument, removing the read message from the
queue.

Exercise Programs :

/* 1. IPC USING PIPES */

#include<stdio.h>
main()
{
int fd[2],child;
char a[10];
printf("\nEnter the string to enter into the pipe ");
scanf("%s",a);
pipe(fd);

33
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

child=fork();
if(!child)
{
close(fd[0]);
write(fd[1],a,5);
wait(0);
}
else
{
close(fd[1]);
read(fd[0],a,5);
printf("\nThe string received from the pipe is %s\n",a);
}
return 0;
}
OUTPUT:
enter the string to enter into the pipe hello
the string received from the pipe is hello

/* 2. IPC USING SHARED MEMEORY */


#include<stdio.h>
#include<sys/shm.h>
#include<sys/ipc.h>

main()
{
int child, shmid,i;
char *shmptr;
child=fork();

if(!child)
{
shmid=shmget(2041,32,0666|IPC_CREAT);
shmptr=shmat(shmid,0,0);

printf("\nParent writing.........\n");
for(i=0;i<10;i++)
{
shmptr[i]='a'+i;
putchar(shmptr[i]);
}
printf("\n%s",shmptr);
wait(NULL);
}
else
{
shmid=shmget(2041,32,0666|IPC_CREAT);
shmptr=shmat(shmid,0,0);

34
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

printf("\nReading from child.........\n");


for(i=0;i<10;i++)
putchar(shmptr[i]);
shmdt(NULL);
shmctl(shmid,IPC_RMID,NULL);
}
return 0;
}
OUTPUT:
parent writing...
reading from child...
abcdefghijabcdefghij
abcdefghij

/* 3. a. IPC USING MESSAGE QUEUES


- SEND MESSAGE */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#include <string.h>

#define MSGSZ 128

/* Declare the message structure. */

typedef struct msgbuf {


long mtype;
char mtext[MSGSZ];
} message_buf;

main()
{
int msqid;
int msgflg = IPC_CREAT | 0666;
key_t key;
message_buf sbuf;
size_t buf_length;

/* Get the message queue id for the "name" 1234, which was created by
* the server. */
key = 1234;
msqid = msgget(key, msgflg );

/* We'll send message type 1 */

sbuf.mtype = 1;
(void) strcpy(sbuf.mtext, "Did you get this?");
buf_length = strlen(sbuf.mtext) ;

35
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

/* Send a message. */
msgsnd(msqid, &sbuf, buf_length, IPC_NOWAIT);
printf("Message: \"%s\" Sent\n", sbuf.mtext);
}
OUTPUT:
message:"did you get there?" sent

/*3 .b. IPC USING MESSAGE QUEUES


- RECEIVE MESSAGE */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>
#include <stdio.h>
#define MSGSZ 128

/* Declare the message structure. */

typedef struct msgbuf {


long mtype;
char mtext[MSGSZ];
} message_buf;

main()
{
int msqid;
key_t key;
message_buf rbuf;

/* Get the message queue id for the "name" 1234, which was created by the server. */
key = 1234;

msqid = msgget(key, 0666);


/* Receive an answer of message type 1 */
msgrcv(msqid, &rbuf, MSGSZ, 1, 0);

/*Print the answer. */


printf("%s\n", rbuf.mtext);
exit(0);
}
OUTPUT:
message:"did you get there?" received

Result :

36
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

Thus C program was program written to implement IPC using pipes, shared memory and
message queues.

7. Producer – Consumer problem using semaphores


Aim :
To write a C program to implement producer consumer problem using semaphore.

Semaphores
Semaphore is a location in memory whose value can be tested and set by more than one 
process. The test and set operation is, so far as each process is concerned, uninterruptible or 
atomic; once started nothing can stop it. The result of the test and set operation is the addition 
of the current value of the semaphore and the set value, which can be positive or negative. 
Depending on the result of the test and set operation one process may have to sleep until the 
semphore's   value   is   changed   by   another   process.   Semaphores   can   be   used   to   implement 
critical regions, areas of critical code that only one process at a time should be executing. 
Say you had many cooperating processes reading records from and writing records to a single 
data   file.   You   would   want   that   file   access   to   be   strictly   coordinated.   You   could   use   a 
semaphore with an initial value of 1 and, around the file operating code, put two semaphore 
operations, the first to test and decrement the semaphore's value and the second to test and 
increment it. The first process to access the file would try to decrement the semaphore's value 
and it would succeed, the semaphore's value now being 0. This process can now go ahead and 
use   the   data   file   but   if   another   process   wishing   to   use   it   now   tries   to   decrement   the 
semaphore's value it would fail as the result would be ­1. That process will be suspended until 
the first process has finished with the data file. When the first process has finished with the 
data file it will increment the semaphore's value, making it 1 again. Now the waiting process 
can be woken and this time its attempt to increment the semaphore will succeed. 
A semaphore is represented by an anonymous structure including the following members:

unsigned short semval; /* semaphore value */


unsigned short semzcnt; /* # waiting for zero */
unsigned short semncnt; /* # waiting for increase */
pid_t sempid; /* process that did last op */

The function semop performs operations on selected members of the semaphore set
indicated by semid. Each of the nsops elements in the array pointed to by sops specifies an
operation to be performed on a semaphore by a struct sembuf including the following
members:

unsigned short sem_num; /* semaphore number */


short sem_op; /* semaphore operation */
short sem_flg; /* operation flags */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semop(int semid, struct sembuf *sops, unsigned nsops);


SEMGET:

37
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

semget - get a semaphore set identifier

SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key_t key, int nsems, int semflg);

DESCRIPTION
This function returns the semaphore set identifier associated with the
argument key.

semctl - semaphore control operations

SYNOPSIS
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semctl(int semid, int semnum, int cmd, ...);

DESCRIPTION
The function semctl performs the control operation specified by cmd on the semaphore
set identified by semid, or on the semnum-th semaphore of that set. (Semaphores are
numbered starting at 0.)

/* program to demonstrate a basic producer-consumer implementation. */

#include <stdio.h> /* standard I/O routines. */


#include <stdlib.h> /* rand() and srand() functions */
#include <unistd.h> /* fork(), etc. */
#include <time.h> /* nanosleep(), etc. */
#include <sys/types.h> /* various type definitions. */
#include <sys/ipc.h> /* general SysV IPC structures */
#include <sys/sem.h> /* semaphore functions and structs. */

#define NUM_LOOPS 10 /* number of loops to perform. */

int main(int argc, char* argv[])


{
int sem_set_id; /* ID of the semaphore set. */
int child_pid; /* PID of our child process. */
int i; /* counter for loop operation. */
struct sembuf sem_op; /* structure for semaphore ops. */
int rc; /* return value of system calls. */
struct timespec delay; /* used for wasting time. */

/* create a private semaphore set with one semaphore in it, */

38
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

/* with access only to the owner. */


sem_set_id = semget(IPC_PRIVATE, 1, 0600);
printf("semaphore set created, semaphore set id '%d'.\n", sem_set_id);
rc = semctl(sem_set_id, 0, SETVAL, 0);
/* fork-off a child process, and start a producer/consumer job. */
child_pid = fork();
switch (child_pid) {
case 0: /* child process here */
for (i=0; i<NUM_LOOPS; i++) {
/* block on the semaphore, unless it's value is non-negative. */
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = 0;
semop(sem_set_id, &sem_op, 1);
printf("consumer: '%d'\n", i);
fflush(stdout);
}
break;
default: /* parent process here */
for (i=0; i<NUM_LOOPS; i++) {
printf("producer: '%d'\n", i);
fflush(stdout);
/* increase the value of the semaphore by 1. */
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = 0;
semop(sem_set_id, &sem_op, 1);

/* pause execution for a little bit, to allow the */


/* child process to run and handle some requests. */
/* this is done about 25% of the time. */
if (rand() > 3*(RAND_MAX/4)) {
delay.tv_sec = 0;
delay.tv_nsec = 10;
nanosleep(&delay, NULL);
}
}
break;
}

return 0;
}
OUTPUT:
Semaphore set created ,semaphore set id '2588751'
Producer:0
Consumer:0
Producer:1
Producer:2
Consumer:1
Consumer:2

39
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

Producer:3
Consumer:3
Producer:4
Consumer:4
Producer:5
Producer:6
Producer:7
Consumer:5
Consumer:6
Consumer:7
Producer:8
Producer:9
Consumer:8
Consumer:9

Result :
40
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

Thus C program was written to implement producer consumer problem using


semaphores.

8. Memory Management Scheme – I

( First Fit and Best Fit Memory Allocation Strategies )

Aim :

To implement memory allocation algorithms first fit and best fit.

Description :

In an environment that supports dynamic memory allocation, the memory manager must keep
a record of the usage of each allocatable block of memory. This record could be kept by using
almost any data structure that implements linked lists. An obvious implementation is to
define a free list of block descriptors, with each descriptor containing a pointer to the next
descriptor, a pointer to the block, and the length of the block. The memory manager keeps a
free list pointer and inserts entries into the list in some order conducive to its allocation
strategy. A number of strategies are used to allocate space to the processes that are competing
for memory.

Best Fit

The allocator places a process in the smallest block of unallocated memory in which it will
fit.

Problems:

 It requires an expensive search of the entire free list to find the best
hole.
 More importantly, it leads to the creation of lots of little holes that are
not big enough to satisfy any requests. This situation is called fragmentation, and is a
problem for all memory-management strategies, although it is particularly bad for
best-fit.

Solution: One way to avoid making little holes is to give the client a bigger block than it
asked for. For example, we might round all requests up to the next larger multiple of 64
bytes. That doesn't make the fragmentation go away, it just hides it.

 Unusable space in the form of holes is called external fragmentation


 Unusable space in the form of holes is called external fragmentation

Worst Fit

41
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

The memory manager places process in the largest block of unallocated memory available.
The idea is that this placement will create the largest hole after the allocations, thus
increasing the possibility that, compared to best fit, another process can use the hole created
as a result of external fragmentation.

First Fit

Another strategy is first fit, which simply scans the free list until a large enough hole is
found. Despite the name, first-fit is generally better than best-fit because it leads to less
fragmentation.

Problems:

 Small holes tend to accumulate near the beginning of the free list,
making the memory allocator search farther and farther each time.

Solution: Next Fit

Next Fit

The first fit approach tends to fragment the blocks near the beginning of the list without
considering blocks further down the list. Next fit is a variant of the first-fit strategy. The
problem of small holes accumulating is solved with next fit algorithm, which starts each
search where the last one left off, wrapping around to the beginning when the end of the list
is reached (a form of one-way elevator)

Result:
Thus C program was written to implement first fit and best fit allocation strategies.

9. Memory Management Scheme – II

( Paging and Page replacement algorithm – FIFO)


Aim :
To write a C program for implementing paging scheme and FIFO page replacement
algorithm

Paging

• Basic idea: allocate physical memory to processes in fixed size chunks called page
frames. Present abstraction to application of a single linear address space. Inside machine,
break address space of application up into fixed size chunks called pages. Pages and page
frames are same size. Store pages in page frames. When process generates an address,
dynamically translate to the physical page frame which holds data for that page.

42
Lab Manual Meenakshi College of Engineering, Chennai
CS 2257 - Operating Systems Laboratory

• So, a virtual address now consists of two pieces: a page number and an offset within
that page. Page sizes are typically powers of 2; this simplifies extraction of page numbers
and offsets. To access a piece of data at a given address, system automatically does the
following:
o Extracts page number.
o Extracts offset.
o Translate page number to physical page frame id.
o Accesses data at offset in physical page frame.

First-In, First-Out (FIFO)


First-in, first-out is as easy to implement as Random Replacement, and
although its performance is equally unreliable or worse, claims , its
behavior does follow a predictable pattern. Rather than choosing a victim
page at random, the oldest page (or first-in) is the first to be removed.
Conceptually compares FIFO to a limited size queue, with items being
added to the queue at the tail. When the queue fills (all of the physical
memory has been allocated), the first page to enter is pushed out of head of
the queue. Similar to Random Replacement, FIFO blatantly ignores trends,
and although it produces less page faults, still does not take advantage of
locality trends unless by coincidence as pages move along the queue .

43
Lab Manual Meenakshi College of Engineering, Chennai

You might also like