0% found this document useful (0 votes)
28 views

Operating System Lab

Uploaded by

Sehrish Murtaza
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
28 views

Operating System Lab

Uploaded by

Sehrish Murtaza
Copyright
© © All Rights Reserved
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 22

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

Compile command in Linux


irfan@irfan:~$ gcc w.c

Run command in Linux


irfan@irfan:~$ ./a.out

write()/read() system call


read() and write() system calls are used to read and write data respectively to a
file descriptor. To understand the concept of write()/read() system calls let us
first start with write() system call.

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>

ssize_t write(int fd, const void *buf, size_t count);

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.

To understand better lets look at the first program below:

Program1: To write some data on the standard output device (by default –
monitor)

//Name the program file as “write.c”


#include<unistd.h>
int main()
{
write(1,"hello\n",6); //1 is the file descriptor, "hello\n" is the
data, 6 is the count of characters in data
}

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);

printf("Total bytes written: %d\n",count);

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()

write(1,"hello\n",3);//the bytes to be printed (third parameter)


are less than the data specified in 2nd parameter

Program5:

#include<unistd.h>

#include<stdio.h>

int main()

int count;

count=write(3,"hello\n",6); //the file descriptor is not one of the


pre-specified ones i.e., 0, 1 or 2

printf("Total bytes written: %d\n",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>

ssize_t read(int fd, const void *buf, size_t count);

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];

read(0,buff,10);//read 10 bytes from standard input


device(keyboard), store in buffer (buff)

write(1,buff,10);//print 10 bytes from the buffer on the screen

}
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];

nread=read(0,buff,10);//read 10 bytes from standard input


device(keyboard), store in buffer (buff)

write(1,buff,nread);//print 10 bytes from the buffer on the screen

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.

Practice Programs on write()/read() system call

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.

Viva Questions on write()/read() system call

Q1. What does the write() system call return on success?


Q2. What does the write() system call return on failure?
Q3. Can you use write() system to send data to a printer?
Q4. Can write system be used to write into a file “xyz.txt” without knowing the
file descriptor of xyz.txt?
Q5. How to access the manual page of write()?
Q6. What does the read() system call return on success?

Program on open() system call


In the previous section on read/write system call we learned how to read from
the standard input device and how to write to a standard output device. But,
normally we would either read from a user-created file or write to a user-created
file. Hence, the question comes that how do know the file descriptor of these
files because to read or to write the first parameter in the read()/write() system
calls is the file descriptor. We can use the open() system call to get the file
descriptor of any file.

Syntax

#include <sys/types.h>

#include <sys/stat.h>

#include <fcntl.h>

int open(const char *pathname, int flags);

int open(const char *pathname, int flags, mode_t mode);

The open() system call has two syntax. We discuss the first one here:

int open(const char *pathname, int flags);

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];

fd=open("test.txt",O_RDONLY); //opens test.txt in read mode and the


file descriptor is saved in integer fd.

printf("The file descriptor of the file is: %d\n,fd); // the value


of the file descriptor is printed.

n=read(fd,buff,10);//read 10 characters from the file pointed to by


file descriptor fd and save them in buffer (buff)

write(1,buff,n); //write on the screen from the buffer

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

Step1: create the file test.txt and write “1234567890abcdefghij54321” into it


$nano test.txt
Step2: compile the program
$gcc open.c
Step3: run
$./a.out

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.

int open(const char *pathname, int flags, mode_t mode);

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);

fd1=open("towrite.txt",O_WRONLY|O_CREAT,0642);//use the pipe symbol


(|) to separate O_WRONLY and O_CREAT

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

Practice Program on open() system call

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

Viva Questions on open() system call

Q1. What does the open() system call returns on success?


Q2. Which system call is use to know the file descriptor of a file?
Q3. The value of the file descriptor of any user-created file is always greater
than 2. Why?
Q4. What is the difference between O_APPEND and O_TRUNC flags used in
open() system call?

lseek() system call


lseek() system call repositions the read/write file offset i.e., it changes the
positions of the read/write pointer within the file. In every file any read or write
operations happen at the position pointed to by the pointer. lseek() system call
helps us to manage the position of this pointer within a file.
e.g., let’s suppose the content of a file F1 is “1234567890” but you want the
content to be “12345hello”. You simply can’t open the file and write “hello”
because if you do so then “hello” will be written in the very beginning of the file.
This means you need to reposition the pointer after ‘5’ and then start writing
“hello”. lseek() will help to reposition the pointer and write() will be used to write
“hello”

Syntax

#include <sys/types.h>

#include <unistd.h>

off_t lseek(int fd, off_t offset, int whence);

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:

 lseek(fd,5,SEEK_SET) – this moves the pointer 5 positions ahead starting from


the beginning of the file
 lseek(fd,5,SEEK_CUR) – this moves the pointer 5 positions ahead from the
current position in the file
 lseek(fd,-5,SEEK_CUR) – this moves the pointer 5 positions back from the
current position in the file
 lseek(fd,-5,SEEK_END) -> this moves the pointer 5 positions back from the
end of the file
On success, lseek() returns the position of the pointer within the file as
measured in bytes from the beginning of the file. But, on failure, it returns -1.

To understand the working of lseek() system call lets first write two programs:
Program1 without using lseek() and Program2 using lseek().

Pre-requisite: Create a file “seeking” and write


“1234567890abcdefghijxxxxxxxxxx” into it.

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

Q. What you think should be the output of this program?


Ans: it will be
1234567890abcdefghij
Because when the file opens the pointer is in the start by default. read() reads
10 characters “1234567890”. The pointer is now positioned at ‘a’ i.e., 10
positions ahead. write() then writes the characters on screen. read() again reads
next 10 characters “abcdefghij” and write() writes on the screen.

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);

lseek(f,5,SEEK_CUR);//skips 5 characters from the current position

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.

Here’s another program to understand the working better

Program3: Write a program to print 10 characters starting from the 10th


character from a file “seeking”.

//Let the contents of the file F1 be “1234567890abcdefghijxxxxxxxx”. This


means we want the output to be “abcdefghij”.
//Note: the first character ‘1’ is at 0th 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

Practice Questions on lseek() system call

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)

Viva Questions on lseek() system call

Q1. How can you find the size of the file using lseek() system call?
Q2. Can lseek() be used to read and write also?

Program for dup() system call


Leave a Comment / Programs / By Baljit Singh Saini

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>

int dup(int oldfd);

int dup2(int oldfd, int newfd);

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

Program 1: Program for dup() system call in C to duplicate a file descriptor.

//dup.c

#include<unistd.h>

#include<stdio.h>

3include<fcntl.h>

int main()

int old_fd, new_fd;

old_fd=open("test.txt",O_RDWR);

printf("File descriptor is %d\n",old_fd);

new_fd=dup(old_fd);

printf("New file descriptor is %d\n",new_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()

int old_fd, new_fd;

old_fd=open("test.txt",O_RDWR);

printf("File descriptor is %d\n",old_fd);

new_fd=dup2(old_fd,7);

printf("New file descriptor is %d\n",new_fd);

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

//create a file test.txt with the content


"1234567890abcdefghij54321"

#include<unistd.h>

#include<stdio.h>

#include<fcntl.h>

int main()

int old_fd, new_fd;

char buff[10];

old_fd=open("test.txt",O_RDWR);

read(old_fd,buff,10);//read first 10 characters using old file


descriptor

write(1,buff,10);//prints them on screen

new_fd=dup(old_fd);//duplicates file descriptor


read(old_fd,buff,10);//this read will read the next 10 characters
even if new file descriptor is used

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

Practice Programs on dup() system call in C

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.

Viva questions on dup() system call

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()?

Operating System Lab - Dextutor

(4) Linux Installation - YouTube

You might also like