Professional Documents
Culture Documents
Lab Manual
Subject:
Operating system
Submitted By:
Adeeba Zahra 2020-BCS-001
Arbab Aslam 2020-BCS-006
Ayesha Khalid 2020-BCS-010
Sehrish Jabeen 2020-BCS-037
Submitted To:
Sir Majid Shafique
Contents
Lab#1: Introduction to Linux........................................................................................................................4
LAB TASK..........................................................................................................................................4
Lab#2: Introduction to Basic Shell commands...........................................................................................18
LAB TASKS......................................................................................................................................22
Lab#3: Implementing Linux Commands......................................................................................................25
LAB TASKS......................................................................................................................................29
Lab#4: Introduction to Shell Programming................................................................................................32
LAB TASKS......................................................................................................................................39
Lab#5: System Calls....................................................................................................................................42
LAB TASKS......................................................................................................................................46
Lab#6 & 7: System Calls.............................................................................................................................49
LAB TASKS......................................................................................................................................53
Lab#8: Interprocess Communication using Pipes......................................................................................64
LAB TASKS......................................................................................................................................66
Lab#9: Memory Management Schemes-First Fit Best Fit..........................................................................68
LAB TASKS......................................................................................................................................69
Lab#10: Threads.........................................................................................................................................72
LAB TASKS......................................................................................................................................76
Lab#11: Shortest Job First..........................................................................................................................78
LAB TASK........................................................................................................................................79
Lab#12: Round-Robin CPU Scheduling Algorithm..........................................Error! Bookmark not defined.
LAB TASK............................................................................................Error! Bookmark not defined.
List of Figure:
Figure 1........................................................................................................................................................5
Figure 2........................................................................................................................................................5
Figure 3........................................................................................................................................................6
Figure 4........................................................................................................................................................6
Figure 5........................................................................................................................................................7
Figure 6........................................................................................................................................................7
Figure 7........................................................................................................................................................8
Figure 8........................................................................................................................................................8
Figure 9........................................................................................................................................................9
Figure 10......................................................................................................................................................9
Figure 11....................................................................................................................................................10
Figure 12....................................................................................................................................................10
Figure 13....................................................................................................................................................11
Figure 14....................................................................................................................................................11
Figure 15....................................................................................................................................................11
Lab#1: Introduction to Linux
Linux:
Linux is a generic term refereeing to Unix-like computer operating system based on Linux
Kernel:
Linux is an operating system. (Labs of operating system will be conducted in Linux operating
system.)
The following are the characteristics of Linux:
Forget about viruses
Free and unlimited support
Security
Flexibility
Compatibility
Stability
Low cost
Network friendliness
Fast and easy installation
Multitasking
Open Source
Layers in Linux:
Three important parts of Linux are Kernel, Shell and File system.
Kernel:
Kernel is the heart of the operating system.
It is the low level core of the System that is the interface between applications and H/W.
Functions are Manage Memory, I/O devices, allocates the time between user and process;
inter process communication, sets process priority.
Shell:
The shell is a program that sits on the as an interface between users and kernel.
It is a command interpreter and also has programming capability of its own.
File System:
Linux treats everything as a file including hardware devices. Arranged as a directory
hierarchy.
The top level directory is known as “root (/)”.
LAB TASK
Task#1: Install Linux operating system in your systems.
Figure 1
Figure 2
Figure 3
Figure 4
Figure 5
Figure 6
Figure 7
Figure 8
Figure 9
Figure 10
Figure 11
Figure 12
Figure 13
Figure 14
Figure 15
Typing a Command
Changing Directories
Changing Back to the Root Directory
Creating a Directory
Deleting a Directory
Changing Drives
Copying Files
Renaming Files
Deleting Files
Command: pwd
"pwd" stands for print working directory. It displays your current position in the UNIX/LINUX file
system.
Example:
o pwd
It is simply used to report your current working directory.
Command: ls
"ls" stands for list. It is used to list information about files and directories.
Example:
o ls
It provides a very basic listing of the files in your current working directory. Filenames beginning
with a decimal are considered hidden files, and they are not shown.
o ls -al
This command provides a long listing of information about all files in the current directory.
This is probably the most used version of the ls command.
Command: mv
The "mv" command is used to move and rename files.
Examples:
o mv Lab OSLab
This command renames the file "Lab" to the new name "OSLab".
o mv OSLab garbage
This command renames the file "OSLAB1" to the new name "garbage". (Notice that if "garbage" is
a directory, "OSLAB" would be moved into that directory).
To move directory (folder) use the following command mv /source directory /destination directory.
Example
mv /home/mshahzad/Downloads/test /home/mshahzad/Documents/
Command: rm
The "rm" command is used to remove files and directories.
Examples:
o rm OSLab
This command deletes the file named "OSLab" (assuming you have permission to delete this file).
o rm OSLab1 OSLab2
This command deletes the files named "Chapter1", "Chapter2", and "Chapter3".
o rm -i OSLab1 OSLab2
This command prompt you before deleting any of the three files specified. The -i option stands for
inquire.
You must answer y (for yes) for each file you really want to delete. This can be a safer way to
delete files.
o rm in*
This command deletes all files in the current directory whose filename begins with the characters
"in".
o rm *.txt
This command deletes all files in the current directory whose filename ends with the characters ".txt".
o rm -r Labs
This command deletes the directory named "Labs”. This directory, and all of its' contents, are
erased from the disk, including any sub-directories and files.
Command: cp
The "cp" command is used to copy files and directories. When using the cp command, you must
always specify both the source and destination of the file(s) to be copied.
Examples:
o cp /home/Lab1 /home/OSLabs
This command copies the "Lab1" file in "/home" to the directory named "/home/OSLabs".
Command: mkdir
The "mkdir" command is used to create new directories (sub-directories).
Examples:
o mkdir Lab
This command creates a new directory named "Lab" in your current directory. (This example
assumes that you have the proper permissions to create a new sub-directory in your current
working directory.)
o mkdir memos letters
This command creates two new sub-directories (memos, letters) in the current directory.
o mkdir /home/labb
This command creates a new directory named "labb" in the directory "/home".
Command: rmdir
The "rm" command is used to remove files and directories. (Warning - be very careful when
removing files and directories!)
Examples:
o rm Lab
This command deletes the file named "Lab" (assuming you have permission to delete this file).
o rm Lab1 Lab2
This command deletes the files named "Lab1","Lab2".
o rm -i Lab1 Lab2
This command prompt you before deleting any of the three files specified. The -i option stands for
inquire. You must answer y (for yes) for each file you really want to delete. This can be a safer
way to delete files.
o rm *.txt
This command deletes all files in the current directory whose filename ends with the characters ".txt".
o rm in*
This command deletes all files in the current directory whose filename begins with the characters
"in".
o rm -r labb
This command deletes the directory named "labb". This directory, and all of its' contents, are
erased from the disk, including any sub-directories and files.
Command: clear
“Clear” is used to clear the full screen of text, perhaps garbage on the terminal.
Examples:
o clear
This command clears all text on the terminal.
LAB TASKS
Verify that you are in your home directory. Make the directory LABS using the following
command. List the files in the current directory to verify that the directory LABS has been
made correctly. Change directories to LABS. Create the file named file1. List the contents of
the file file1 to the screen. Make a copy of the file file1 under the name file2. Verify that the
files file1 and file2 both exist. List the contents of both file1 and file2 to the monitor screen.
Then delete the file file1. Clear the window. Rename file2 to thefile. Copy thefile to your
home directory. Remove thefile from the current directory. Copy thefile from your home
directory to the current directory. Change directories to your home directory. Remove thefile
from your home directory and from directory LABS. Verify thefile is removed from the
directory LABS. Remove the directory LABS from your home directory with the following
command. Verify that thefile and LABS are gone from your home directory.
Verify that you are in your home directory.
List the contents of both file1 and file2 to the monitor screen.
Verify that thefile and LABS are gone from your home directory.
Command: head
It displays the top part/lines of the file. By default it allows 10 lines, but you can change the
settings of the number of lines to be displayed by using –n.
Examples:
head –n25 file1.txt
This example displays the first 25 lines of the file named “file1.txt”.
Command: tail
It displays the last part/lines of the file. By default it allows 10 lines, but you can change the
settings of the number of lines to be displayed by using –n.
Examples:
tail –n25 file1.txt
This example displays the last 25 lines of the file named “file1.txt”.
Command: ls -l
This command is use to find permission level of the file.
The permission levels are
“r” Read only
“w” Write
“x” execute
I n case of directory, “x” grants permission to list directory contents.
Command: chmod
Each file in UNIX/LINUX has an associated permission level. This allows the user to prevent
others from reading/writing/executing their files or directories.
If you own a file, you can change its permissions with “chmod”.
Example
chmod 7 7 7 filename
user group others
Gives user, group and others r, w, x permissions
chmod 770 filename
Gives the user read, write and execute.
Gives group members read and execute.
Gives others no permissions.
Using numeric representations for permissions:
r = 4; w = 2; x = 1; total = 7
Redirection of Input and Output
Mostly all command gives output on screen or take input from keyboard, but in Linux (and in other
OSs also) it's possible to send output to file or to read input from file.
Command: ls
“ls” command is used to output to screen.
Examples:
ls > file1
This command put output of ls to file1.
It outputs Linux-commands result (output of command or shell script) to file. Note that if file
already exist, it will be overwritten else new file is created.
ls >> file1
This command put output of ls at the end of file1.
It output Linux-commands result (output of command or shell script) to end of file. If file exists, it
will be opened and new information/data will be written to end of file, without losing previous
information/data, and if file does not exist, then new file is created.
ls < file1
This command put contents to command or shell script from the file.
It takes input to Linux-command from file instead of key-board.
Command: sort
“sort” is used to sort the contents in the file.
Examples:
sort file1
This command sorts the contents in the file1.
sort < file1 > sort_names
cat sort_names
In above example sort command takes input from “file1” file and output of sort command (i.e.
sort_name) is redirected to sort_name file.
tr "[a-z]" "[A-Z]" < file1 > cap_names
cat cap_names
tr command is used to translate all lower case characters to upper-case letters. It takes input from
“file1” file, and tr's output is redirected to cap_names file.
2. User defined variables (UDV) - Created and maintained by user. This type of variable
defined in lower letters.
To define UDV use following syntax
Syntax: variable name=value
'value' is assigned to given 'variable name' and Value must be on right side = sign.
Example:
no=10
It define variable called ‘no’ having value 10.
vech=Bus
It define variable called 'vech' having value Bus
There are rules for naming variable name (Both UDV and System Variable)
Variable name must begin with Alphanumeric character or underscore character (_),
followed by one or more Alphanumeric character.
Don't put spaces on either side of the equal sign when assigning value to variable. e.g.
In following variable declaration there will be no error.
Variables are case-sensitive, just like filename in Linux. For example: To print or access
value of UDV (User defined variables)
Example:
vech=Bus
echo $vech
It will print the value of vech.
Shell Arithmetic
Use to perform arithmetic operations.
Examples:
o expr 1 + 3
o expr 2 - 1
These examples print the result.
By default in Linux if particular command/shell script is executed, it return two type of values
which is used to see whether command or shell script executed is successful or not.
Shell scripts
A shell script or a shell program is a series of commands put in a file and executed by the Shell.
Remember both bc and Linux Shell uses different ways to show True/False values.
Try it as follows:
$ chmod 755 isnump_n
$ ./isnump_n 5
5 number is positive
$ ./isnump_n -45
-45 number is negative
$ ./isnump_n
./ispos_n : You must give/supply one integers
$ isnump_n 0
number is negative
Example:
You can write the entire if-else construct within either the body of the if statement of the body of
an else statement. This is called the nesting of ifs.
nestedif.sh a=0
echo "1. Unix (Sun Os)" echo "2. Linux (Red Hat)"
echo "Select your os choice [1 or 2]? " read a if [
$a -eq 1 ]
thenecho "You Pick up Unix (Sun Os)" else #### nested if i.e. if within if ######
if [ $a -eq 2 ] then
echo "You Pick up Linux (Red Hat)"else
echo "What you don't like Unix/Linux OS."fi fi
Nested … if :
You can use the nested ifs as follows also:
test command or [ expr ]
test command or [ expr ] is used to see if an expression is true, and if it is true it return zero(0),
otherwise returns nonzero for false.
Syntax:
test expression OR [ expression ]
Example:
Following script determine whether given argument number is positive.
Run it as follows:
$ chmod 755 ispostive
$./ ispostive 5
5 number is positive
$./ispostive -45
Nothing is printed
$./ispostive
./ispostive: test: -gt: unary operator expected
Multilevel if-then-else
Syntax: if condition
then
condition is zero (true - 0)
execute all commands up to elif
statement elif condition1 then
condition1 is zero (true - 0)
execute all commands up to elif
statement elif condition2 then
condition2 is zero (true - 0)
execute all commands up to elif statement else
None of the above condtion,condtion1,condtion2 are true (i.e.
all of the above nonzero or false)
execute all commands up to
fi fi
For multilevel if-then-else statement try the following script:
$ cat > elf
#
# Script to test if..elif...elsegive number "
#
if [ $1 -gt 0 ]; then echo "$1 is positive" elif [ $1 -lt 0 ] then
echo "$1 is negative" elif [ $1 -eq 0 ] then
LAB TASKS
Task # 1: Write shell script as follows:
cat > trmif
#
# Script to test rm command and exist status
#
if rm $1
then
echo "$1 file deleted"
fi
Press Ctrl + d to save
$ chmod 755 trmif
Answer the following question in reference to above script:
1. foo file exists on your disk and you give command, $ ./trmfi foo what will be output?
2. If bar file not present on your disk and you give command, $ ./trmfi bar what will
be output?
3. And if you type $ ./trmfi What will be output?
Output:
Task # 2: Write a shell script that computes the gross salary of an employee according to the
following:
1. if basic salary is <1500 then HRA=10% of the basic salary.
2. if basic salary is >1500 then HRA=20% of the basic salary.
Output:
Task # 3: Write a shell script to ADD two numbers taken from
argument? Note: show error if no argument or more than 2 arguments are
passed
$ ./ADD 5 6
Output : Sum of 5 and 6 = 5+6 = 11
Output:
Lab#5: System Calls
System Calls
The System Call is the request for running any Program and for performing any operation on the
system. For making any request a user will prepare a special call which is also known as the
system call. The system call is the fundamental interface between an application and the Linux
kernel. Some of the system calls are:
1. fork()
2. wait()
3. exec()
4. exit()
fork ()
The fork () system call will spawn a new child process which is an identical process to the parent
except that has a new system process ID. The process is copied in memory from the parent and a
new process structure is assigned by the kernel. The return value of the function is which
discriminates the two threads of execution. A zero is returned by the fork function in the child's
process, and on failure it returns -1.
Example:
#include<stdio.h>
(pid > 0) printf("\n I'm the parent process. My child pid is %d",
pid); else
perror("error in fork");
The pid_t data type is a signed integer type which is capable of representing a process ID. In the
GNU C Library, this is an int. it can be an int, short int, long int.
There is another function getpid ()that returns the process ID of the current process.
The C library function void perror (const char *str) prints a descriptive error message to stderr.
First the string str is printed followed by a colon then a space.
When the fork is executed, an identical process called the child is created. Then both the parent
and the child process begin execution at the next statement. When a fork is executed, everything
in the parent process is copied to the child process. This includes variable values, code, and file
descriptors. Following the fork, the child and parent processes are completely independent. There
is no guarantee which process will print first. The child process begins execution at the statement
immediately after the fork, not at the beginning of the program. A parent process can be
distinguished from the child process by examining the return value of the fork call. Fork returns a
zero to the child process and the process id of the child process to the parent process. A
process can execute as many forks as desired.
wait ()
The wait () system call suspends execution of the calling process until one of its children
terminates. This system call blocks calling process until the child process terminates. If child
process has already terminated, the wait () call returns immediately. if the calling process has
multiple child processes, the function returns when one returns. If the call is successful, the
process ID of the
terminating child is returned. If a parent dies before its child, the child (orphan process) is
automatically adopted by the original “init” process whose PID is 1.
wait (int *status);
where status is an integer value where the UNIX system stores the value returned by child process.
Zombie process—a process that has terminated but whose exit status has not yet been received by
its parent process or by init.
Example
#include <stdio.h>
void main()
printf(“fork failed\n”);
exit(1);
} if(pid
== 0)
{ printf(“Child!\n”);
else
exit ( )
terminates the process which calls this function and returns the exit status value, exit (1) for
abnormal termination (when error occurs), exit (0) for normal termination.
exit ()
The exit() system call ends a process and returns a value to its parent. The prototype for the exit()
system call is:
void exit(status)
int status;
where status is an integer between 0 and 255. This number is returned to the parent via wait() as
the exit status of the process. By convention, when process exits with a status of zero that means
it didn't encounter any problems; when a process exit with a non-zero status that means it did
have problems. exit() is actually not a system routine; it is a library routine that call the system
routine
_exit(). exit() cleans up the standard I/O streams before calling _exit(), so any output that has
been buffered but not yet actually written out is flushed. Calling _exit() instead of exit() will
bypass this cleanup procedure.
exit() does not return.
exec ()
Typically the exec system call is used after a fork system call by one of the two processes to
replace the process’ memory space with a new executable program. The new process image is
constructed from an ordinary, executable file. There can be no return from a successful exec
because the calling process image is overlaid by the new process image.
execl (const char *file, const char *arg0, ..., const char *argn,char *)0);
Takes the path name of an executable program (binary file) as its first argument. The rest of the
arguments are a list of command line arguments to the new program argv[] The list is terminated
with a null pointer.
Example 1
#include <unistd.h> #include
<stdio.h> void main()
{ printf(“ 1 \n”);
execl(“/bin/ls”,”ls”,NULL);
Example 2
Step 1
Create a file with name prog2.c, compile it and run it.
aa prog2.c
Step 2
#include <stdio.h>
#include <unistd.h> void
main()
LAB TASKS
Example#1:
Example#2:
Example#3:
Task 1: Write a program where a child is created to execute a command.
Output:
Task 2: Write a program that spawns two children, then wait for their
completion, and behaves differently according to which one is finished.
Output:
Lab#6 & 7: System Calls
System Calls
The System Call is the request for running any Program and for performing any operation on the
system. For making any request a user will prepare a special call which is also known as the
system call. The system call is the fundamental interface between an application and the Linux
kernel.
The file structure related system calls available in the UNIX system let you create, open, and
close files, read and write files, randomly access files, alias and remove files, get information
about files, check the accessibility of files, change protections, owner, and group of files, and
control devices. These operations either use a character string that defines the absolute or relative
path name of a file, or a small integer called a file descriptor that identifies the I/O channel.
int main()
int fd;
}
close(fd);
exit (0);
open ()
This system call can be used to open an existing file or to create a new file if it does not exist
already. The syntax of open has two forms:
int open(const char *path, int flags); int open(const char *path, int flags, mode_t
modes);The first form is normally used to open an existing file, and the second form to open a
file and to create a file if it does not exist already. Both forms returns an integer called the file
descriptor. The file descriptor will be used for reading from and writing to the file. If the file
cannot be opened or created, it returns -1. The first parameter path in both forms specifies the file
name to be opened or created. The second parameter (fl specifies how the file may be used. The
following list some commonly used flag values.
Flags Description
O_RDONLY open for reading only
O_WRONLY open for writing only
O_RDWR open for reading and writing
O_CREAT create file if it does not exist
O_APPEND append on each write
There is a limit on how many files a program can open, because it takes resources to store all
information needed to correctly handle an opened file. So, close all files you don't currently need
to save some resources. The number of files that can be opened varies from system to system and
user to user. Some system allows as many as 2000 files, and sometimes a user's resource is
limited.
Example:
open(“hello.c”,O_RDWR) // hello.c is opened and is ready for reading and writing.
If successful open returns non negative integer else return -1.
close ()
To close a channel, use the close() system call. The prototype for the close() system call is:
int close(file_descriptor)
int file_descriptor;
where file_descriptor identifies a currently open channel. close() fails if file_descriptor does not
identify a currently open channel.
Example of open() and close():
#include <stdio.h>
#include <stdlib.h>
int main()
{
int fd;
// char buffer[80];
}
else
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. When used with
the lseek() system call, they provide all the tools necessary to do input and output randomly.
Both read() and write() take three arguments. Their prototypes are:
int read(file_descriptor, buffer_pointer, transfer_size) int file_descriptor; char
*buffer_pointer; unsigned transfer_size;
int write(file_descriptor, buffer_pointer,
transfer_size) 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.
There is no limit on transfer_size, but you must make sure it's safe to copy transfer_size bytes to
or from the memory pointed to by buffer_pointer. A transfer_size of 1 is used to transfer a byte at
a time for so-called "unbuffered" input/output. The most efficient value for transfer_size is the
size of the largest physical record the I/O channel is likely to have to handle.
lseek ()
The UNIX system file system treats an ordinary file as a sequence of bytes. Generally, a file is
read or written sequentially, that is, from beginning to the end of the file. The UNIX system lets
you read and write anywhere in the file. Known as "random access", this capability is made
possible with the lseek() system call. During file I/O, the UNIX system uses a long integer, also
called a File Pointer, to keep track of the next byte to read or write. This long integer represents
the number of bytes from the beginning of the file to that next character. Random access I/O is
achieved by changing the value of this file pointer using the lseek() system call.
If successful, lseek() returns a long integer that defines the new file pointer value measured in
bytes from the beginning of the file. If unsuccessful, the file position does not change.
#include <stdio.h>
int main()
{
int fd;
char buffer[80];
}
else
LAB TASKS
Example#1
Output:
Example#2
Output:
Example#3
Output:
Example#4
Task#1: Create a file named “oslab.txt” present in directory named “os”
located in home directory.
Output:
Task#2.1: Open a file for reading named “oslab.txt” present in directory named
“os” located in home directory.
Output:
Task#2.2: Open a new file for reading and writing, whose location is provided
by the user.
Task#3.1: Read at most 100 bytes into buf from standard input.
Task#3.2: Read bytes into temporary buffer buf from file whose location and
name is entered by the user as an argument at the time of execution.
Task#4.1: Write “read” and “write” commands for the following conditions
Read data from standard input and write it on standard output. Read data
from the file, given as an argument by the user and write it on standard output.
Start reading from the end of file.
Output:
Task#4.2: Read data from standard input and write it on the file given as an
argument by the user.
Output:
Task#4.3: Read and write data from the files named “lab3.c” and “lab4.c”
respectively. The files are present in the directory “lab”, located in the home
directory.
Output:
Task 5: Write complete code to copy the contents of an input file to an output
file using system calls where the input and output files names are entered by the
user.
Output:
Pipes:
A pipe is a communication channel between two ends. It is mostly used to communicate between
processes running within a computer. It is a communication device that permits unidirectional
communication. Data written to the “write end” of the pipe is read back from the “read end”.
Pipes are serial devices; the data is always read from the pipe in the same order it was written.
A pipe’s data capacity is limited. If the writer process writes faster than the reader process
consumes the data, and if the pipe cannot store more data, the writer process blocks until more
capacity becomes available. If the reader tries to read but no data is available, it blocks until data
becomes available.
Thus, the pipe automatically synchronizes the two processes.
Creating Pipes:
To create a pipe, invoke the pipe command. Supply an integer array of size 2.The call to pipe
stores the reading file descriptor in array position 0 and the writing file descriptor in position 1.
For example, consider the code: int pipe_fds[2]; int read_fd; int write_fd; pipe (pipe_fds); read_fd
= pipe_fds[0]; write_fd = pipe_fds[1];
Data written to the file descriptor read_fd can be read back from write_fd.
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. If successful, the array will contain two new file descriptors to
be used for the pipeline.
System call: pipe ();
Prototype: int pipe (int fd[2]
); It returns 0 on success, -1
on error.
NOTE:
o fd[0] is set up for reading
o fd[1] is set up for writing
The first integer in the array (element 0) is set up and opened for reading, while the second integer
(element 1) is set up and opened for writing. Visually speaking, the output of fd1 becomes the
input for fd0.
Some of the system calls that are used in piping are:
Open Open or create a file
Read Read from a pipe
Write Write data to a pipe
Close Close/destroy a pipe
Pipe Create a pipe for IPC
Example:
//Parent creates pipe, forks a child, child writes into pipe, and parent reads from pipe
#include <stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <string.h> main()
{
perror("pipe");
}
pid = fork ();
if (pid < 0)
{
perror("fork");
if (pid == 0)
close(pipefd[1]); }
printf("End!\n"); }
return(0); }
LAB TASKS
Output:
Task#2: Using pipes, parent read data from one file, and child write data into
another file.
Output:
Lab#9: Memory Management Schemes-First Fit Best Fit
Memory Management Algorithms
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.
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.
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
Best Fit
The allocator places a process in the smallest block of unallocated memory in which it will fit. 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. 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
Algorithm:
1. Start the program.
2. Get the number of segments and size.
3. Get the memory requirement and select the option.
4. If the option is ‘2’ call first fit function.
5. If the option is ‘1’ call best fit function.
6. Otherwise exit.
7. For first fit, allocate the process to first possible segment which is free.
8. For best fit, do the following steps.
a. Sorts the segments according to their sizes.
b. Allocate the process to the segment which is equal to or slightly greater than the process size.
2. Stop the program.
LAB TASKS
Task#1
// C implementation of First - Fit algorithm
#include<stdio.h>
// Function to allocate memory to
// blocks as per First fit algorithm
void firstFit(int blockSize[], int m, int processSize[], int n)
{
int i, j;
// Stores block id of the
// block allocated to a process
int allocation[n];
// Initially no block is assigned to any process
for(i = 0; i < n; i++)
{
allocation[i] = -1;
}
// pick each process and find suitable blocks
// according to its size ad assign to it
for (i = 0; i < n; i++) //here, n -> number of processes
{
for (j = 0; j < m; j++) //here, m -> number of blocks
{
if (blockSize[j] >= processSize[i])
{
// allocating block j to the ith process
allocation[i] = j;
// Reduce available memory in this block.
blockSize[j] -= processSize[i];
break; //go to the next process in the queue
}
}
}
printf("\nProcess No.\tProcess Size\tBlock no.\n");
for (int i = 0; i < n; i++)
{
printf(" %i\t\t\t", i+1); printf("%i\
t\t\t\t", processSize[i]); if
(allocation[i] != -1)
printf("%i", allocation[i] + 1);
else
printf("Not Allocated");
printf("\n");
}
}
// Driver code
int main()
{
int m; //number of blocks in the memory
int n; //number of processes in the input queue
int blockSize[] = {100, 500, 200, 300, 600};
int processSize[] = {212, 417, 112, 426};
m = sizeof(blockSize) / sizeof(blockSize[0]);
n = sizeof(processSize) / sizeof(processSize[0]);
firstFit(blockSize, m, processSize, n);
return 0 ;
}
Output:
Task#2
int main()
{
int m; //number of blocks in the memory
int n; //number of processes in the input queue
int blockSize[] = {100, 500, 200, 300, 600};
int processSize[] = {212, 417, 112, 426, 312};
m = sizeof(blockSize) / sizeof(blockSize[0]);
n = sizeof(processSize) / sizeof(processSize[0]);
firstFit(blockSize, m, processSize, n);
return 0 ;
}
Output:
Task#2
// Driver code
int main()
{
int m; //number of blocks in the memory
int n; //number of processes in the input queue
int blockSize[] = {100, 500, 200, 300, 600, 400};
int processSize[] = {212, 417, 112, 426, 312, 326, 410};
m = sizeof(blockSize) / sizeof(blockSize[0]);
n = sizeof(processSize) / sizeof(processSize[0]);
firstFit(blockSize, m, processSize, n);
return 0 ;
}
Output:
Lab#10: Threads
A thread is a single sequence stream within in a process. Threads have some of the properties of
processes; they are sometimes called lightweight processes. In a process, threads allow multiple
executions of streams. In many respect, threads are popular way to improve application through
parallelism. The CPU switches rapidly back and forth among the threads giving illusion that the
threads are running in parallel. Like a traditional process i.e., process with one thread, a thread can
be in any of several states (Running, Blocked, Ready or Terminated). Each thread has its own
stack. Since thread will generally call different procedures and thus a different execution history.
This is why thread needs its own stack. An operating system that has thread facility, the basic unit
of CPU utilization is a thread. A thread has or consists of a program counter (PC), a register set,
and a stack space. Threads are not independent of one other like processes as a result threads shares
with other threads their code section, data section, OS resources also known as task, such as open
files and signals.
Multithreading is the ability of a program or an operating system process to manage its use by
more than one user at a time and to even manage multiple requests by the same user without
having to have multiple copies of the programming running in the computer. Each user request for
a program or system service (and here a user can also be another program) is kept track of as a
thread with a separate identity. As programs work on behalf of the initial request for that thread
and are interrupted by other requests, the status of work on behalf of that thread is kept track of
until the work is completed.
Thread Programming:
Some of the basic thread routines are as follows:
Creation:
int pthread_create(pthread_t * thread, const pthread_attr_t * attr, void * (*start_routine)(void *),
void *arg);
Analogous to a combined fork and exec routine
Returns a thread id in thread.
When attr is NULL the default thread attributes are used.
Pthread_t: It is defining a thread pointer. When a thread is created identifier is written into the
variable to which the pointer points. This identifier helps to refer to thread.
Pthread_attr_t: It is used to set the thread attributes. If attr is NULL, the default attributes are
used.
Name of function: The name of the function to be started by the thread for execution.
Arguments to be passed to the function: When a new thread is created it executes the
function pointed by the function variable name.
On success, pthread_create ( ) returns 0, and on error, it returns an error number.
Termination
void pthread_exit(void * return_value);
Analogous to exit
The exit routine kills all threads and exits the process
If the current thread is the last thread then the process terminates
Returning from the start_routine is equivalent to calling pthread_exit
Returning from the initial thread main is the equivalent to calling exit
Example:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
Output
Example 2:
#include<stdio.h>
#include<stdlib.h>
#include<pthread.h>
void *msg_function(void *ptr);
main()
{
pthread_t thread1, thread2;
char *msg1 = "I'm Thread1";
char *msg2 = "I'm Thread2";
int t1, t2;
t1 = pthread_create(&thread1, NULL, msg_function,
(void*)msg1); t2 = pthread_create(&thread2, NULL, msg_function,
(void*)msg2); pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("Thread 1 returns: %d\n", t1);
printf("Thread 2 returns: %d\n", t2);
exit(0);
}
void *msg_function (void *ptr)
{
char *msg;
int i;
msg = (char*) ptr;
for (i=0; i<5; i++)
{
printf("%s - %d\n", msg,i);
/* sleep() causes the current thread to suspend execution for a specified period. This is an efficient
means of making processor time available to the other threads of an application or other
applications that might be running on a computer system. */
sleep(1);
}
}
Output
LAB TASKS
Write a program that sorts the array in ascending order using bubble sort and
descending order using selection sort by means of multithreading.
#include <stdio.h>
#include<stdlib.h>
#include<pthread.h>
void *bubbleSort();
void *SelectionSort();
void *bubbleSort()
{
int arr[]={3,2,5,1,6};
int i, j,k,temp;
for (i = 0; i < 5-1; i++)
// Last i elements are already in place
for (j = 0; j < 5-i-1; j++)
if (arr[j] > arr[j+1])
{ temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
printf("Buble sort ");
for (k=0; k < 5; k++)
printf("%d ",arr[k]);
}
void *SelectionSort(){
int arr[]={3,2,5,1,6};
int i, j,k,temp;
for(i=0;i<5;i++)
{ for(j=i+1;j<5;j++){
if(arr[i]< arr[j]){
temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;}
}
}
printf("\nSelection sort");
for(i=0;i<5;i++)
printf(" %d",arr[i]);
}
int main()
{
pthread_t thread1, thread2;
pthread_create(&thread1, NULL,bubbleSort,NULL);
pthread_create(&thread2, NULL, SelectionSort,NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
return 0;
}
Output:
Associate with each process the length of its next CPU burst. Use these lengths to schedule the
process with the shortest time.
Two schemes:
Non preemptive: Once CPU given to the process it cannot be preempted until completes its
CPU burst
Preemptive: If a new process arrives with CPU burst length less than remaining time of current
executing process, preempt. This scheme is known as the Shortest-Remaining-Time-First (SRTF)
SJF is optimal gives minimum average waiting time for a given set of processes
Suppose that there are four processes P1, P2, P3, P4
Algorithm:
Take total no. of processes from user.
Take Name, Arrival Time and Burst Time for each process.
Select the process which have shortest burst will execute first.
If all processes arrive at 0 time interval than process with the smallest CPU
Burst will execute first.
If processes arrive at different time intervals than CPU will be given to the
process that will arrive first and let the other processes to be in queue.
If two processes have same burst length then FCFS scheduling algorithm will be
used.
Sort the processes in ascending order of their CPU Burst.
Compute Waiting Time & Turnaround Time for each process.
Compute Average Waiting Time & Turnaround Time of processes.
Display Average Waiting and Turnaround Time of processes.
Display the Gantt chart.
LAB TASK
Example 1:
#include<stdio.h>
int main()
{
int bt[20],p[20],wt[20],tat[20],i,j,n,total=0,pos,temp;float avg_wt,avg_tat;
printf("Enter number of process:");scanf("%d",&n);
printf("\nEnter Burst Time:\n");for(i=0;i<n;i++)
{
printf("p%d:",i+1);
scanf("%d",&bt[i]);p[i]=i+1;
}
//sorting of burst times
for(i=0;i<n;i++)
{
pos=i; for(j=i+1;j<n;j++)
{
if(bt[j]<bt[pos])pos=j;
}
temp=bt[i];
bt[i]=bt[pos];
bt[pos]=temp;
temp=p[i];
p[i]=p[pos];
p[pos]=temp;
}
wt[0]=0;
for(i=1;i<n;i++)
{
wt[i]=0;
for(j=0;j<i;j++)
wt[i]+=bt[j];
total+=wt[i];
}
avg_wt=(float)total/n;total=0;
printf("\nProcess\t Burst Time \tWaiting Time\tTurnaround
Time");
for(i=0;i<n;i++)
{
tat[i]=bt[i]+wt[i]; total+=tat[i];
printf("\np%d\t\t %d\t\t
%d\t\t\t%d",p[i],bt[i],wt[i],tat[i]);
}
avg_tat=(float)total/n;
printf("\n\nAverage Waiting Time=%f",avg_wt); printf("\nAverage
Turnaround Time=%f\n",avg_tat);
Output:
Lab Task
Implement Shortest Job First (Non-Preemptive) CPU Scheduling Algorithm.
#include<stdio.h>
int main()
{
int bt[20],p[20],wt[20],tat[20],i,j,n,total=0,pos,temp;
float avg_wt,avg_tat;
printf("Enter number of process:");
scanf("%d",&n);
printf("\nEnter Burst Time:\n");
for(i=0;i<n;i++)
{
printf("p%d:",i+1);
scanf("%d",&bt[i]);
p[i]=i+1;
}
//sorting of burst times
for(i=0;i<n;i++)
{
pos=i;
for(j=i+1;j<n;j++)
{
if(bt[j]<bt[pos])
pos=j;
}
temp=bt[i];
bt[i]=bt[pos];
bt[pos]=temp;
temp=p[i];
p[i]=p[pos];
p[pos]=temp;
}
wt[0]=0;
for(i=1;i<n;i++)
{
wt[i]=0; for(j=0;j<i;j+
+)
wt[i]+=bt[j];
total+=wt[i];
}
avg_wt=(float)total/n;
total=0;
printf("\nProcess\t Burst Time \tWaiting Time\tTurnaround Time");
for(i=0;i<n;i++)
Output:
LAB TASK
Example 1:
#include<stdio.h>
int main()
{
int i, limit, total = 0, x, counter = 0, time_quantum;
int wait_time = 0, turnaround_time = 0, arrival_time[10], burst_time[10], temp[10];
float average_wait_time, average_turnaround_time;
printf(" Enter Total Number of Processes: ");
scanf("%d", &limit);
x = limit;
for(i = 0; i < limit; i++)
{
printf(" \n Enter Details of Process[%d]n ", i + 1);
printf(" Arrival Time: " );
scanf("\n %d", &arrival_time[i]);
printf(" Burst Time: ");
scanf("\n %d", &burst_time[i]);
temp[i] = burst_time[i];
}
printf(" Enter Time Quantum: ");
scanf("\n %d", &time_quantum);
printf(" Process ID Burst Time Turnaround Timet Waiting Time ");
for(total = 0, i = 0; x != 0;)
{
if(temp[i] <= time_quantum && temp[i] > 0)
{
total = total + temp[i];
temp[i] = 0;
counter = 1;
}
else if(temp[i] > 0)
{
temp[i] = temp[i] - time_quantum;
total = total + time_quantum;
}
if(temp[i] == 0 && counter == 1)
{
x--;
printf(" \n Process[%d] %d %d %d", i + 1, burst_time[i], total - arrival_time[i], total -
arrival_time[i]- burst_time[i]);
wait_time = wait_time + total - arrival_time[i] - burst_time[i];
turnaround_time = turnaround_time + total - arrival_time[i];
counter = 0;
if(i == limit - 1)
{
i = 0;
}
else if(arrival_time[i + 1] <= total)
{ i+
+;}
else
{
i = 0;}}
average_wait_time = wait_time * 1.0 / limit;
average_turnaround_time = turnaround_time * 1.0 / limit;
Output:
Lab Task
Implement Round Robin CPU Scheduling Algorithm.
#include<stdio.h>
int main()
{
int i, limit, total = 0, x, counter = 0, time_quantum;
int wait_time = 0, turnaround_time = 0, arrival_time[10], burst_time[10], temp[10];
float average_wait_time, average_turnaround_time;
printf("\nEnter Total Number of Processes:\t");
scanf("%d", &limit);
x = limit;
for(i = 0; i < limit; i++)
{
printf("\nEnter Details of Process[%d]\n", i + 1);
printf("Arrival Time:\t");
scanf("%d", &arrival_time[i]);
printf("Burst Time:\t");
scanf("%d", &burst_time[i]);
temp[i] = burst_time[i];
}