Operating System Lab
Operating System Lab
System calls
write()/read() system calls
open() system call
lseek() system call
dup() system call
Process
Process Duplication using fork()
Program for wait() system call
Program to create an Orphan Process
Creating a Zombie Process
Understanding the execl() system call
Difference between system() vs execl()
Thread
Program to create threads in linux
Program to return integer value from thread
Program to pass array to thread
Deadlock
Program to simulate Deadlock using threads
Synchronization
Race Condition
Process synchronization using mutex locks
Process synchronization using semaphores
Dining Philosopher Problem
Inter-Process Communication (IPC)
Program for IPC using popen/pclose
Program for IPC using pipe() function
Program for IPC using named pipes(mkfifo)
Program for IPC using shared memory
Program for IPC using Message Queues
Disk Scheduling Algorithms
FCFS algorithm program
SSTF algorithm program
SCAN algorithm prohram
LOOK algorithm program
Page Replacement Algorithms
Manual opening command for different system calls such as read, write and open etc.
irfan@irfan:~$ man 2 write
Command for opening a file in the nano text editor in Linux/ Ubuntu
irfan@irfan:~$ nano w.c
write() system call is used to write to a file descriptor. In other words write()
can be used to write to any file (all hardware are also referred as file in Linux) in
the system but rather than specifying the file name, you need to specify its file
descriptor.
Syntax:
#include<unistd.h>
The first parameter (fd) is the file descriptor where you want to write. The data
that is to be written is specified in the second parameter. Finally, the third
parameter is the total bytes that are to be written.
Program1: To write some data on the standard output device (by default –
monitor)
How it works?
The write() system call takes three parameters: “1” which is the file descriptor
of the file where we want to write. Since we want to write on standard output
device which is the screen, hence the file descriptor, in this case, is ‘1’, which is
fixed (0 is the file descriptor for standard input device (e.g. keyboard) and 2 is
for standard error device)).
Next thing is what we want to write on the screen. In this case its “hello\n” i.e.
hello and newline(\n), so a total of 6 characters, which becomes the third
parameter. The third parameter is how much you want to write, which may be
less than the data specified in the second parameter. You can play around and
see the change in output.
Output:
Once you compile and run this, the output on the screen will be the word
“hello”, as shown below
On success, the write() system call returns the ‘number of bytes written’ i.e. the
count of how many bytes it could write. This you can save in an integer variable
and checked. The write() system call on failure returns -1.
Note: students get confused by thinking that write() return the data that is
written. Remember, it returns the count of characters written. Refer to the
program below.
Program 2
#include<stdio.h
#include<unistd.h>
int main()
int count;
count=write(1,"hello\n",6);
How it Works?
The program is similar to the previous one except that this time it also explicitly
prints the count of bytes that write() system call was able to write on file
descriptor 1.
Output:
Variations
Try making the changes as shown in the codes below and observe the output to
understand the working of the write() system call in detail.
Program 3:
#include<unistd.h>
int main()
{
write(1,"hello\n",60); //the bytes to be printed (third parameter)
are more than the data specified in 2nd parameter
Program4:
#include<unistd.h>
int main()
Program5:
#include<unistd.h>
#include<stdio.h>
int main()
int count;
Will this call to write() be successful? If not then what will it return?
read()
The use of read() system call is to read from a file descriptor. The working is
same as write(), the only difference is read() will read the data from file pointed
to by file descriptor.
Syntax:
#include<unistd.h>
The first parameter is the file descriptor. The second parameter is the buffer
where the read data will be saved. Lastly, the third parameter is the number of
bytes that you want to read.
Think of the buffer as a temporary storing area. As you are reading from this
page and before typing the program on your system you temporarily store it in
your brain. So your brain is the buffer. Although this page contains a lot of data,
you might want to read only 20 characters. Hence, the third parameter (count)
tells, how much you want to read?
Program 6: To read data from the standard input device and write it on the
screen
//read.c
#include<unistd.h>
int main()
char buff[20];
}
How it works?
The read() system call reads the input typed by the user via the keyboard (file
descriptor 0) and stores it in the buffer (buff) which is nothing but a character
array. It will read a maximum of 10 bytes (because of the third parameter). This
can be less than or equal to the buffer size. No matter how much the user types
only first 10 characters will be read.
Finally, the data is printed on the screen using the write() system call. It prints
the same 10 bytes from the buffer (buff) on the screen (file descriptor 1).
Output:
Variations: you can try different values of the third parameter in read and write
to understand the working better.
The read() system call returns -1 on failure and “the count of bytes read” on
success.
Important:
A common question that comes to our mind is that as a programmer you can
not guarantee how much the user will type as an input. Hence, you can not
specify the correct bytes in write() system call’s 3rd parameter. Hence, the
output may vary from what you expect.
Now, remember what read() returns on success! the number of bytes read, and
that’s the key as demonstrated below.
Program 7: To read data from the standard input device and write it on the
screen
//read.c
#include<unistd.h>
int main()
{
int nread;
char buff[20];
How it works?
This time we store the count of bytes read by read() in nread variable and then
use variable in the write() to print exactly the same number of bytes on the
screen.
Q1. Write a program to read a maximum of 15 characters from the user and
print them on the screen.
Q2. Write a program to print the count of characters read by the read() system
call.
Syntax
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
The open() system call has two syntax. We discuss the first one here:
The first parameter is the name of the file that you want to open for
reading/writing. The second parameter is the mode in which to open the file i.e.,
for reading or for writing. For reading from a file, the flag used is O_RDONLY, for
writing O_WRONLY and for both reading and writing O_RDWR.
Other commonly used flags are O_CREAT, O_APPEND, O_TRUNC, O_EXCL
On success, the open() system call return the file descriptor of the file. This
descriptor now can be used in read()/write() system call for further processing.
The value of the file descriptor will always be a positive number greater than 2.
Whereas on failure it returns -1.
Program 1: Write a program using open() system call to read the first 10
characters of an existing file “test.txt” and print them on screen.
//open.c
#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
int n,fd;
char buff[50];
How it works?
First, create a file “test.txt” and write some content into it(more than 10
characters). The open() system call opens the file test.txt in read-only mode and
returns the file descriptor. This file descriptor is saved in variable ‘fd’. You can
print it to check the value of file dexcriptor of the file. next, use read() to read
10 characters from the file into the buffer. Finally, the buffer values are printed
on the screen. The file descriptor used here is ‘0’ which is the file descriptor for
standard output device.
Output
Syntax 2:
The second syntax is used when the file involved does not already exist in the
system and you want to create it on the go.
The first parameter is the file name. The second parameter is the mode
(read/write). In this case apart from writing O_RDONLY, O_WRONLY and O_RDWR
you also need to write O_CREAT, to create the file. The third parameter secifies
the permissions on the created file (read/write/execute).
Note: O_RDONLY and O_WRONLY flags are different from read and write
permission in the manner that even if a file has write permision on it it will not
open in write mode until you specify the O_WRONLY mode.
Now, we extend Program 1 to read from file text.txt and write the contents into
a npon existing file “towrite.txt”
Program2: To read 10 characters from file “test.txt” and write them into non-
existing file “towrite.txt”
//open2.c
#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
int n,fd,fd1;
char buff[50];
fd=open("test.txt",O_RDONLY);
n=read(fd,buff,10);
write(fd1,buff,n);
How it works?
In this we open the “towrite.txt” in write mode and also use O_CREAT to create
it with read and write permission for user, read for the group and write for
others. The data is read from test.txt using file descriptor fd and stored in buff. It
is then written from buff array into file towrite.txt using file descriptor fd1.
Output
Q1. Write a program to read the contents of file F1 into file F2. The contents of
file F2 should not get deleted or overwritten.
hint: use O_APPEND flag
Q2. Write a program using open() system call to copy the contents of one file
into another file.
Solution Link
Syntax
#include <sys/types.h>
#include <unistd.h>
The first parameter is the file descriptor of the file, which you can get using
open() system call. the second parameter specifies how much you want the
pointer to move and the third parameter is the reference point of the movement
i.e., beginning of file(SEEK_SET), current position(SEEK_CUR) of pointer or end of
file(SEEK_END).
Examples:
To understand the working of lseek() system call lets first write two programs:
Program1 without using lseek() and Program2 using lseek().
Program1: Program using lseek() system call that reads 10 characters from file
“seeking” and print on screen. Again read 10 characters and write on screen.
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h
#include<sys/stat.h>
#int main()
int n,f;
char buff[10];
f=open("seeking",O_RDWR);
read(f,buff,10);
write(1,buff,10);
read(f,buff,10);
write(1,buff,10);
Output
Program2: Program using lseek() system call that reads 10 characters from file
“seeking” and print on screen. Skip next 5 characters and again read 10
characters and write on screen.
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h
#include<sys/stat.h>
int main()
int n,f;
char buff[10];
f=open("seeking",O_RDWR);
read(f,buff,10);
write(1,buff,10);
read(f,buff,10);
write(1,buff,10);
Output
This time the output will be the first 10 characters “1234567890” followed by
“fghijxxxxx”. The inbetween 5 characters are skipped because we used lseek to
reposition the pointer 5 characters ahead from the current (SEEK_CUR) position.
#include<unistd.h>
#include<fcntl.h>
#include<sys/types.h
#include<sys/stat.h>
#include<stdio.h>
int main()
{
int n,f,f1;
char buff[10];
f=open("seeking",O_RDWR);
f1=lseek(f,10,SEEK_SET);
printf("Pointer is at %d position\n",f1);
read(f,buff,10);
write(1,buff,10);
How it works?
lseek is used to position the cursor at 10th position from the starting, hence the
use of SEEK_SET. f1 saves the current position of the pointer which is printed.
Then the next 10 characters are read using read() and printed on screen using
write().
Output
Q1. Write a program to print characters starting from 15th character till the 20th
character of file F1.txt into file F4.txt.
Q2. Write a program to print the last 5 characters of a file.
Q3. Write a program to read a number(n) from the user. Print the first n
characters from the file F1.txt.
Q4. Write a program to print the second half of a file.
Q5. Write program(s) to show the use of SEEK_SET, SEEK_CUR and SEEK_END.
(solution)
Q1. How can you find the size of the file using lseek() system call?
Q2. Can lseek() be used to read and write also?
Before starting with the program to use dup() system call in linux, let’s first
understand the use and syntax of dup()
Use
dup() system call is used to duplicate a file descriptor. It creates a copy of the
old file descriptor to a new file descriptor. The new file descriptor can be system-
generated or a number of your choice depending upon either you use dup() or
dup2().
Syntax
#include<unistd.h>
dup() takes the old file descriptor as the input parameter. On success, it returns
the lowest-numbered unused file descriptor as the new file descriptor.
Now, we can use the old and the new file descriptor because they refer to the
same file.
Note: Both these file descriptor share the same file offset i.e., if you use old file
descriptor to read from the file and the file pointer is positioned at 10th position.
Even if you use new file descriptor the reading/writing within the file will start
from 10th position only.
dup2() system call is same as dup() with the difference that here you can give
the value of new file descriptor of your own choice. If the new file descriptor is
already open, it is silently closed and then reopened for reuse.
Programs
//dup.c
#include<unistd.h>
#include<stdio.h>
3include<fcntl.h>
int main()
old_fd=open("test.txt",O_RDWR);
new_fd=dup(old_fd);
How it works?
open() system call returns the file descriptor of the file “test.txt”. The old_fd
variable stores the value of this file descriptor. Next, we duplicate the file
descriptor by using dup(), which assign the lowest unused file descriptor value.
Finally, the new_fd variable stores the value of the new file descriptor. Now,
both old_fd and new_fd point to the same file “test.txt”
Output
Program 2: Program to use dup2() system call in linux to duplicate a file descriptor.
//dup2.c
#include<unistd.h>
#include<stdio.h>
3include<fcntl.h>
int main()
old_fd=open("test.txt",O_RDWR);
new_fd=dup2(old_fd,7);
How it works?
it works in the same manner as Program 1 with the only difference that now the
value of new file descriptor will be ‘7’.
Output
Program 3: Program to show that both file descriptor point to the same file and
same pointer position is maintained
#include<unistd.h>
#include<stdio.h>
#include<fcntl.h>
int main()
char buff[10];
old_fd=open("test.txt",O_RDWR);
write(1,buff,10);
How it works?
The file “test.txt” is opened with the pointer positioned at ‘1’. The read() system
call reads the first 10 characters i.e., 1234567890 and write() prints them on
screen. The call to read() leaves the pointer pointing to ‘a’ (the 11th character of
the file). Next, the file descriptor is duplicated and read() is used to read 10
more characters. Since, the pointer is at ‘a’ it reads the next 10 characters
starting ‘a’ which are “abcdefghij”. Hence, the output “1234567890abcdefghij”
Output
Q1. Write a program using dup()/dup2() to assign ‘1’ as the duplicate file
descriptor.
Q2. Write a program to duplicate a file descriptor of a file. Use the old file
descriptor to read the first 5 characters and the new file descriptor to append
some new content to the file.
Q1. Can you assign 0,1,2 as new file descriptors using dup()?
Q2. Can you assign 0,1,2 as new file descriptors using dup2()?