Vous êtes sur la page 1sur 132

Kuwait University

Kuwait University

College
for Women
Information Technology
Solutions

College of Computing Sciences and Engineering


Department of Information Science

LAB MANUAL
ISC 357
OPERATING SYSTEMS AND FILE SYSTEM ORGANIZATION
LABORATORY
Version 1.0

PREPARED BY
DR. KALIM QURESHI
PROF. DR. MOHAMMAD SARFRAZ
MARYAM AL-OTAIBI

REVISED SPRING 2015-2016

TABLE OF CONTENTS
Lab Hardware, Softwares / Tools Requirements ............................................................................................... 6
LAB SYLLABUS for ISC357 ............................................................................................................................................ 7
Operating Systems and File System Organization .............................................................................................. 7
Course catalog ............................................................................................................................................................... 7
Lab Objective ................................................................................................................................................................. 7
Prerequisite.................................................................................................................................................................... 7
Lab Schedule .................................................................................................................................................................. 8
Evaluation Policy ......................................................................................................................................................... 9
Project .............................................................................................................................................................................. 9
Laboratory Policy ........................................................................................................................................................ 9
Laboratory 0: How install UBUNTU 8.10 DESK TOP EDITION ........................................................... 10
Laboratory1: Introduction to the UNIX Operating System .......................................................................... 18
What is UNIX?............................................................................................................................................................. 18
Types of UNIX ............................................................................................................................................................. 18
Unix Major Components ........................................................................................................................................ 18
Files and processes .................................................................................................................................................. 19
The Directory Structure ......................................................................................................................................... 20
Accessing UNIX System .......................................................................................................................................... 21

Connected to UNIX machines remotely via Putty ................................................................... 21


Starting UNIX terminal ...................................................................................................................... 22
Laboratory2,4: Unix Commands.............................................................................................................................. 24
Command syntax rules ........................................................................................................................................... 24
UNIX Directory Management Commands ....................................................................................................... 25

Printing working directory command - pwd ............................................................................ 25


Changing Directory- cd ..................................................................................................................... 25
List -ls ....................................................................................................................................................... 27
Make a directory-mkdir .................................................................................................................... 28
Remove directory ................................................................................................................................ 29
copy -cp ................................................................................................................................................... 30
Move-mv ................................................................................................................................................. 31
Display file content- cat, more, less, head, tail ......................................................................... 31
Finding a file find ............................................................................................................................. 32
Searching the Contents of a File .................................................................................................... 33
Determine file type ............................................................................................................................. 34
Entering more than one command.................................................................................................................... 34
2|Page

Redirecting standard input and output ........................................................................................................... 34


Access Permissions .................................................................................................................................................. 35

Understanding Access Permissions ............................................................................................. 35


Displaying Access Permissions ...................................................................................................... 35
Default Access Permissions ............................................................................................................. 36
Changing Access Permissions......................................................................................................... 36
Process related commands ................................................................................................................................... 37

What is a Process? ............................................................................................................................... 37


Monitoring processes ........................................................................................................................ 37
Managing Jobs and Processes ......................................................................................................... 38
Placing a foreground process in the background ..................................................................... 39
Miscellaneous Command ....................................................................................................................................... 40
Excersices..................................................................................................................................................................... 41
Laboratory 5, 6: Shell Programming ..................................................................................................................... 42
Overview of Shell ...................................................................................................................................................... 42
User defined variables ............................................................................................................................................ 43

Reading Values into User-defined Variables (Reading user input): ................................ 43


Command Substitution: .................................................................................................................... 44
Computation on Shell Variables .................................................................................................... 45
Pre-defined shell variables ................................................................................................................................... 45

Passing arguments to the shell ...................................................................................................... 46


Shift command .......................................................................................................................... 46
Conditional Execution Operators ....................................................................................................................... 48
Conditional statements .......................................................................................................................................... 49

The if statement ................................................................................................................................... 49


Nested if statement .................................................................................................................. 49
test Command ........................................................................................................................... 49

The case statement ............................................................................................................................. 52


Flow of control statements ................................................................................................................................... 54

The for statement ................................................................................................................................ 54


The while and until statements ..................................................................................................... 55
The break and continue statements............................................................................................. 55
Excersices..................................................................................................................................................................... 58
Laboratory7: UNIX and Advance topics in C Programming......................................................................... 59
A Simple C Program ................................................................................................................................................. 59
Compile and Execute a C program under Unix System ............................................................................. 59
3|Page

UNIX Library Functions.......................................................................................................................................... 60


C Functions .................................................................................................................................................................. 61
Command line arguments in C ............................................................................................................................ 62
Running UNIX Commands From C..................................................................................................................... 63
laboratory8: Major File Structure Related System Calls ............................................................................... 64
What is a System Call? ............................................................................................................................................ 64
Use of System Calls ................................................................................................................................................... 64
creat( ) System Call .................................................................................................................................................. 66
close( ) System call ................................................................................................................................................... 69
read() write()System calls .................................................................................................................................... 69
lseek() system call .................................................................................................................................................... 70
Excersices..................................................................................................................................................................... 72
laboratory9, 10: Process Creation and Execution ............................................................................................ 73
The death of a parent or child process............................................................................................................. 76

Parent process dies before child process................................................................................... 76


Child process dies before parent process .................................................................................. 77
Excersices..................................................................................................................................................................... 78
Laboratory11: Inter-Process Communication: Pipes & Signals ................................................................. 82
Pipes ............................................................................................................................................................................... 82

pipe System Call ................................................................................................................................... 82


I/O with a pipe .......................................................................................................................... 83
Signals............................................................................................................................................................................ 89

SIGHUP .................................................................................................................................................... 90
SIGINT ...................................................................................................................................................... 90
SIGTSTP ................................................................................................................................................... 90
SIGQUIT ................................................................................................................................................... 90
SIGILL ....................................................................................................................................................... 91
SIGTRAP .................................................................................................................................................. 91
SIGIOT ...................................................................................................................................................... 91
SIGEMT .................................................................................................................................................... 91
SIGFPE ..................................................................................................................................................... 91
SIGKILL .................................................................................................................................................... 91
SIGBUS ..................................................................................................................................................... 91
SIGSEGV................................................................................................................................................... 91
SIGPIPE .................................................................................................................................................... 91
SIGALARM .............................................................................................................................................. 92
4|Page

SIGTERM ................................................................................................................................................. 92
SIGUSR1 .................................................................................................................................................. 92
SIGUSR2 .................................................................................................................................................. 92
SIGPWR ................................................................................................................................................... 92
Requesting An Alarm Signal: alarm( ) ......................................................................................... 93
pause System Call:............................................................................................................................... 95
kill System Call ..................................................................................................................................... 96
Excersices..................................................................................................................................................................... 97
laboratory12: Inter Process Communication (IPC)-Using Shared Memory........................................ 100
What is Shared Memory?..................................................................................................................................... 101
Asking for a Shared Memory Segment - shmget( ) ................................................................................... 102
Attaching a Shared Memory Segment to an Address Space - shmat( )............................................. 104
Detaching and Removing a Shared Memory Segment - shmdt( ) and shmctl( )........................... 106
Excersices................................................................................................................................................................... 111
laboratory13: Threads Creation and Execution ............................................................................................. 111
Introduction .............................................................................................................................................................. 112

What is thread? ................................................................................................................................. 112


What are pthreads? ......................................................................................................................... 112
Why pthreads?................................................................................................................................... 113
The pthreads API .................................................................................................................................................... 113

Thread Management Functions:................................................................................................. 114


Thread Initialization ....................................................................................................................... 115
Terminating Thread Execution:.................................................................................................. 115
Thread Attributes ............................................................................................................................. 116
Thread Identifiers: ........................................................................................................................... 117
Excersices................................................................................................................................................................... 126
Appendix A ..................................................................................................................................................................... 129
References ...................................................................................................................................................................... 130
Appendix A: Rules to fallow by Computer Lab Users................................................................................ 131
Appendix B: Certification ...................................................................................................................................... 132

5|Page

LAB HARDWARE, SOFTWARES / TOOLS REQUIREMENTS

Softwares
Currently used software
1. Redhat server
2. Putty which is a client program for the ssh, telnet and rlogin network protocols.
3. Ubuntu for DESKTOP

Hardware
Hardware required is standard PC having Mouse, Keyboard, Monitor, and Networking Support.

6|Page

LAB SYLLABUS FOR ISC357


OPERATING SYSTEMS AND FILE SYSTEM ORGANIZATION

COURSE CATALOG
The main aim of this course is to acquire a systematic knowledge of operating systems and to
develop a critical understanding of their purpose, the main concepts, techniques and methods.
Topics covered include processes and threads, scheduling, memory management, file systems,
and storage file organizations and access methods from the operating system, programming
language, and information systems design perspectives are also introduced.

LAB OBJECTIVE
The objective of the operating systems labs is to practically implement the major operating
system issues discussed in the lectures. All the process, memory, file and directory management
issues will be demonstrated under the UNIX/LINUX operating system. Also the UNIX commands
and shell programming will be discussed in detail.

PREREQUISITE
It is very essential for students to have strong knowledge of the C language for this course, as all
experiments will be written in C language.

7|Page

LAB SCHEDULE

Lab
Lab-1

Lab-2

Lab-3

Topic
Introduction
get familiar with UNIX,
Connect to UNIX machines remotely via Putty,
Starting UNIX terminal (UBUNTU),
Getting user accounts, and How to Login Redhat server,
Getting familiar with UNIX environment.
Unix Directory Management Commands (pwd, cd, ls, mkdir, rmdir, cp, mv, find, Determine
file type: file, Linking files and directories)

Lab-11

File Manipulation Commands


Display file content ( cat, more, less, head, tail)
Searching the Contents of a File : grep
Sorting the content of a file
File Manipulation Commands: vi Text Editors
Continue Unix Commands
Entering more than one command.
Redirecting standard input and output.
Miscellaneous Command (who, finger, echo, tty ,Id , Clear, Hostname, cal, wc)
Access Permissions command.
UNIX Shell Programming
UNIX and C Programming ( Pointers, linked lists, structures, Arrays)
Major File Structure Related System Calls (creat( ),open( ),close( ), read( ) , write( ) , and
lseek( ) )
Major Process Related System Calls
fork,
exec,
wait,
sleep,
exit
The death of a parent or child process
Inter-Process Communication. i.e. Pipes & Signals

Lab-12

Inter Process Communication (IPC)-Using Shared Memory

Lab-13

Threads Creation and Execution


Creating Threads
Terminating Thread Execution
Passing Arguments To Threads
Thread Identifiers
Joining Threads
Detaching / Undetaching Threads

Lab-4

Lab-5, 6
Lab-7
Lab-8
Lab-9,10

8|Page

EVALUATION POLICY
Activity
Lab Work (12 x 0.5%)
Lab Quizzes + HWs
Lab Project
Total

Weight
6%
9%
6%
21%

PROJECT
There will be two mini projects covering the two major topics Shell Programming and Processes/
Threads. Project summary/outline will be provided on the blackboard. Honor the project
submission dead line. After that dead line, a reduction of 20 points for up to 24 hours late
submission and -50 points for up to next 24 hours late submission and after that, submissions
will not be accepted. The projects will be graded only after the student gives a demonstration of
it. Without the demo, the project will not be graded. The projects should be submitted in both
soft copy (through blackboard) and hard copy (printed) in the form of a report with the source
code, along with the detailed explanation of the approach followed.

Notes:

To pass this course, the student must pass the lab-component of the course.
Cheating in whatever form will result in F grade.
Attendance will be checked at the beginning of each Lab.
Absence for three (03) or more unexcused labs will result in a F grade in the Course. An
official excuse must be shown in one week following return to classes.
Every unexcused absence leads to a loss of 0.5 % marks.
Cheating in Lab Work or Lab Project will result F grade in Lab.
Late Submission of Home Works & Projects will not be accepted.
There will be no make-up for any Quiz/Exam/Lab.
Hard work and dedication are necessary ingredients for success in this course.

LABORATORY POLICY

Fallow the laboratory rules listed in appendix A

To pass this course, the student must pass the lab-component of the course.

Cheating in whatever form will result in F grade.

Attendance will be checked at the beginning of each Lab.

Absence for three (03) or more unexcused labs will result in a F grade in the Course. An
official excuse must be shown in one week following return to classes.

Every unexcused absence leads to a loss of 0.5 % marks.

Cheating in Lab Work or Lab Project will result F grade in Lab.

Late Submission of Home Works & Projects will not be accepted.

There will be no make-up for any Quiz/Exam/Lab.

9|Page

LABORATORY 0: HOW INSTALL UBUNT U 8.10 DESK TOP EDITION


Objective:
Learn How to down load and install UBUNTU 8.10 DESK TOP EDITION in your PC.
Procedure:

The installation of the base system is easy as 1-2-3 because the Ubuntu installer doesn't offer
a lot of options to choose from, so you cannot go wrong.
1. Download the Ubuntu 8.10 desktop edition iso image from
http://www.ubuntu.com/getubuntu/download (or take the CD from your instructor), burn
it onto a CD, and boot your computer from it.
2.

Select your language when asked...

3. Select the second option "Install Ubuntu," and hit the Enter key...

10 | P a g e

4. Wait for the CD to load into RAM...

5. When the installer appears, you are able to select your native language for the installation
process. Click the Forward button to continue...

11 | P a g e

6. Select your location.


The second screen will feature a map of the Earth with little red dots, so you can select your
city/country. Upon the selection of your current location, the time for the final system will
adjust accordingly. You can also select your current location from the drop down list
situated at the bottom of the window.
Click the Forward button after you have selected your desired location...

7. Test your keyboard


On the third screen, you will be asked to select the keyboard layout that suits you best
(default is U.S. English). You can also test your keyboard on the small text input field
situated at the bottom of the window.
Click the Forward button when you have finished with the keyboard configuration...

12 | P a g e

8. Hard disk partitioning


Hold on, don't leave just yet! The hard disk partitioning is an easy task, so I am quite sure
you will handle it too. You have three options here:
1. If you want to keep your existing operating system (e.g. Dual boot with Windows XP),
select the first option: "Guided - resize the partition and use the freed space." This option will
appear if you have another operating system installed, such as Microsoft Windows. Remember
that, after the installation, the Windows boot loader will be overwritten by the Ubuntu boot
loader!
2. If you want to delete your existing operating system, or the hard drive is already empty
and you want to let the installer automatically partition the hard drive for you, select the
second option, "Guided - use entire disk."
3. Manual is the third choice and it is recommended for advanced users.
WARNING: Be aware that all the data on the selected hard drive or partition will be
ERASED and IRRECOVERABLE.
Click the Forward button to continue with the installation...

9. Who are you?


On this screen, you must do exactly what the title says. Fill in the fields with your real name,
the name you want to use to log in on your Ubuntu OS (also known as the username), the
password and the name of the computer (automatically generated, but can be overwritten).
Also at this step, there's an option called Log in automatically. If you check the box on this
option, you will be automatically logged in to the Ubuntu desktop.
Click the Forward button...

13 | P a g e

10. Are you really ready for Ubuntu?


This is the final step of the installation. Here, you can select to install the boot loader on
another partition or hard drive than the default one...

Click the Install button to install Ubuntu...

14 | P a g e

The Ubuntu 8.10 (Intrepid Ibex) operating system will be installed...

After approximately 8 to 15 minutes (depending on your computer's specs), a pop-up window


will appear, notifying you that the installation is complete, and you need to restart the computer
in order to use the newly installed Ubuntu operating system.
Click the Restart Now button...

15 | P a g e

11. The CD will be ejected, remove it and press the Enter key to reboot...

The computer will be restarted and, in a few seconds, you will see the Ubuntu login screen.
Input your username and password...

16 | P a g e

Have fun using Ubuntu!

17 | P a g e

LABORATORY1: INTRODUCTION TO THE UNIX OPERATING


SYSTEM
Objective:
1.
2.
3.
4.

Get familiar with UNIX


Connect to UNIX machines remotely via Putty
Starting UNIX terminal (UBUNTU)
Get familiar with UNIX environment
a. Types of UNIX
b. Unix Major Components
c. Files and processes
d. The Directory Structure.

WHAT IS UNIX?
An operating system is the program that controls all the other parts of a computer system - both
the hardware and the software. Most importantly, it allows you to make use of the facilities
provided by the system. Example of operating system are Windows XP, Windows NT, UNIX,
Linux, ..etc.
UNIX is an operating system which was first developed in the 1960s, and has been under
constant development ever since. By operating system, we mean the suite of programs which
make the computer work. It is a stable, multi-user, multi-tasking system for servers, desktops
and laptops [1].
UNIX systems also have a graphical user interface (GUI) similar to Microsoft Windows which
provides an easy to use environment. However, knowledge of UNIX is required for operations
which aren't covered by a graphical program, or for when there is no windows interface
available, for example, in a telnet session [1].

TYPES OF UNIX
There are many different versions of UNIX, although they share common similarities.
The most popular varieties of UNIX are:

Sun Solaris,

GNU/Linux, and

MacOS X.

UNIX MAJOR COMPONENTS


UNIX operating system is made up of three major components the kernel, the Shell, and some
system/ application programs.
1. Kernel
The Kernel is the core of UNIX operating system. It is a large program that is loaded into
memory when the machine is turned on, and it controls the allocation of hardware
18 | P a g e

resources from that point forward. The kernel knows what hardware resources are
available (like the processor(s), memory, the disk drives, network interfaces, etc.), and it has
the necessary programs to talk to all the devices connected to it. It also prevents anyone
from accessing the hardware directly, forcing everyone to use the tools it provides. This way
the kernel provides some protection for users from each other.
2. The Shell
The shell acts as an interface between the user and the kernel. It is a command line
interpreter. It interprets the commands the user types in and arranges for them to be
carried out. It takes each command and passes it to the operating system kernel to be acted
upon. It then displays the results of this operation on your screen. There are several
different shells available for Unix; the most popular are:

/.../sh

Bourne shell (sh)

/.../csh

C shell (csh)

/.../tcsh

TC shell (tcsh)

/.../ksh

Korn shell (ksh)

/.../bash

Bourne Again SHell (bash)

You can identify which shell you are presently using from the last part of the pathname.
Information about which shell you are using is held in the SHELL environment variable.
Example:
Display the value of the variable SHELL.
Note that the name of environment variable must be given in UPPERCASE
>echo $SHELL
/bin/bash
To switch to another shell enter the shell command name at the system prompt.
Example:
This switches you from your current shell to the Bourne shell.
>sh
sh-2.05b>

FILES AND PROCESSES


Everything in UNIX is either a file or a process.
A process is an executing program identified by a unique PID (process identifier).
A file is a collection of data. They are created by users using text editors, running
compilers etc. Types of Unix Files:
1. Ordinary files. This type of file is used to store information, such as some text,
or an image, or Executable or binary file. You can set access permissions to files
which you create you "own". Any file is always contained within a directory.

19 | P a g e

2. Directories. A directory is a file that holds other files and other directories. You
can set access permissions to directory which you create. i.e. you own them.
3. Special files. This type of file is used to represent a real physical device such as a
printer, tape drive or terminal.
4. Pipes. UNIX allows you to link commands together using a pipe. The pipe acts as
a temporary file, which only exists to hold data from one command until it is
read by another.

THE DIRECTORY STRUCTURE


All the files are grouped together in the directory structure. The file-system is arranged in a
hierarchical structure, like an inverted tree. The top of the hierarchy is traditionally called root
(written as a slash / ).

The /bin directory contains the commands and utilities that you use day to day. These
are executable binary files - hence the directory name bin.

The /dev directory contains special files used to represent real physical devices such as
printers and terminals.

The /etc directory contains various commands and files which are used for system
administration

The /home directory contains a home directory for each user of the system.

The /lib directory contains libraries that are used by various programs and languages.

The /tmp directory acts as a "scratch" area in which any user can store files on a
temporary basis.

The /usr directory contains system files and directories that you share with other users.
Application programs, on-line manual pages, and language dictionaries typically reside
here.

20 | P a g e

ACCESSING UNIX SYSTEM


There are many ways that you can access a UNIX system:
The main mode of access to a UNIX machine is through a terminal, which
usually includes a keyboard, and a video monitor. For each terminal connected
to the UNIX system, the kernel runs a process called a tty that accepts input from
the terminal, and sends output to the terminal.
Personal computers can be used to emulate terminals, so that they can be
connected to a UNIX machine. PCs are connected to UNIX machines directly or
remotely.

CONNECTED TO UNIX MACHINES REMOTELY VIA PUTTY


1. You will find Putty program installed in the pcs in the laboratory.
2. Launch Putty: Double-click on the PUTTY program to get Configuration window.
3. Enter the server IP- 139.141.169.188 in the field for 'Host Name (or IP address) and
select 'SSH' radio button for connection type.
4. Then simply press the 'Open' button.

21 | P a g e

The regular PUTTY terminal window will pop up, as it is shown in the figure below. Enter your
username and password. Note that while you are typing your password cursor will not be
moved.

STARTING UNIX TERMINAL


To open an UNIX terminal window, click on the "Terminal" icon from Applications/Accessories
menus.

An UNIX Terminal window will then appear with a % prompt, waiting for you to start entering
commands.
22 | P a g e

23 | P a g e

LABORATORY2,4: UNIX COMMANDS


Objective
1.
2.
3.
4.
5.
6.
7.

Understand Unix Directory Management Commands


Know File Manipulation Commands
Find out How to Enter more than one command
Find out How to Redirecting standard input and output
Learn Access Permissions commands
Study Miscellaneous Command
Learn Process related commands

COMMAND SYNTAX RULES


A command is a program that tells the UNIX system to do something.
A command, or a program, interacts with the kernel to perform the functions called by the
user. A program can be:

an executable shell file, known as a shell script,

built-in shell command, or

a source compiled, object code file.

command [options][arguments]
Commands are case sensitive.
An option: modifies the command, changing the way it performs. Options are generally
preceded by a hyphen (-) and for most commands, more than one option can be used
together.
argument: indicates on what the command is to perform its action, usually a file or
series of files.
Any options or arguments enclosed in [ ] square brackets are optional.
Anything not enclosed in [ ] square brackets must be entered.
Boldface words are considered to be literals and must be typed exactly as they appear.
This usually applies to the command name and command options.
Arguments shown in italics must be replaced by whatever it is that they represent. This
is usually the name of a file or directory.
Ellipses '...' mean that the previous argument can be repeated any number of times.

24 | P a g e

UNIX DIRECTORY MANAGEMENT COMMANDS


PRINTING WORKING DIRECTORY COMMAND - pwd
pwd
Display the pathname of the current working directory
Example:
>pwd
/home/ISC357/091/maryam2
Which means that maryam2 (your home directory) is in the sub-directory 091 (the group
directory), which in turn is located in the ISC357 sub-directory, which is in the home subdirectory, which is in the top-level root directory called " / "(see the figure below) .
/

bin

home

tmp

usr

dev

ISC35
7
091

Myfolder

082

maryam2

test.c

Abrar

report.doc

CHANGING DIRECTORY- cd
cd [directory]
Changing working directory
Examples:
This moves you up to the root
> cd /
This moves you down to your HOME directory.
cd ~
>cd /usr
>pwd
25 | P a g e

/usr
This moves you down one level from current directory to subdirectory bin
>cd bin
>pwd
/usr/bin
>cd usr/etc
>pwd
usr/etc
Move up the directory tree without entering the pathname
>cd ..
>pwd
/usr
This moves you down one level from current directory to subdirectory start with letter e,
for example usr/etc.
>cd e*
This moves you up one level in the directory tree and then moves you into usr/bin the
subdirectory bin
>cd ../bin
(.) means the current directory, in other word stay where you are. Note: there is a space
between cd and the dot. This may not seem very useful at first, but using (.) as the name of
the current directory will save a lot of typing, as we shall see later in the tutorial.
>cd .

26 | P a g e

LIST -ls
ls [-aAcCdfFgilLqrRstu1] [filename]
List the contents of a directory
options

Description

-a

List all entries; even the hidden file that begin with .(dot)

-A

Same as a, except that . and .. are not listed

-c

Use time of last edit (or last mode change) for sorting or printing

-C

Force multiple-column output, with entries sorted down the columns .This is the default when
output is to terminal.

-d

If argument is a directory, lidt only its name(not its contents);often used with l to get the
status of a diectory.

-F

Mark directories with a trailing slash (/), executable files with a trailing asterisk(*), symbolic
links with a trailing at-sign (@), and AF_UNIX address family sockets with a trailing equals
sign(=)

-l

list in long format, access permissions, number of links, owner, size in bytes, and time of last
modification for each file. If the file is a special file the size field will instead contain the major
and minor device numbers. If the time of last modification is greater than six months ago, it is
shown in the format month date year; files modified within six months show month date
time .If the file is a symbolic link the path name of the linked-to file is printed preceded by ->.

-L

If argument is a symbolic link, list the file or directory the link references rather than the link
itself.

-q

Display non-graphic characters in filenames as the character ?; for ls, this is the default when
output is to a terminal.

-r

Reverse the order of sort to get reverse alphabetic or oldest first as a appropriate.

-R

Recursively list subdirectories encountered.

-s

Give size of each file, including any indirect blocks used to map the file, in kilobytes.

-t

Sort by time modified (latest first) instead of by name.

-u

Use time of last access instead of last modification for sorting (with t option) and/or printing
(with the l option)

-1

Force one entry per line output format; this is the default when output is not to terminal

27 | P a g e

Examples:
>ls
bin dev home lib misc usr boot

etc tmp var Examples:

>ls -F
/bin /dev /home /lib /misc /usr /boot

/etc /tmp /var

>ls a
. .. .autofsck bin dev home lib misc usr boot

etc

>ls Fa
. .. .autofsck /bin /dev /home /lib /misc /usr /boot

/etc

>ls m*
myfile maryam.tar
>ls l
rwxr-xr-x 1

ahmed staff

3649 Feb 22 15:51 prog.c

In the example above, this first item -rwxr-xr-x represents the access permissions on
this file.

The owner has read,write and execute permissions.


The group has read and execute permissions.
All other user has execute permissions.

The next items represent the number of links (1) to it; the username (ahmed) of the
person owning it; the name of the group (staff) which owns it; its size in bytes (3649);

MAKE A DIRECTORY-mkdir
mkdir directory Name
Make a directory or directories
Examples:
This creates the directory maryam in the current directory
>mkdir maryam
This creates the directory presentations in the parent
directory of the current working directory
>mkdir . . / presentations
>mkdir ~/test/test1

28 | P a g e

REMOVE DIRECTORY
rmdir directory
Remove an empty directories
Example :
The directory must be empty before you can delete it
>rmdir maryam

rm -r directory
Deletes all the contents of the directory including any subdirectories.
Examples:
Current working
directory

command

home/isc357>

mkdir lab1

home/isc357>

mkdir ../ lab2

home/isc357>

mkdir home/ lab3

29 | P a g e

Result

COPY -cp
cp [ -ip ] filename1 filename2
Copy the content of filename1 into filename2.
cp rR [ ip ] directory1 directory2
Recursively copies directory1, along with its contents and subdirectories to
directory2
Directory2 is created if it does not exist, and directory1 is created as a
subdirectory within it.
cp [-iprR] filename directory
Copy the filename/s in the indicated directory
Options

Description

-i

Interactive, Prompt for confirmation whenever the copy would overwrite an existing file. A
y answer confirms that the copy should proceed. Any other answer confirms cp from
overwriting the file.

-p

Preserve. Duplicate not only the contents of the original file or directory, but also the
modification time and permission modes.

-r/R

Recursive. If any of the source files are directory, copy the directory along with its
files(including any subdirectories and their files); the destination must be directory.

...

The dot is shorthand for the parent directory.

The dot is shorthand for the current directory.

Examples:
>ls ~/maryam/programs
Prog1 prog1.p
> cp ~/maryam/programs/prog1.p ~/maryam/programs/prog1.old
>ls ~/maryam/programs
Prog1 prog1.old prog1.p
>cp r ~/maryam/programs ~/maryam/oldprograms
>ls ~/maryam/oldprograms
Prog1 prog1.old prog1.p
>mkdir ~/tmp
>cp ~/oldprograms/*.* ~/tmp
>Ls ~/tmp
prog1 prog1.old prog1.p
ls R ~/maryam

30 | P a g e

MOVE-mv
mv[ -fi ] filename1 filename2
Rename filename1 as filename2
mv [ fi ] directory1 directory2
mv[-fi] filename directory
Options

Description

-f

Force. Override any mode restrictions and the I option. The f option
also suppresses any warning messages about modes which would
potentially restrict overwriting.

-I

Interactive mode. mv displays the name of the file or directory followed


by a question mark whenever a move would replace an existing file or
directory. If you type a line starting with y, mv moves the specified file or
directory, otherwise mv does nothing with that file or directory.

DISPLAY FILE CONTENT- cat, more, less, head, tail


cat[ -bens] filename
Display the contents of a file on the screen
options

Description

-b

number nonblank output lines

-e

Display nonprinting character and display $ at end of each line

-n

number all output lines, even blank lines.

-s

Squeeze blank never more than one single blank line

Example:
>cat n testfile
1 Hello
2 i this is my first file text file
3
4
5 bye
>cat testfile -sn
1 Hello
2 i this is my first file text file
3
31 | P a g e

4 bye

more filename
Display the contents of a file on the screen.
less filename
Display the contents of a file on the screen. Press the [space-bar] if you
want to see another page, and type [q] if you want to quit reading. As you
can see, less is used in preference to cat for long files.

Keyboard

Description

space bar

Display next page of text.

<RETURN>

Display next line of text.

Quit from reading.

Scroll forwards about half a screen of text.

Skip backwards one screen of text.

Display a list of commands (help).

head -n filename
Display the first n number of lines of a text file use the command.
Displays only first 10 lines if the option of n is not specified
tail -n filename
display the last n number of lines of a text file use the command. Displays
only last and last 10 lines respectively if the option of n is not specified
Example:
Display the first three lines
>head -3 testfile
Displays last and last 10 lines
>tail testfile

FINDING A FILE find


find pathname -name filename
32 | P a g e

This command locates a file in the file system.


Pathname: where to search i.e. defines the directory to start from.
You can define the filename using wildcards. If these are used, the
filename must be placed in 'quotes'.
To search in the whole system for any files named foo and display their pathnames.
>find / -name foo
To find program.c file starting from the current directory: If the file is not found nothing
is displayed.
>find . name program.c -print
Find all files with the extension .c under the current directory.
>find . -name '*.c' -print
To search in /home/isc357/091/maryam2 for all files with name contains tt letters.
find /home/isc357/091/maryam2 -name '*tt*

SEARCHING THE CONTENTS OF A FILE


grep [options] regexp [file(s)]
- used to search for generalized regular expression inside Unix file.
- regexp is a regular expression. It is preferred to be specified single
quotes.
- Options: can be one of the options described in the table below:
Common
options
-i
-c

Meaning
ignore case
report only a count of the number of lines containing matches, not the
matches themselves
invert the search, displaying only lines that do not match
display the line number along with the line on which a match was found
work silently, reporting only the final status:
0, for matche(s) found
1, for no matches
2, for error
list filenames, but not lines, in which matches were found.

-v
-n
-s

-l

Searches for the string copying in the file help and displays the lines related.
>grep copying help
Find and display each line in the file tasks that contains the pattern don't or Don't. The line
number for each line is also displayed.
>grep -n '[dD]on\'t' tasks
List only those students currently login to your server.
>who | grep st*
Count number of directories in your current work directory.
33 | P a g e

>ls F | grep c /$

DETERMINE FILE TYPE


file filename
This command determines the type of a file, or to find out if executable
files contain shell scripts, or are binaries. Shell scripts are text files and
can be displayed and edited.
Example:
file *
file testdir

ENTERING MORE THAN ONE COMMAND


To enter several commands on one command line, use a ; (semicolon) to separate each one
from the next.
Example:
This command line contains two commands. The first, cd .. changes the current directory to
the parent directory. The second, ls -l produces a long listing of the contents of the current
directory. If necessary you can continue the commands onto another line.
> cd .. ; ls l

REDIRECTING STANDARD INPUT AND OUTPUT


UNIX considers any device attached to the system to be a file. By default, a command treats your
terminal as the standard input file from which to read in information. Your terminal is also
treated as the standard output file to which information is sent from the command. This action
can be changed by redirecting standard input and standard output from and to any other file.
Symbol

Description

command <file

To redirect the standard input for a command

command > file

To redirect the standard output from a command. If the file that you
redirect standard output to does not already exists it will be created.

command >>file

To append the standard output from a command to a file

command1 | command2

pipe the output of command1 to the input of command2

Example:
This redirects the standard output from the man command so that it goes to the file
hlp1.txt
man mkdir > hlp1.txt.

34 | P a g e

This creates a file called list1,then you can start type the content you desire till you type
^D it will save the content and exit.
cat > list1
Then start to type in file, ex: .
pear
banana
apple
you can use [Return] ,
^ D {this means press [Ctrl] and [d] to stop}
This creates a file called chapt2 with the same contents as part1.
cat part1 > chapt2
It then reads the contents of part2 and appends them to the file chapt2. The file chapt2
now contains the data from part1 followed by the data from part2.
cat part2 >> chapt2
Concatenate file1 and file2 to file0
cat file1 file2 > file0

ACCESS PERMISSIONS
UNDERSTANDING ACCESS PERMISSIONS
There are three types of permissions:

r
read the file or directory

w
write to the file or directory

x
execute the file or search the directory
Each of these permissions can be set for any one of three types of user:
u
the user who owns the file (usually you)
g
members of the group to which the owner belongs
all
other users
The access permissions for all three types of user can be given as a string of nine characters:
user group others
rwx rwx rwx

DISPLAYING ACCESS PERMISSIONS


To display the access permissions of a file or directory use the ls command:
ls l

filename or directory

Example:
The owner of the file has read and write permissions and no permissions to others.
>ls l file1
-rw------- 2

35 | P a g e

ahmed 3287 Apr 8 12:10 file1

The owner has read and write permissions. Everyone else - the group and all other users
- can read the file.
>ls -l testfile
-rw-r--r-- 2

ahmed 3287 Apr 8 12:11 file2

DEFAULT ACCESS PERMISSIONS


The default access permissions for new created file: rw------- gives you read and write
permission for your files owner; no access permissions for the group or others.
The default access permission s for newly created directory: rwx------ gives you read , write
and execute permission for your directories owner; no access permissions for the group
or others. Access permissions for your home directory are usually set to rwx--x--x or rwxrxr-x.

CHANGING ACCESS PERMISSIONS


chmod [-fR] mode filename
chmod [-fR] mode directory_name
Only the owner of a file (or the super user) may change its mode.
-f: Force.
-R: Recursive
The mode can be changed using absolute Numeric or symbolic value.
1. An absolute mode: is setting permissions by using octal numbers (Read 4, write 2 and
execute 1). see the table below.
2. Symbolic mode has the form: [who] op permission [permission]

who : u, g, o, a. If who is omitted, the default is a.


op permission: +, -, =.
Permission: r, w, x.
op Description

Setting Access Permissions Numerically


Description
1

execute only

write only

write and execute (1+2)

read only

read and execute (4+1)

read and write (4+2)

read and write and execute (4+2+1)

Examples:
36 | P a g e

To add the permissions

To remove permissions

To assign the permission explicitly

Symbolic mode
who

Description

Users permissions

Group permissions

Others

ALL

Give members of your group permission to read a file.


>chmod g+r file2
It denies write permission to others for file1.
>chmod o-w file1
To gives read and write and execute for owner, and read and execute for group and
others
>chmod 755 newfile

PROCESS RELATED COMMANDS


WHAT IS A PROCESS?

A process is a name given to a program being executed by the operating system.

It may be a system'' program (e.g login, update, csh) or program initiated by the user
(pico, a.out or a user written one).

When you login to the system a process is started to run your shell program init , and
its PID is 1. Any processes that are started from within your shell - such as entering a
command - are the children of this process. A process can have many children, but only
one parent.

You can have multiple processes executing the same program, but each process has its
own copy of the program within its own address space and executes it independently of
the other copies.

Each process created on the system has a unique number (a process ID), known as its
PID, associated with it.

UNIX command ps will list all current processes running on your machine and will
list the pid.

MONITORING PROCESSES
ps [-option]
Without options to list all the processes owned by you and associated
with your terminal.
The information displayed by the ps command varies according to which command option(s)
you use and the type of UNIX that you are using.
These are some of the column headings displayed by the different versions of this command.
PID SZ(size in Kb) TTY(controlling terminal) TIME(used by CPU) COMMAND
Example:
Display information about all your processes.
> ps -u
37 | P a g e

Display information about your processes those are currently running.


> ps
>ps -ef
UID

PID

PPID C

STIME TTY TIME CMD

root

02

0:15:23 ? 0:14 sched

root

20:15:24 ? 0:00 /sbin/init

root

20:15:24 ? 0:00 pageout

root

20:15:24 ? 0:00 fsflush

240

daemon

20:16:37 ? 0:00 /usr/lib/nfs/statd ...

The first three columns are important. The first lists the user the process is running as, the
second lists the ID of the process, and the third lists the ID of the parent of the process. The final
column is a description of the process, usually the name of the binary that was launched.
The presence of a parent PID (PPID) implies that one process is created by another process.
The original process that kicks this off is called init, and it is always given a PID of 1. init is the
first real process to be started by the kernel on bootup. It is the job of init to start up the rest of
the system. init and other processes with a PPID of 0 belong to the kernel.

sleep time
Waits a amount of seconds. time The amount of seconds to wait..

wait [pid] [jobid]


Await process completion.
pid process ID of a command, for which the utility is to wait for the
termination.
Jobid job ID that identifies a background process group to be waited for.
Example:
Sleeps for 10 seconds
>sleep 10
Wait on pid 2017 until termination
> wait 2017

MANAGING JOBS AND PROCESSES


Canceling a foreground process To cancel the process that is currently running enter
the key combination: Ctrl-c. This cancels the current foreground process completely: it
no longer exists.
Suspending a foreground process To suspend a foreground process enter the key
combination: Ctrl-z. This stops the current foreground process. If you are using the
Bourne shell you will then have to kill the process. Other shells provide you with a
facility to restart a process in the foreground or as a background job.
38 | P a g e

PLACING A FOREGROUND PROCESS IN THE BACKGROUND


Run a foreground process as a background job
1. Suspend the foreground process.
2. Enter the bg (background) command to move the process into the background.
This starts a foreground process to sleep for 20 seconds and then display done after 20
seconds. The process is then stopped and the job moved into the background. The state of
this job is then checked by using jobs command.
>(sleep 20; echo done)
^Z
Stopped (user)
> bg
[1] + ( sleep 15; echo done ) &
> jobs
[1] + Running ( sleep 15; echo done )
Running processes as background jobs
To run a process in the background as a job and carry on working add an & (ampersand) at
the end of the command line.
Example:
> (sleep 15; echo done) &
[1] 20980

The shell forks a child process to run the command and displays the job number ([n]) and
the PID (Process ID) number. The shell prompt returns and you can enter further
commands.
Redirect the standard output for a command that is being run in the background to a file.
This prevents the output from the command appearing on your screen and interrupting
your current work. If the command is likely to produce error messages you will need to
redirect standard error. Otherwise all error messages are sent to your screen.
Do not run an interactive command that requires you to type something at the terminal as a
background job. If you do the job will stop and wait for user input. You will then have to kill
its process.

39 | P a g e

MISCELLANEOUS COMMAND
man command
It show a brief manual in a clear text format for most of the commands
available on your Unix OS and provides cross-references to other similar
manuals. Press the [space-bar] if you want to see another page, and type
[q] if you want to quit reading
All the manuals for UNIX commands are split into clearly marked sections:

NAME - command name as it should be typed

SYNOPSIS - syntax for running a command all the possible command line options

DESCRIPTION - textual description of what a command is used for

OPTIONS - full list of command line options with thorough explanations

FILES - files which are used by a command

SEE ALSO other relevant commands you might want to look at

BUGS - known bugs and limitations of a command

AUTHOR - list of command authors, developers and most current maintainers

Example:
Press the [space-bar] if you want to see another page, and type [q] if you want to quit
reading
>man cd

history
It displays a numbered list of commands in the order in which you have
used them.
command

Description

!!

Run the previous command

!n

Run command number n

!string

Run most recent command starting with characters in string

!?string

Run most recent command containing characters that match string

Repeat the last command


>!!
Display all history of command
>history
1 ls
2 man ls
3 mkdir t6
4 pwd

40 | P a g e

Run the last command start with mkdir


>!mkdir
command

Description

who

Displays who is currently logged in the system

finger [userid]

It dispays information about a specified userid

echo <message>

It prints message to stdout (your standard output file)

tty

It shows special file that represents your terminal.

Id

It displays the userid and groupid

Clear

Clears the terminal screen

Hostname

Displays the name of your Unix system

cal
Displays the calendar of current month and year
cal <year>
Displays the calendar of the specified year
cal <month> <year> Displays the calendar of the specified months number and year
wc c <filename>
wc w <filename>
wc l <filename>

Counts number of characters in the specified file name


Counts number of words in the specified file name
Counts number of lines in the specified file name

EXCERSICES
1. Write a command to store a list of your files names in the home directory and the
subdirectories in a text file called myfilesList.txt. (Hint: use redirect standard
output).
2. Create a file named as lab2.txt by using vi editor. Write at least 5 sentences in this file.
3. Write a command to count number of characters, words and lines in lab2.txt , you have
created in problem#2.
4. Write a command to count number of words in the first line of lab2.txt, you have created
in problem#2. (Hint: use pipe).
5. Write a command to count number of words in the last line of lab2.txt. , you have created
in problem#2. (Hint: use pipe).

41 | P a g e

LABORATORY 5, 6: SHELL PROGRAMMING


Objective
1. User defined variables
1. Reading Values into User-defined Variables (Reading user input)
2. Command Substitution
3. Computation on Shell Variables
2. Pre-defined shell variables
1. Passing arguments to the shell
3. Conditional Execution Operators
4. Conditional statements
1. The if statement
2. The case statement
5. Flow of control statements
1. The for statement
2. The while and until statements
3. The break and continue statements

OVERVIEW OF SHELL
Shell
The shell acts as an interface between the user and the kernel. It is a command line interpreter.
It interprets the commands the user types in and arranges for them to be carried out. It takes
each command and passes it to the operating system kernel to be acted upon. It then displays
the results of this operation on your screen. There are several different shells available for Unix;
Three most widely used shells in UNIX are Bourne shell, C shell, and Korn shell.
Shell Scripts and Uses
A shell script or a shell program is a series of commands put in a file and executed by the
Shell. Bourne Again shell will be used to create shell scripts.
Since the user cannot interact with the kernel directly, Shell Programming skills are a must to be
able to exploit the power of UNIX to the fullest extent. A shell script can be used for variety of
tasks, such as:
Customizing the user work environment. For Example user can write a shell script to see
the current date, a welcome message, and the list of users who have logged on, every
time user login.
Automating your daily tasks. For example, to back up all the programs at the end of the
day.
Automating repetitive tasks.
Executing important system procedures, like shutting down the system, formatting a
disk, creating a file system etc.
Performing some operations on many files.

42 | P a g e

Shell Variables
The variables in the Bourne Shell are classified as:
User defined variables: defined by the user for his use (e.g age=32).
Environmental variables: defined by shell for its own operations (PATH, HOME, TERM,
LOGNAME, PS1, SHELL e.t.c).
Predefined variables: reserved variables used by the shell and UNIX commands for
specifying the exit status of command, arguments to the shell scripts, the formal parameters
e.t.c.

USER DEFINED VARIABLES


Examples:
#variable name is assigned a value Ali
>name=Ali
#Ali will be displayed
>echo $name
Ali
#See output of this in your computer
>echo Hello $name ! , Welcome to $HOME

READING VALUES INTO USER-DEFINED VARIABLES (READING USER INPUT):


read
In shell script read command, used to read standard input.

Example:
It prompts the user for input, assigns this to the variable name and then displays the value
of this variable to standard output.
>cat lab5_0
>echo "Please enter your name:"
>read name
>echo "Welcome to CFW, ISC $name"
Running the file lab4_0?
>chmod u+x lab5_0
> ./lab5_0
Please enter your name:
Dr. Kalim Qureshi
Welcome to CFW, ISC Dr. Kalim Qureshi.

43 | P a g e

If there is more than one word in the input, each word can be assigned to a different variable.
Any words left over are assigned to the last named variable.
Example:
echo "Please enter your surname\n"
echo "followed by your first name: \c"
read name1 name2
echo "Welcome to ICS Dept, KFUPM , $name2 $name1"
Example:
This shell script will accept the name and age from the user and display the same on the
terminal screen.
>cat lab5_1
echo Enter your name : \c
read name
echo Enter your age : \c
read age
echo Hello $name , nice to meet you. You are $age years old
Example:
This script takes two file names and copies the first file into the second one
>cat lab5_2
echo Please Enter source file name :\c
read source
echo Enter the target file name :\c
read target
cp $source $target
echo file $source is copied into the $target

COMMAND SUBSTITUTION:
Format for command substitution is:
var = `command` (where is back quote)
Example:
It will display the output of date command
>echo date
Check the output of this script
>echo there are who | wc l users working on the system

44 | P a g e

COMPUTATION ON SHELL VARIABLES


Various forms for performing computations on shell variables using expr command are:

expr val_1 op val_2

# (Where op is operator)

expr $val_1 op $val_2


val_3 = `expr $val_1 op $val_2`
Examples:
Gives 12
>expr 5 + 7
Gives 3
>expr 6 3
Gives 12
>expr 3 \* 4
Gives 8
>expr 24 / 3
>sum=expr 5 + 6
Gives 11
>echo $sum
>a=12
>b=90
Will display sum is 12 + 90
>echo sum is $a + $b
Gives sum is 102
>echo sum is `expr $a + $b`

PRE-DEFINED SHELL VARIABLES


There are some variables which are set internally by the shell and which are available to the
user. These variables are called Pre-defined shell variables. The table below list such variables:
Name
$1 - $9
$0
$#
$?
$$
$!
$45 | P a g e

Description
These variables are the positional parameters
The name of the command currently being executed
The number of positional arguments given to this invocation of the shell, Parameter
Count.
The exit status of the last command executed is given as a decimal string. When a
command completes successfully, it returns the exit status of 0 (zero), otherwise it
returns a non-zero exit status.
The process number of this shell - useful for including in filenames, to make them
unique (PID of Current Shell).
The process id of the last command run in the background (It holds PID of last
background process).
The current options supplied to this invocation of the shell.

$*
$@@

A string containing all the arguments to the shell, starting at $1, i.e. All Parameters.
Same as above, except when quoted.

Notes:
$* and $@@ when unquoted are identical and expand into the arguments.
"$*" is a single word, comprising all the arguments to the shell, joined together with spaces. For
example '1 2' 3 becomes "1 2 3".
"$@@" is identical to the arguments received by the shell, the resulting list of words completely
match what was given to the shell. For example '1 2' 3 becomes "1 2" "3"

PASSING ARGUMENTS TO THE SHELL


Shell scripts can act like standard UNIX commands and take arguments from the command line.
Arguments are passed from the command line into a shell program using the positional
parameters $1 through to $9. Each parameter corresponds to the position of the argument on
the command line.
The positional parameter $0 refers to the command name or name of the executable file
containing the shell script. Only nine command line arguments can be accessed, but you can
access more than nine using the shift command. All the positional parameters can be referred
to using the special parameter $*. This is useful when passing filenames as arguments.
Example
This is shell script, which will accept 5 numbers as parameters and display their sum. Also
display the contents of the different variables in the script.
>cat lab5_3
echo the parameters passed are : $1, $2, $3, $4, $5
echo the name of the script is : $0
echo the number of parameters passed are : $#
sum=`expr $1 + $2 + $3 + $4 + $5`
echo The sum is : $sum

SHIFT COMMAND
If more than 9 parameters are passed to a script, it is not possible to refer to the parameters
beyond the 9th one. This is because shell accepts a single digit following the dollar sign as a
positional parameter definition.
The shift command is used to shift the parameters one position to the left. On the execution of
shift command the first parameter is overwritten by the second, the second by third and so on.
This implies that the contents of the first parameter are lost once the shift command is executed.

46 | P a g e

Example
Write a script, which will accept different numbers and finds their sum. The number of
parameters can vary.
>cat lab5_4
sum=0
while [ $# -gt 0 ]
do
sum=expr $sum + $1
shift
done
echo sum is $sum
Here, the parameter $1 is added to the variable sum always. After shift, the value of $1 will be
lost and the value of $2 becomes the value of $1 and so on.
The above script can also be written without using the shift command as:
for i in $*
do
sum=expr $sum + $i
done

Usually only nine command line arguments can be accessed using positional parameters. The
shift command gives access to command line arguments greater than nine by shifting each of the
arguments. The second argument ($2) becomes the first ($1), the third ($3) becomes the
second ($2) and so on. This gives you access to the tenth command line argument by making it
the ninth. The first argument is no longer available.
Successive shift commands make additional arguments available. Note that there is no "unshift"
command to bring back arguments that are no longer available!.
Example
To successively shift the argument that is represented by each positional parameter:
> cat shift_demo
echo "arg1=$1 arg2=$2 arg3=$3"
shift
echo "arg1=$1 arg2=$2 arg3=$3"
shift
echo "arg1=$1 arg2=$2 arg3=$3"
shift
echo "arg1=$1 arg2=$2 arg3=$3"

47 | P a g e

Runing example above


>./shift_demo one two three four five six seven
arg1=one arg2=two arg3=three
arg1=two arg2=three arg3=four
arg1=three arg2=four arg3=five
arg1=four arg2=five arg3=six
arg1=five arg2=six arg3=seven

CONDITIONAL EXECUTION OPERATORS


Conditional execution of commands are useful when we want to execute the command based on
the status of the previous command, i .e whether the previous command has succeeded or
failed. This is examined by the exit status of each command. For success of any command exit
status will be 0 (zero) and 1 (One) if unsuccessful.

&& ( e.g command1 && command2)


The operator && executes the command(s) following it (e.g command2),
if and only if the preceding command (e.g command1) was successfully
compiled.

||

(Double pipe)

The || operator executes the command(s) following it e.g command2), if


the preceding command failed (e.g command1).

Examples
The above command will remove mydoc.doc if it exits, otherwise, it will do nothing.
%ls | grep mydoc.doc && rm mydoc.doc
The above command will display the contents of mydoc.doc if it exists otherwise file not
found displayed.
%cat mydoc.doc || echo file not found

In case, more than one command is to be executed or more than one condition need to be
checked simultaneously, then this type of conditional execution is not helpful. In such cases the
if-then-elif-else-fi statement is used.

48 | P a g e

CONDITIONAL STATEMENTS
THE IF STATEMENT
The if statement uses the exit status of the given command and conditionally executes the
statements following.
The general syntax is:

if test
then
commands

(if condition is true)

else
commands

(if condition is false)

fi
then, else and fi are shell reserved words and as such are only recognized after a new line or ;
(semicolon). Make sure that you end each if construct with a fi statement.

NESTED IF STATEMENT

if (-----)
then ...
else if ...
...
fi
fi
The elif statement can be used as shorthand for an else if statement.
Example:

if (------)
then ...
elif ...
...
fi

TEST COMMAND
The Unix system provides test command, which investigates the exit status of the previous
command, and translates the result in the form of success or failure, i.e either a 0 or 1.

49 | P a g e

The test command does not produce any output, but its exit status can be passed to the if
statement to check whether the test failed or succeeded.
All commands return the exit status to a pre-defined Shell Variable ?. Which can be displayed
using the echo command. Every Unix command returns a value on exit, which the shell can
interrogate. This value is held in the read-only shell variable $?. A value of 0 (zero) signifies
success; anything other than 0 (zero) signifies failure.
echo $?
If output of this is 0 (Zero) it means the previous command was successful and if output is 1
(One) it means previous command failed.
The test command has specific operators to operate on files, numeric values and strings,
which are explained below:
1. Operators on Numeric Variables used with test command:

-eq

: equal to

-ne

: not equals to

-gt

: grater than

-lt

: less than

-ge

: greater than or equal to

-le

: less than equal to

Example:
> a=12; b=23
> test $a eq $b
Gives 1 (one) as output.(Indicates exit status false)
>echo $?

2. Operators on String Variables used with test command:

: equality of strings

!=

: not equal

-z
: zero length string (i.e string containing zero character i.e null
string).
-n

50 | P a g e

: String length is non zero.

Examples:
$> name=Ahmad
Will return the exit status 1 as the string name is not null.
>test z $name
Will return 0 as the string is not null.
>test n $name
Will return 0 as the variable has not been defined.
>test z $address
Will return 1 as the value of name is not equal to Ali
>test $name = Ali

3. Operators on files used with test command:

-f :

the file exists.

-s :

the file exists and the file size is non zero.

-d :

directory exists.

-r :

file exits and has read permission.

-w :

file exists and has write permission.

-x :

file exists and has execute permission.

Examples:
Will check for the file mydoc.doc , if exists, returns 0 else 1.
>test f mydoc.doc
Will check for read permission for mydoc.doc
>test r mydoc.doc
Will check for the existence of the users home directory.
>test d $HOME

4. Logical Operators used with test command:

Combining more than one condition is done through the logical AND, OR
and NOT operators.

51 | P a g e

-a

: logical AND

-o

: logical OR

: logical NOT

Example:
Will check both the read and write permission for the file mydoc.doc and returns either 0
or 1, Depending on result.
> test r mydoc.doc a w mydoc.doc
Example
To carry out a conditional action:
if who | grep -s rafiq > /dev/null
then
echo rafiq logged in 357 Lab
else
echo rafiq available in 357 Lab
fi
This lists who is currently logged on to the system and pipes the output through grep to search
for the username rafiq. The -s option causes grep to work silently and any error messages are
directed to the file /dev/null instead of the standard output.
If the command is successful i.e. the username rafiq found in the list of users currently logged in
then the message rafiq logged in 357 Lab is displayed, otherwise the second message is
displayed.

THE CASE STATEMENT


The case statement case is a flow control construct that provides for multi-way branching based
on patterns.
Program flow is controlled on the basis of the WORD given. This WORD is compared with each
PATTERN in order until a match is found, at which point the associated COMMAND (S) are
executed. When all the commands are executed control is passed to the first statement after the
esac. Each list of commands must end with a double semi-colon (;;).

case WORD in
PATTERN1 )

COMMAND(S ) ;;

PATTERN2 )

COMMAND(S ) ;;

--------------------------------------------PATTERNN )

*) default
esac

52 | P a g e

COMMAND(S)

command ;;

;;

A command can be associated with more than one pattern. Patterns can be separated from each
other by a | symbol. For example:

case WORD in
PATTERN1|PATTERN2 ) COMMAND

...

;;

Patterns are checked for a match in the order in which they appear. A command is always
carried out after the first instance of a pattern. The * character can be used to specify a default
pattern as the * character is the shell wildcard character.
Examples:
> cat Lab4_5
# Display a menu of options and depending upon the user's choice,
#Execute associated command
#Display the options to the users
clear
echo "1. Date and time"
echo
echo "2. Directory listing"
echo
echo "3. Users information "
echo
echo "4. Current Directory"
echo
echo "Enter choice (1,2,3 or 4 ) :\n"
read choice
case $choice in
1)

date;;

2)

ls -l;;

3)

who ;;

4)
*)

pwd ;;
echo wrong choice;;

esac

53 | P a g e

FLOW OF CONTROL STATEMENTS


The Bourne shell provides several flows of control statements. Select an item for further
information.

THE FOR STATEMENT


The for loop notation has the general form:
for var in list-of-words
do
commands
done
COMMANDS is a sequence of one or more commands separated by a new

line or ; (semicolon). The reserved words do and done must be preceded


by a new line or ; (semicolon). Small loops can be written on a single line.
For example:
for VAR in LIST;
do COMMANDS ;
done
Examples
To take each argument in turn and see if that person is logged onto the system or not?.
>cat snooper
# See if a number of people are logged in
for i in $*
do
if who | grep -s $i > /dev/null
then
echo $i is logged in
else
echo $i not available
fi
done
For each username given as an argument a if statement is used to test if that person is logged on
and an appropriate message is then displayed.

54 | P a g e

THE WHILE AND UNTIL STATEMENTS


The while statement has the general form:
while command-list1
do
command-list2
done

The commands in COMMAND-LIST1 are executed; and if the exit status of the last command in
that list is 0 (zero), the commands in COMMAND-LIST2 are executed.
The sequence is repeated as long as the exit status of COMMAND-LIST1 is 0 (zero).

The until statement has the general form:


until command-list1
do
command-list2
done

This is identical in function to the while command, except that the loop is executed as long as the
exit status of COMMAND-LIST1 is non-zero. The exit status of a while/until command is the exit
status of the last command executed in COMMAND-LIST2. If no such command list is executed, a
while/until has an exit status of 0 (zero).

THE BREAK AND CONTINUE STATEMENTS


It is often necessary to handle exception conditions within loops. The statements break and
continue are used for this.

The break command terminates the execution of the innermost enclosing


loop, causing execution to resume after the nearest done statement. To
exit from n levels, use the command:
break N
This will cause execution to resume after the done N levels up.

The continue command causes execution to resume at the while, until or for statement which
begins the loop containing the continue command. You can also specify an argument N|FR to
continue which will cause execution to continue at the N|FRth enclosing loop up.
Example s
To prompt for commands to run
while echo "Please enter command"
55 | P a g e

read response
do
case "$response" in
'done') break

# no more commands

;;
"")

continue

# null command

;;
*)

eval $response # do the command


;;

esac
done

This prompts the user to enter a command. While they enter a command or null string the script
continues to run. To stop the command the user enters done at the prompt.
Examples:
To show use of case statement
>cat Lab5_6
echo What kind of tree bears acorns\ ?
read responce
case $responce in
[Oo][Aa][Kk]) echo $responce is correct ;;
*) echo Sorry, response is wrong
esac
To show use of while statement
>cat Lab5_7
clear
echo What is the Capital of Saudi Arabia \?
read answer
while test $answer != Riyadh
do
echo No, Wrong please try again.
read answer
done
echo This is correct.

56 | P a g e

Example to show use of until statement


Accept the login name from the user
>cat Lab5_8
clear
echo "Please Enter the user login name: \n"
read login_name
until who | grep $login_name
do
sleep 30
done
echo The user $login_name has logged in
#To show use of if statement
# Read three numbers and display largest
>cat Lab5_9
clear
echo "Enter the first number :\n"
read num1
echo "Enter the second number :\n"
read num2
echo "Enter the third number :\n"
read num3
if test $num1 -gt $num2
then
if test $num1 -gt $num3
then
echo $num1 is the largest
else
echo $num3 is the largest
fi
else
if test $num2 -gt $num3
then
echo $num2 is largest
else
echo $num3 is the largest
fi
fi

57 | P a g e

EXCERSICES
1. Run all the programs given above and observe the output of each program one by one.
2. Modify above shell script #File name lab5_2 to check the presence of target file before
copying.
Input and output for this program must be in the following format:
>./lab5_solution2
Please Enter Source filename: m1
Enter target file name: m2
Dear! Target file m2 already present
>./lab5_solution2
Please Enter Source filename: m2
Enter target file name: m21
m2 file copied into m21 file
3. Write a shell script that takes a command line argument and reports on whether it is a
directory, a file, or something else.
Input and output in this program must be in the following format:
>./ lab5_solution3 Math 376_042
I don't Know what is Math 376_042 is
>lab5_solution3 dir
dir is a directory
>lab5_solution3 t1
t1 is a ordinary file
4. Write a shell script to find the number of files in a directory.
Inputs and outputs in this program must be in following format:
>lab5_solution4
Enter the directory path: /a/general/export/homedir/facics/rafiq/Math 376_042
There are 33 numbers of files in the directory

58 | P a g e

LABORATORY7: UNIX AND ADVANCE TOPICS IN C


PROGRAMMING
Objectives

Be familiar with syntax of Unix C-Program.


Gain knowledge of how to create, compile, and execute a C program under Unix System.
Find out how to write C-Program using command line arguments.
Running UNIX Commands from C.

A SIMPLE C PROGRAM
Example#1:
Assume we have the following program stored in a file called file.c.
>vi file.c
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char* argv[])
{
printf (Hello World!\n);
exit (0);
}

#include <stdio.h> is a directive to the c preprocessor to include the file stdio.h that will
tell the program how to input and output data.

#include <stdlib.h> is to be able to use the exit function that tells us if the program ran
successfully or not.

COMPILE AND EXECUTE A C PROGRAM UNDER UNIX SYSTEM


gcc [-o FileName] fileName.c
To compile C program

The gcc is assumed to be your GNU c compiler. Otherwise you would compile the
program using the standard cc compiler.

The -o option indicates that the compile file should be stored in a file called FileName
instead of the default a.out.

Cont Example#1:
Compile the program in example #1 without using o option
> gcc file.c
Run the program
59 | P a g e

> ./a.out
Or you can compile the program in example #1 using o option
gcc -o file file.c
Run the program
> ./file

UNIX LIBRARY FUNCTIONS


The UNIX system provides a large number of C functions as libraries. Some of these implement
frequently used operations, while others are very specialized in their application. Do Not
Reinvent Wheels: It is wise for programmers to check whether a library function is available to
perform a task before writing their own version. This will reduce program development time.
The library functions have been tested, so they are more likely to be correct than any function
which the programmer might write. This will save time when debugging the program.

Finding Information about Library Functions


The UNIX manual has an entry for all available functions. Function documentation is stored in
section 3 of the manual, and there are many other useful system calls in section 2. If you already
know the name of the function you want, you can read the page by typing (to find about sqrt):
man 3 sqrt
If you dont know the name of the function, a full list is included in the introductory page for
section 3 of the manual. To read this, type
man 3 intro
There are approximately 700 functions described here. This number tends to increase with each
upgrade of the system.
Example#2
The file sqrt1.c contains c code prints the square roots of the numbers from 0 to 25.
Notice that we converted the integer i to a double using the typcast operation.
#include <stdio.h>
#include <math.h>
int main()
{
int i;
double number;
for (i = 0; i <= 25; i++) {
number = sqrt((double) i);
printf(The square root of %d is %f\n,i,number);
}
}
60 | P a g e

To compile program that used c library: gcc -o sqrt1 sqrt1.c -lm


To execute the program: ./sqrt1
Example#3:
This example generates random numbers that range from a minimum value of 3 and a
maximum value of 12. Notice that we used the modulo operator % to ensure maximum
value of our random numbers is less than 10.
#include <stdio.h>
#include <stdlib.h>
int main ()
{
int i, number, min value;
min value = 3;
for (i = 0; i < 15; i++)
{
number = min value + (rand() % 10);
printf(Random number is %d \);
}
}

C FUNCTIONS
C uses function to package blocks of code. A function has a name, a list of arguments and the
block of code it executes.
Example #4:
The following example shows a function that converts speed from miles/hour to
kilometers/hour.
#include <stdio.h>
float mphtokph(float speed)
{
return(speed*1.60934);
}
int main()
{
float mph, kph;
printf("Enter speed (miles/hour): ");
scanf("%f", &mph);
kph = mphtokph(mph);

61 | P a g e

printf("\n speed of %3.1f miles/hour equals %3.1f kilometers/hour


\n\n",mph, kph);
}

COMMAND LINE ARGUMENTS IN C


The arguments for main( int argc, char *argv[] ) are argc(argument count) and argv(argument
vector). The argument argc is an integer that contains the number of arguments being passed to main ;
argv is an array of strings. Each string is an argument. The computer is able to count the number of
arguments and assign the value to argc. The array argv[1] contains the first argument, argv[2]
contains the second argument and so on . The programs name is stored in argv[0].
Example#5:
For a program named prog1 which is invoked with the command line: The value of argc is
4, the value of argv[0] is "prog1", the value of argv[1] is "add", the value of argv[2] is "12",
and the value of argv[3] is "5".
>prog1 add 12 5
Example#6:
Try to run the program with and without argument and see the result.
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
int i;
for (i = 0; i < argc ; i++) // scan al entries of argv[i]
{
/* print all the arguments */
printf(arg %d: %s \n, i, argv[i]);
}
exit (0);
}
Example#7:
Note: atoi( ) function is used to convert string into integer.
#include<stdio.h>
#include<stdlib.h>
main(int argc, char *argv[])
{
int sum;
if(argc<=3)
{
62 | P a g e

printf("You must input three numbers as command line inputs.\n");


exit(0);
}
sum=atoi(argv[1])+atoi(argv[2])+atoi(argv[3]);
printf("The sum of three values is = %d\n",sum);
}

RUNNING UNIX COMMANDS FROM C


We can run commands from a C program just as if they were from the UNIX command line by
using the system( ) function.
int system ( char *string ) where string can be the name of a UNIX utility, an executable shell
script or a user program. System returns the exit status of the shell.
System is prototyped in <stdlib.h>
system is a call that is made up of 3 other system calls: execl( ), wait( ) and fork( ) (which are
prototyped in <unistd>)
Example#8:
Calling a UNIX command
main( )
{ printf(``Files in Directory are:\n'');
system(``ls -l'');
}
Example#9:
Calling a shell script
main( )
{ printf(``Files in Directory are:\n'');
system(./sh'');
}

63 | P a g e

LABORATORY8: MAJOR FILE STRUCTURE RELATED SYSTEM


CALLS
Objective
1. Understand system calls.
2. Identify the use of system calls.
3. Learn Major File Structure Related System Calls(open, create, close, read, write, and lseek).

WHAT IS A SYSTEM CALL?


A system call is 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.

USE OF SYSTEM CALLS


UNIX system calls are used to:
1.

manage the file system,

2. control processes,
3. and to provide interprocess communication.
Major System Calls:
1. The UNIX system interface consists of about 80 system calls (as UNIX evolves
this number will increase). The table below lists about 40 of the most important
system call.
2. The file structure related system calls in UNIX 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.

64 | P a g e

File Structure Related Calls


SPECIFIC CLASS
Creating a Channel

Input/Output

SYSTEM
CALL
creat( )

Process Related Calls


SPECIFIC CLASS

SYSTEM CALL

Process Creation and


termination

exec( )

open( )

fork( )

close( )

wait( )

read( )

exit( )

write( )

Process Owner and Group

getuid( )

Random Access

lseek( )

getgid( )

Channel Duplication

dup( )

getegid( )

Aliasing and Removing Files

link( )

Aliasing and Removing Files

unlink( )

File Status

stat( )

Access Control

Process Identity

getpid( )
getppid( )

Process Control

signal( )

fstat( )

kill( )

access( )

alarm( )

chmod( )

Change Working Directory

chdir( )

chown( )

Device Control

umask( )

Process Related Calls

ioctl( )

SPECIFIC CLASS

SYSTEM CALL

Pipelines

pipe( )

Messages

msgget( )
msgsnd( )
msgrcv( )
msgctl( )

Semaphores

semget( )
semop( )

Shared Memory

shmget( )
shmat( )
shmdt( )

65 | P a g e

System call 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.
A channel is a connection between a process and a file that appears to the process as an
unformatted stream of bytes.
File descriptors 0, 1, and 2 refer to standard input, standard output, and standard error
files respectively.
File descriptor 0 is a channel to your terminal's keyboard and file descriptors 1 and 2
are channels to your terminal's

CREAT( ) SYSTEM CALL


int creat(char *file_name, int mode)
It returns either a non-negative file descriptor or 1 on error.
creat( ), creates an empty file with the specified mode permissions, if the file named by
file_name does not exist. However, if the file does exist, its contents are discarded and the
mode value is ignored. The permissions of the existing file are retained.
The mode is usually specified as an octal number such as 0666 that would mean read/write
permission for owner, group, and others or the mode may also be entered using manifest
constants defined in the "/usr/include/sys/stat.h" file. e.g. S_IREAD,S_IWRITE
Header files needed for this system call in which the actual prototype appears, & in which
useful constants are defined are:
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
All input and output operations start by opening a file using either the "creat( )" or "open( )"
system calls. These calls return a file descriptor that identifies the I/O channel. Recall that
file descriptors 0, 1, and 2 refer to standard input, standard output, and standard error files
respectively, and that file descriptor 0 is a channel to your terminal's keyboard and file
descriptors 1 and 2 are channels to your terminal's display screen.
Example#1:
Create a file newfile with read & write permission to owner and read only for the group
and others.
fd = creat(/tmp/newfile, 0644);

66 | P a g e

Example#2:
After running the example check whether, the file datafile.dat exist in your current folder
or not.
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>

/* defines types used by 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 creating datafile.dat\n");
else
{
printf("datafile.dat created for read/write access\n");
printf("datafile.dat is currently empty\n");
}
close(fd);
exit (0); /*exit() terminates the calling process , exit(0) for successful &
exit(1) for error, exit() is defined in #include<stdlib.h> */
}

int open(char *file_name, int option_flags, [int mode])


It returns either a non-negative file descriptor or 1 on error.
open( ), It opens a file for reading or writing, or creates an empty file.

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. It is only
used with the O_CREAT option_flag and it is concerned with the security
permissions.

Header files needed for this system call in which the actual prototype appears, & in
which useful constants are defined are:

67 | P a g e

#include<sys/types.h>

#include<sys/stat.h>

#include<fcntl.h>

The allowable option flags as defined in "/usr/include/fcntl.h" or #include<fcntl.h> are:


Option flag

Description

#define O_RDONLY 0

Open the file for reading only

#define O_WRONLY 1

Open the file for writing only

#define O_RDWR 2

Open the file for both reading and writing

#define O_APPEND 010

append (writes guaranteed at the end)

#define O_CREAT 00400

If file doesnt exist , create the file, set the owner ID to the processs
effective UID, and set the group id to the group id of the directory in
which the file is created.

#define O_TRUNC 01000

If file exists, it is truncated to length zero

#define O_EXCL 02000

Exclusive open(i. e If O_CREAT is set and the file exists, then open() fails.

Multiple values are combined using the | operator (i.e. bitwise OR). Note: some
combinations are mutually exclusive such as: O_RDONLY | O_WRONLY and will cause open(
) to fail. If the O_CREAT flag is used, then a mode argument is required. The mode argument
may be specified in the same manner as in the creat( ) system call.
Example#3:
This causes the file data, in the current working directory, to be opened as read only for the
use by the program.
fd = open(data, O_RDONLY);
Example#4:
The open call can also be used to create a file from scratch, as follows:
fd = open (/tmp/newfile, O_WRONLY | O_CREAT, 0644);
Example#5:
means, if file lock does not exist, then create it with permission 0644. If it does exist, then
fail open call, returning 1 in fd.
fd = open(lock, O_WRONLY | O_CREAT | O_EXCL, 0644);
Example#6:
O_TRUNC when used with O_CREAT it will force a file to be truncated to zero bytes if it
exists and its access permissions allow.
fd = open(file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
Example#7:
#include<stdlib.h>
68 | P a g e

#include<fcntl.h>
#define PERMS 0644 /* Permission for open with O_CREAT */
char *filename = "newfile";
main()
{
int fd;
if((fd=open(filename, O_RDWR | O_CREAT, PERMS)) == -1)
{
printf("Couldn't create %s\n",filename);
exit(1);

/*error, so exit */

}
printf(The file is opened and ready for read and write operation)
/* rest of program follows */
exit(0); /*normal successful exit */
}

CLOSE( ) SYSTEM CALL


int close(int file_descriptor)
The close system calls returns 0 if successful, -1 on error (which can
happen if the integer argument is not a valid file descriptor).
close( ) system call to close a previously opened file. It is defined in header file
#include<unistd.h>. file_descriptor identifies a currently open file. close( ) fails if
file_descriptor does not identify a currently open file.

READ() WRITE()SYSTEM CALLS


int read( int file_descriptor, char *buffer_pointer, unsigned transfer_size)
int write(int file_descriptor, char *buffer_pointer, unsigned transfer_size)
return the number of bytes transferred if successful & -1 if error

file_descriptor is a file descriptor which has been obtained from a previous call to either
open or creat,

buffer_pointer points to the area in memory (or is a pointer to an array or structure into
which data will be copied, in many cases it is simply name of array itself ) 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 (or number of bytes) . 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

69 | P a g e

"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.
Example#8:
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 512
int main()
{ char buffer[BUFSIZE];
int fd;
int nread;
long total = 0;
if(( fd = open("myfile", O_RDONLY)) == -1) /* open "myfile" read only */
{ printf("Error in opening myfile\n");
exit(1);
}
while( (nread = read(fd,buffer, BUFSIZE)) >0) /* loops until EOL, shown by
return value of 0 */
{ total += nread;

/* increment total */

}
printf("Total chars in my file : %ld\n",total);
exit(0);
}

LSEEK() SYSTEM CALL


long lseek(int file_descriptor, long offset, int whence)
returns a long integer that defines the new file pointer value measured in
bytes from the beginning of the file. If unsuccessful (it returns 1), the
file position does not change.
whence

new position

0 (SEEK_SET)

offset bytes into the file (The offset is measured from the beginning of the file;
usual actual integer value=0)

1 (SEEK_CUR)

current position in the file plus offset (The offset is measured from the
current position of the file pointer; usual value =1 )

2 (SEEK_END)

current end-of-file position plus offset (The offset is measured from the end
of the file; usual value =2)

70 | P a g e

The UNIX system file system treats an ordinary file as a sequence of bytes. No internal
structure is imposed on a file by the operating system. Generally, a file is read or written
sequentially -- that is, from beginning to the end of the file. Sometimes sequential reading
and writing is not appropriate. It may be inefficient, for instance, to read an entire file just
to move to the end of the file to add characters. Fortunately, 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.
lseek() enables random access into
a file. To use it we need header files
#include<sys/types.h> and #include<unistd.h> .
Example#9:
a program fragment gives a position 16 bytes before the end of the file. From this example
it is clear that offset can be negative i.e it is possible to move backwards from the starting
point indicated by whence.
newpos = lseek(fd, -16, SEEK_END)
Example#10:
a program fragment that will append to the end of an existing file by opening the file,
moving to the end with lseek, and starting to write.
fd = open(filename, O_RDWR);
lseek(fd, 0, SEEK_END);
write(fd, outbuf, OBSIZE);
Example#11:
#include <fcntl.h>

/* defines options flags */

#include <sys/types.h>

/* defines types used by sys/stat.h */

#include <sys/stat.h>

/* defines S_IREAD & S_IWRITE */

static char message[] = "Hello, world";


int main( )
{
int fd;
char buffer[80];
/* open datafile.dat for read/write access (O_RDWR)
create datafile.dat if it does not exist (O_CREAT)
return error if datafile already exists (O_EXCL)
permit read/write access to file (S_IWRITE | S_IREAD)
*/
fd = open("datafile.dat",O_RDWR | O_CREAT | O_EXCL, S_IREAD | S_IWRITE);
if (fd != -1)
71 | P a g e

{
printf("datafile.dat opened for read/write access\n");
write(fd, message, sizeof(message));
lseek(fd, 0, 0);

/* go back to the beginning of the file */

if (read(fd, buffer, sizeof(message)) == sizeof(message))


printf("\"%s\" was written to datafile.dat\n", buffer);
else
printf("*** error reading datafile.dat ***\n");
close (fd);
}
else
printf("*** datafile.dat already exists ***\n");
exit (0);
}

EXCERSICES
1. Update the code in example#8 to get the file name from the command line argument.

72 | P a g e

LABORATORY9, 10: PROCESS CREATION AND EXECUTION


Objectives:
This lab describes how a program can create, terminate, and control child processes. There are
three distinct operations involved:
1. creating a new child process,
2. causing the new process to execute a program, and
3. coordinating the completion of the child process with the original program.

int fork (void)


The fork function creates a new process.
It returns a positive integer in the parent process that representing a
child process ID or 0 in the child process. If process creation failed, fork
returns a value of -1 in the parent process and no child is created.
The Unix system call for process creation is called fork(). Header file required for fork() system
call is unistd.h. The fork system call creates a child process that is a clone of the parent.

Child has a (virtual) copy of the parents virtual memory.

Child is running the same program as the parent.

Child inherits open file descriptors from the parent. (Parent and child file
descriptors point to a common entry in the system open file table.) Subsequently
changing attributes of the file descriptors in the parent process won't affect the
file descriptors in the child, and vice versa. However, both processes share the
file position associated with each descriptor.

The child process has its own unique process ID.

The child process may execute a different program in its context with a separate exec()
system call.

int getpid (void)


The getpid function returns the process ID of the current process.
int getppid (void)
The getppid function returns the process ID of the parent of the current
process.
Example#1:
>vi frk1.c
#include <stdio.h>
#include <unistd.h> /* contains fork prototype */
int main(void)
{
73 | P a g e

printf("Hello World!\n");
fork( );
printf("I am after forking\n");
printf("\tI am process %d.\n", getpid( ));
}
Sample output after running the program
>gcc frk1.c
>./a.out
Hello World!
I am after forking
I am process 23848.
I am after forking
I am process 23847.

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 I am a process 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.

A process can execute as many forks as desired. However, be wary of infinite loops of
forks (there is a maximum number of processes allowed for a single user).

Example#2:
>cat frk2.c
#include <unistd.h>
#include <stdio.h>
int main (void) {
pid_t p; /* fork returns type pid_t */
p = fork();
printf("fork returned %d\n", p);
}
Output after running the program
> gcc frk2.c -o frk2
> ./frk2

74 | P a g e

fork returned 0

fork returned 698


Example#3:
#include <stdio.h>
#include <unistd.h> /* contains fork prototype */
int main(void)
{
int pid;
printf("Hello World!\n");
printf("I am the parent process and pid is : %d .\n",getpid());
printf("Here i am before use of forking\n");
pid = fork( );
printf("Here I am just after forking\n");
if (pid == 0)
printf("I am the child process and pid is :%d.\n",getpid());
else
printf("I am the parent process and pid is: %d .\n",getpid());
}
Sample output after running the program
>gcc frk2.c
>./a.out
Hello World!
I am the parent process and pid is: 23951.
Here i am before use of forking
Here I am just after forking
I am the child process and pid is: 23952.
Here I am just after forking
I am the parent process and pid is: 23951.
Example#4:
#include <stdio.h>
#include <sys/wait.h> /* contains prototype for wait */
int main(void)
{
int pid;
int status;
printf("Hello World!\n");
75 | P a g e

pid = fork( );
if (pid == -1) /* check for error in fork */
{

perror("bad fork");
exit(1);

}
if (pid == 0)
printf(" I am the child process.\n");
else
{

wait(&status); /* parent waits for child to finish */


printf("I am the parent process.\n");

}
}
Sample output after running the program
>gcc frk2.c
>./a.out
Hello World!
I am the child process.
I am the parent process.

THE DEATH OF A PARENT OR CHILD PROCESS


PARENT PROCESS DIES BEFORE CHILD PROCESS
If the parent process dies before its children, the orphaned children need to know who their
parent process is. Recall that each process has a parent, and you can trace this family tree of
sorts all the way back to PID 1, otherwise known as init. When a parent dies, init adopts all
its children, as shown example below.
Example#5:
In this example, the parent process calls fork, waits for two seconds, then exits. The child
process continues by printing its parent PID for five seconds. You can see that the PPID
changes to 1 as the parent dies. Also of interest is the return of the shell prompt. Because
the child process is running in the background, control returns to the shell as soon as the
parent dies.
>vi die1.c
#include <unistd.h>
#include <stdio.h>
int main(void)
{

int i;
if (fork()) {
sleep(2);

76 | P a g e

/* Parent */

_exit(0);
}
for (i=0; i < 5; i++)
{ printf("My parent is %d\n", getppid());
sleep(1);
}
}
>gcc die1.c -o die1
>./die1
My parent is 2920
My parent is 2920
My parent is 1
My parent is 1 My parent is 1

CHILD PROCESS DIES BEFORE PARENT PROCESS


Example#6:
>cat die2.c
#include <unistd.h>
#include <stdio.h>
int main(void) {
int i;
if (!fork()) { /* Child exits immediately*/
_exit(0);
} /* Parent waits around for a minute */
sleep(60);
}
>gcc die2.c -o die2
>./die2 &
[1] 2934
ps -ef | grep 2934
sean 2934 2885 0 21:43:05 pts/1 0:00 ./die2
sean 2935 2934 0 - ? 0:00 <defunct>
>ps -ef | grep 2934
[1]+ Exit 199 ./die2

77 | P a g e

die2 runs in the background using the & operator, and then a process listing is displayed,
showing only the running process and its children. PID 2934 is the parent process, and PID
2935 is the one that is forked off and terminated immediately. Despite its untimely exit, the
child process is still in the process table as a defunct process, otherwise known as a zombie.
When the parent dies 60 seconds later, both processes are gone.
When a child process dies, its parent is notified with a signal called SIGCHLD. From the time the
child dies until the time the parent acknowledges the signal, the child sits in a zombie state. The
zombie is not running or consuming CPU cycles; it is merely taking up process table space.
When the parent dies, the kernel is finally able to reap the unacknowledged children along with
the parent. This means that the only way you can get rid of zombie processes is by killing the
parent. The best way to deal with zombies is to make sure they don't happen in the first place.

EXCERSICES
1. Use the template below to write a C-program that creates two processes: Process A (the
process with which the program starts execution) and Process B (As child). The Process
A forks Process B. To identify which process writes the output, each process puts its id at
the beginning of each line (see the sample output). Each process performs the following
operations.
Process A: After spawning Process B, it waits for Process B to terminate. After Process Bs
termination, it will write your home directory (use HOME environment variable) and its
process ID, and terminates.
Process B: After being spawned from Process A, it sleeps for three seconds (using sleep()).
Then, it writes process IDs of itself and Process A immediately. After that, executes ps
command (using system library) and terminates.
Sample output:
./a.out

9181: I am the parent, I will create child process


9182:I am the child, I will sleep for 3 seconds
9182:My parent pid is 9181
9182:the ps command
PID TTY

TIME CMD

8931 pts/0 00:00:00 bash


9181 pts/0 00:00:00 a.out
9182 pts/0 00:00:00 a.out
9183 pts/0 00:00:00 ps
9181: My home directory is
/home/user

Template:
78 | P a g e

#include <stdio.h>
#include <unistd.h> /* contains fork prototype */
main(void)
{
int pid,status;
//printf the first message
//fork B process
if (pid == 0)

//child process

{
// print message
// sleep 3seconds
// print message
// print message
// executes ps command
printf("\n");
}
else
{
// parent waits for child to finish
// print message
system("echo $HOME");
printf("\n");
}
}

79 | P a g e

2. Write a program that creates four processes. The original process creates two
children processes and then prints out "parent". The children processes print
"child1" and child2" respectively. The second child process creates a child
process that prints out "grandchild" see the Figure below. Each process should
also print out its process id and the process id of its parent. Output might look
like:

name
pid
-----------parent
12345
grandchild 12389
child1
12350
child2
12355

parent pid
------------12000
12355
12345
12345

Note that the word might is used, since there is no guarantee of the order of the four
process which will execute the output statement first.
Parent

child1

Child2

Grandchild

3. Use the template below to write a C-program that creates two processes: Process A (the
process with which the program starts execution) and Process B (As child). Process A
forks Process B. The two processes read and write from the same files. To identify which
process writes the output, each process puts its id at the beginning of each line. Study the
output and write your observations.

80 | P a g e

#include <stdio.h>
#include <strings.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
int main(void) {
int fd_in, fd_out;
char buf[1024];
memset(buf, 0, 1024); /* clear buffer*/
fd_in = //open infile for readonly
/* Open outfile write only if it is not exist creat it with 0644 permission */
fd_out =
/* create new process It doesn't matter about child vs parent */
while (read(fd_in, buf, 2) > 0) { /* Loop through the infile */
printf("%d: %s", getpid(), buf);
/* Write a line */
sprintf(buf, "%d Hello, world!\n\r", getpid());
write(fd_out, buf, strlen(buf));
// sleep 1 second
memset(buf, 0, 1024); /* clear buffer*/
}
sleep(10);
}
> gcc frk.c -o frk
> ./frk

81 | P a g e

LABORATORY11: INTER-PROCESS COMMUNICATION: PIPES &


SIGNALS
Objective
The objective is to know how to make the processes communicate among themselves. There are
many mechanisms through which the processes communicate and in this lab we will discuss
two such mechanisms: Pipes and Signals. A pipe is used for one-way communication of a stream
of bytes. Signals inform processes of the occurrence of asynchronous events. In this lab we will
learn how to create pipes and how processes communicate by reading or writing to the pipe and
also how to have a two-way communication between processes. This lab also discusses how
user-defined handlers for particular signals can replace the default signals handlers and also
how the processes can ignore the signals.
By learning about signals, you can "protect" your programs from Control-C, arrange for an alarm
clock signal to terminate your program if it takes too long to perform a task, and learn how UNIX
uses signals during everyday operations.
The system calls covered in this lab are:

pipe
dup / dup2
alarm
kill
signal

PIPES
Pipes are familiar to most UNIX users as a shell facility. For instance, to print a sorted list of who
is logged on, you can enter this command line:
who | sort | lpr
There are three processes here, connected with two pipes. Data flows in one direction only,
from who to sort to lpr. It is also possible to set up bidirectional pipelines (from process A to B,
and from B back to A) and pipelines in a ring (from A to B to C to A) using system calls. The shell,
however, provides no notation for these more elaborate arrangements, so they are unknown to
most Unix users.
We'll begin by showing some simple examples of processes connected by a one-directional
pipeline.

PIPE SYSTEM CALL


int pfd[2];
int pipe (pfd); /* Returns 0 on success or -1 on error */

82 | P a g e

I/O WITH A PIPE


These two file descriptors can be used for block I/O
write(pfd[1], buf, SIZE);
read(pfd[0], buf, SIZE);
Fork and a pipe:
A single process would not use a pipe. They are used when two processes wish to communicate
in a one-way fashion. A process splits in two using fork ( ). A pipe opened before the fork
becomes shared between the two processes.
Before fork

After fork

83 | P a g e

This gives two read ends and two write ends. The read end of the pipe will not be closed until
both of the read ends are closed, and the write end will not be closed until both the write ends
are closed. Either process can write into the pipe, and either can read from it. Which process
will get what is not known.
For predictable behavior, one of the processes must close its read end, and the other must close
its write end. Then it will become a simple pipeline again.

Suppose the parent wants to write down a pipeline to a child. The parent closes its read end,
and writes into the other end. The child closes its write end and reads from the other end.
When the processes have ceased communication, the parent closes its write end. This means
that the child gets eof on its next read, and it can close its read end.
Pipes use the buffer cache just as ordinary files do. Therefore, the benefits of writing and
reading pipes in units of a block (usually 512 bytes) are just as great. A single write execution is
atomic, so if 512 bytes are written with a single system call, the corresponding read will return
with 512 bytes (if it requests that many). It will not return with less than the full block.
However, if the writer is not writing complete blocks, but the reader is trying to read complete
blocks, the reader may keep getting partial blocks anyhow. This won't happen if the writer is
faster than the reader, since then the writer will be able to fill the pipe with a complete block
before the reader gets around to reading anything. Still, it's best to buffer writes and reads on
pipes, and this is what the Standard I/O Library does automatically.

#include <stdio.h>
#define SIZE 1024
main( )
{
int pfd[2];
int nread;
int pid;
char buf[SIZE];
84 | P a g e

if (pipe(pfd) == -1)
{
perror("pipe failed");
exit(1);
}
if ((pid = fork()) < 0)
{
perror("fork failed");
exit(2);
}
if (pid == 0)
{ /* child */
close(pfd[1]);
while ((nread = read(pfd[0], buf, SIZE)) != 0)
printf("child read %s\n", buf);
close(pfd[0]);
}
else
{ /* parent */
close(pfd[0]);
strcpy(buf, "hello...");
/* include null terminator in write */
write(pfd[1], buf, strlen(buf)+1);
close(pfd[1]);
}
}

Given that we have two processes, how can we connect them so that one can read from a pipe
what the other writes? We can't. Once the processes are created they can't be connected,
because there's no way for the process that makes the pipe to pass a file descriptor to the other
process. It can pass the file descriptor number, of course, but that number won't be valid in the
other process. But if we make a pipe in one process before creating the other process, it will
inherit the pipe file descriptors, and they will be valid in both processes. Thus, two processes
communicating over a pipe can be parent and child, or two children, or grandparent and
grandchild, and so on, but they must be related, and the pipe must be passed on at birth. In
practice, this may be a severe limitation, because if a process dies there's no way to recreate it
and reconnect it to its pipes -- the survivors must be killed too, and then the whole family has to
be recreated.

85 | P a g e

In general, then, here is how to connect two processes with a pipe:


1. Make the pipe.
2. Fork to create the reading child.
3. In the child close the writing end of the pipe, and do any other preparations that are
needed.
4. In the child execute the child program.
5. In the parent close the reading end of the pipe.
6. If a second child is to write on the pipe, create it, make the necessary preparations, and
execute its program. If the parent is to write, go ahead and write.
Heres a small program that uses a pipe to allow the parent to read a message from its child:
#include <stdio.h>
#include <string.h>
#define READ 0
#define WRITE 1
char* phrase = "This is ICS431 lab time" ;
main ( )
{
int

fd [2], bytesread ;

char message [100] ;


pipe ( fd ) ;
if ( fork ( ) == 0 )

/* child, writer */

{
close ( fd [READ] ) ;

/* close unused end */

write ( fd [WRITE], phrase, strlen (phrase) + 1) ;


close ( fd [WRITE] ) ;

/* close used end */

}
else

/* parent, reader */

{
close ( fd [WRITE] ) ;

/* close unused end */

bytesread = read (fd [READ], message, 100) ;


printf ("Read %d bytes : %s\n", bytesread, message) ;
close ( fd [READ] ) ;
}
}
Implementation of Redirection:

86 | P a g e

/* close used end */

When a process forks, the child inherits a copy of its parents file descriptors. When process
execs, the standard input, output, and error channels remain unaffected. The UNIX shell uses
these two pieces of information to implement redirection.
To perform redirection, the shell performs the following series of actions:

The parent shell forks and then waits for the child shell to terminate.

The child shell opens the file output, creating it or truncating as necessary.

The child shell then duplicates the file descriptor of output to the standard output file
descriptor, number 1, and then closes the original descriptor of output. All standard
output is therefore redirected to output.

The child shell then execs the ls utility. Since the file descriptors are inherited during an
exec ( ), all of standard output of ls goes to output.

When the child shell terminates, the parent resumes. The parents file descriptors are
unaffected by the childs actions, as each process maintains its own private descriptor
table.
#include <fcntl.h>
#include <stdio.h>
#include <sys/file.h>
main (argc, argv)
int argc ;
char *argv[ ] ;
{
int fd ;

/* file descriptor or pointer */

fd = open (argv[1], O_CREAT | O_TRUNC | O_RDWR, 0777) ;


/* open file named in argv[1] */
dup2 (fd, 1) ;

/* and assign it to fd file pointer */

close (fd) ; /* duplicate fd with 1 which is standard output (the monitor) */


execvp (argv[2], &argv[2]) ;
/* the output is not printed on screen but is redirected to output file */
printf ("End\n") ; /* should never execute */
}
dup / dup2 System Call:
int dup (int oldfd )
int dup2 (int oldfd, int newfd )

87 | P a g e

dup ( ) finds the smallest free file descriptor entry and points it to the same file as oldfd. dup2 ( )
closes newfd if its currently active and then points it to the same file as oldfd. In both cases, the
original and copied file descriptors share the same file pointer and access mode.
They both return the index of the new file descriptor if successful and 1 otherwise.
dup/dup2 duplicates an existing file descriptor, giving a new file descriptor that is open to the
same file or pipe. The two share the same file pointer, just as an inherited file descriptor shares
the file pointer with the corresponding file descriptor in the parent. The call fails if the argument
is bad (not open) or if 20 file descriptors are already open.
A pipeline works because the two processes know the file descriptor of each end of the pipe.
Each process has a stdin (0), a stdout (1) and a stderr (2). The file descriptors will depend on
which other files have been opened, but could be 3 and 4, say.
Suppose one of the processes replaces itself by an "exec''. The new process will have files for
descriptors 0, 1, 2, 3 and 4 open. How will it know which are the ones belonging to the pipe? It
can't.
Example:
To implement "ls | wc'' the shell will have created a pipe and then forked. The parent will exec
to be replaced by "ls'', and the child will exec to be replaced by "wc''.
The UNIX shells use unnamed pipes to build pipelines. They use a trick similar to the redirection
mechanism to connect the standard output of one process to standard input of another. To
illustrate this approach, heres the program that executes two named programs, connecting the
standard output of the first to the standard input of the second.
#include <stdio.h>
#include <string.h>
#define READ 0
#define WRITE 1
main (argc, argv)
int argc ;
char* argv[] ;
{
int

pid, fd [2] ;

if (pipe(fd) == -1)
{
perror("pipe failed");
exit(1);
}
if ((pid = fork( )) < 0)
{
88 | P a g e

perror("fork failed");
exit(2);
}
if ( pid != 0 )

/* parent, writer */

{
close ( fd [READ] ) ;

/* close unused end */

dup2 ( fd [WRITE], 1) ;

/* duplicate used end to standard out */

close ( fd [WRITE] ) ;

/* close used end */

execlp ( argv[1], argv[1], NULL) ;

/* execute writer program */

}
else

/* child, reader */

{
close ( fd [WRITE] ) ;

/* close unused end */

dup2 ( fd [READ], 0) ;

/* duplicate used end to standard input */

close ( fd [READ] ) ;

/* close used end */

execlp ( argv[2], argv[2], NULL) ;

/* execute reader program */

}
}
Run the above program as
./ a.out who wc

SIGNALS
Programs must sometimes deal with unexpected or unpredictable events, such as:

a floating point error


a power failure
an alarm clock "ring"
the death of a child process
a termination request from a user (i.e., a Control-C)
a suspend request from a user (i.e., a Control-Z)

These kinds of events are sometimes called interrupts, as they must interrupt the regular flow of
a program in order to be processed. When UNIX recognizes that such an event has occurred, it
sends the corresponding process a signal.
The kernel isn't the only one that can send a signal; any process can send any other process a
signal, as long as it has permissions.
A programmer may arrange for a particular signal to be ignored or to be processed by a special
piece of code called a signal handler. In the latter case, the process that receives the signal
suspends its current flow of control, executes the signal handler, and then resumes the original
flow of control when the signal handler finishes.

89 | P a g e

Signals inform processes of the occurrence of asynchronous events. Every type of signal has a
HANDLER which is a function. All signals have default handlers which may be replaced with
user-defined handlers. The default signal handlers for each process usually terminate the
process or ignore the signal, but this is not always the case.
Signals may be sent to a process from another process, from the kernel, or from devices such as
terminals. The ^C, ^Z, ^S and ^Q terminal commands all generate signals which are sent to the
foreground process when pressed.
The kernel handles the delivery of signals to a process. Signals are checked for whenever a
process is being rescheduled, put to sleep, or re-executing in user mode after a system call.
Types of Signals:
There are 31 different signals defined in "/usr/include/signal.h". A programmer may choose
for a particular signal to trigger a user-supplied signal handler, trigger the default kernelsupplied handler, or be ignored. The default handler usually performs one of the following
actions:

terminates the process and generates a core file (dump)


terminates the process without generating a core image file (quit)
ignores and discards the signal (ignore)
suspends the process (suspend)
resumes the process

Some signals are widely used, while others are extremely obscure and used by only one or two
programs. The following list gives a brief explanation of each signal. The default action upon
receipt of a signal is for the process to terminate.

SIGHUP
Hangup. Sent when a terminal is hung up to every process for which it is the control terminal.
Also sent to each process in a process group when the group leader terminates for any reason.
This simulates hanging up on terminals that can't be physically hung up, such as a personal
computer.

SIGINT
Interrupt. Sent to every process associated with a control terminal when the interrupt key
(Control-C) is hit. This action of the interrupt key may be suppressed or the interrupt key may
be changed using the stty command. Note that suppressing the interrupt key is completely
different from ignoring the signal, although the effect (or lack of it) on the process is the same.

SIGTSTP
Interrupt. Sent to every process associated with a control terminal when the interrupt key
(Control-Z) is hit. This action of the interrupt key may be suppressed or the interrupt key may
be changed using the stty command. Note that suppressing the interrupt key is completely
different from ignoring the signal, although the effect (or lack of it) on the process is the same.

SIGQUIT
90 | P a g e

Quit. Similar to SIGINT, but sent when the quit key (normally Control-\) is hit. Commonly sent in
order to get a core dump.

SIGILL
Illegal instruction. Sent when the hardware detects an illegal instruction. Sometimes a process
using floating point aborts with this signal when it is accidentally linked without the -f option on
the cc command. Since C programs are in general unable to modify their instructions, this
signal rarely indicates a genuine program bug.

SIGTRAP
Trace trap. Sent after every instruction when a process is run with tracing turned on with
ptrace.

SIGIOT
I/O trap instruction. Sent when a hardware fault occurs, the exact nature of which is up to the
implementer and is machine-dependent. In practice, this signal is preempted by the standard
subroutine abort, which a process calls to commit suicide in a way that will produce a core
dump.

SIGEMT
Emulator trap instruction. Sent when an implementation-dependent hardware fault occurs.
Extremely rare.

SIGFPE
Floating-point exception. Sent when the hardware detects a floating-point error, such as a
floating point number with an illegal format. Almost always indicates a program bug.

SIGKILL
Kill. The one and only sure way to kill a process, since this signal is always fatal (can't be ignored
or caught). To be used only in emergencies; SIGTERM is preferred.

SIGBUS
Bus error. Sent when an implementation-dependent hardware fault occurs. Usually means that
the process referenced at an odd address data that should have been word-aligned.

SIGSEGV
Segmentation violation. Sent when an implementation-dependent hardware fault occurs.
Usually means that the process referenced data outside its address space. Trying to use NULL
pointers will usually give you a SIGSEGV.

SIGPIPE
91 | P a g e

Write on a pipe not opened for reading. Sent to a process when it writes on a pipe that has no
reader. Usually this means that the reader was another process that terminated abnormally.
This signal acts to terminate all processes in a pipeline: When a process terminates abnormally,
all processes to its right receive an end-of-file and all processes to its left receive this signal.
Note that the standard shell ( sh) makes each process in a pipeline the parent of the process to
its left. Hence, the writer is not the reader's parent (it's the other way around), and would
otherwise not be notified of the reader's death.

SIGALARM
Alarm clock. Sent when a process's alarm clock goes off. The alarm clock is set with the alarm
system call.

SIGTERM
Software termination. The standard termination signal. It's the default signal sent by the kill
command, and is also used during system shutdown to terminate all active processes. A
program should be coded to either let this signal default or else to clean up quickly (e.g., remove
temporary files) and call exit.

SIGUSR1
User defined signal 1. This signal may be used by application programs for interprocess
communication. This is not recommended however, and consequently this signal is rarely used.

SIGUSR2
User defined signal 2. Similar to SIGUSR1.

SIGPWR
Power-fail restart. Exact meaning is implementation-dependent. One possibility is for it to be
sent when power is about to fail (voltage has passed, say, 200 volts and is falling). The process
has a very brief time to execute. It should normally clean up and exit (as with SIGTERM). If the
process wishes to survive the failure (which might only be a momentary voltage drop), it can
clean up and then sleep for a few seconds. If it wakes up it can assume that the disaster was only
a dream and resume processing. If it doesn't wake up, no further action is necessary.
Programs that need to clean up before terminating should arrange to catch signals SIGHUP,
SIGINT, and SIGTERM. Until the program is solid, SIGQUIT should be left alone so there will be a
way to terminate the program (with a core dump) from the keyboard. Arrangements for the
other signals are made much less often; usually they are left to terminate the process. But a
really polished program will want to catch everything it can, to clean up, possibly log the error,
and print a nice error message. Psychologically, a message like ``Internal error 53: contact
customer support'' is more acceptable than the message ``Bus error -- core dumped'' from the
shell. For some signals, the default action of termination is accompanied by a core dump. These
are SIGQUIT, SIGILL, SIGTRAP, SIGIOT, SIGEMT, SIGFPE, SIGBUS, SIGSEGV, and SIGSYS.

92 | P a g e

REQUESTING AN ALARM SIGNAL: ALARM( )


One of the simplest ways to see a signal in action is to arrange for a process to receive an alarm
clock signal, SIGALRM, by using alarm ( ). The default handler for this signal displays the
message "Alarm Clock" and terminates the process. Here's how alarm ( ) works:

int alarm (int count)


alarm ( ) instructs the kernel to send the SIGALRM signal to the calling process after count
seconds. If an alarm had already been scheduled, it is overwritten. If count is 0, any pending
alarm requests are cancelled. alarm ( ) returns the number of seconds that remain until the
alarm signal is sent.
Here's a small program that uses alarm ( ) together with its output.
#include <stdio.h>
main ( )
{
alarm (5) ;

/* schedule an alarm signal in 5 seconds */

printf ("Looping forever ...\n") ;


while ( 1 ) ;
printf ("This line should never be executed.\n") ;
}
The output is:
Looping forever...
Alarm clock
Signal System Call:
#include <signal.h>
void (*signal(sig, func))() /* Catch signal with func */
void (*func)();

/* The function to catch the sig */

/* Returns the previous handler */


/* or -1 on error */

The declarations here baffle practically everyone at first sight. All they mean is that the second
argument to signal is a pointer to a function, and that a pointer to a function is returned. The
first argument, sig, is a signal number. The second argument, func, can be one of three things:

SIG_DFL. This sets the default action for the signal.


SIG_IGN. This sets the signal to be ignored; the process becomes immune to it. The

signal SIGKILL can't be ignored. Generally, only SIGHUP, SIGINT, and SIGQUIT should
ever be permanently ignored. The receipt of other signals should at least be logged,
since they indicate that something exceptional has occurred.

93 | P a g e

A pointer to a function. This arranges to catch the signal; every signal but SIGKILL may be
caught. The function is called when the signal arrives.
The signals SIGKILL and SIGSTP may not be reprogrammed.
A child process inherits a parents action for a signal. Actions SIG_DFL and SIG_IGN are
preserved across an exec, but caught signals are reset to SIG_DFL. This is essential because the
catching function will be overwritten by new code. Of course, the new program can set its own
signal handlers. Arriving signals are not queued. They are either ignored, they terminate the
process, or they are caught. This is the main reason why signals are inappropriate for
interprocess communication -- a message in the form of a signal might be lost if it arrives when
that type of signal is temporarily ignored. Another problem is that arriving signals are rather
rude. They interrupt whatever is currently going on, which is complicated to deal with properly,
as we'll see shortly. signal returns the previous action for the signal. This is used if it's
necessary to restore it to the way it was.
Defaulting and ignoring signals is easy; the hard part is catching them. To catch a signal you
supply a pointer to a function as the second argument to signal. When the signal arrives two
things happen, in this order:

The signal is reset to its default action, which is usually termination. Exceptions are
SIGILL and SIGTRAP, which are not reset because they are signaled too often.
The designated function is called with a single integer argument equal to the number of
the signal that it caught. When and if the function returns, processing resumes from the
point where it was interrupted.
If the signal arrives while the process is waiting for any event at all, and if the signalcatching function returns, the interrupted system call returns with an error return of
EINTR -- it is not restarted automatically. You must distinguish this return from a
legitimate error. Nothing is wrong -- a signal just happened to arrive while the system
call was in progress.

It's extremely difficult to take interrupted system calls into account when programming. You
either has to program to restart every system call that can wait or else temporarily ignore
signals when executing such a system call. Both approaches are awkward, and the second runs
the additional risk of losing a signal during the interval when it's ignored. We therefore offer
this rule: Never return from a signal-catching function. Either terminate processing entirely or
terminate the current operation by executing a global jump (not described here).
If you make it a habit to always print out the value of errno when a system call fails (by calling
perror for example) you won't be mystified for long since the EINTR error code will clarify
what's going on.
Since the first thing that happens when a caught signal arrives is to change its action to the
default (termination), another signal of the same type arriving immediately after the first can
terminate the process before it has a chance to even begin the catching function. This is rare but
possible, especially on a busy system.
This loophole can be tightened, but not eliminated, by setting the signal to be ignored
immediately upon entering the catching function, before doing anything else. Since we're not
using signals as messages, we don't care if an arriving signal is thereby missed. We're concerned
only with processing the first one correctly and with not terminating prematurely.

94 | P a g e

PAUSE SYSTEM CALL:


int pause ( )
pause() suspends the calling process and returns when the calling
process receives a signal. It is most often used to wait efficiently for an
alarm signal. pause( ) doesn't return anything useful.

The following program catches and processes the SIGALRM signal efficiently by having user
written signal handler, alarmHandler ( ), by using signal ( ).
#include <stdio.h>
#include <signal.h>
int alarmFlag = 0 ;
void alarmHandler ( ) ;
main ( )
{
signal(SIGALRM, alarmHandler) ; /*Install signal Handler*/
alarm (5) ;
printf ("Looping ...\n") ;
while (!alarmFlag)
{
pause ( ) ; /* wait for a signal */
}
printf ("Loop ends due to alarm signal\n") ;
}
void alarmHandler ( )
{
printf ("An ALARM clock signal was received\n") ;
alarmFlag = 1 ;
}
The output will be as:
Looping ...
An ALARM clock signal was received
Loop ends due to alarm signal
95 | P a g e

Protecting Critical Code And Chaining Interrupt Handlers:


The same techniques described previously may be used to protect critical pieces of code against
Control-C attacks and other signals. In these cases, it's common to save the previous value of the
handler so that it can be restored after the critical code has executed. Here's the source code of
the program that protects itself against SIGINT signals:
#include <stdio.h>
#include <signal.h>
main ( )
{
int (*oldHandler) ( ) ; /* holds old handler value */
printf ("I can be Control-C'ed \n") ;
sleep (5) ;
oldHandler = signal(SIGINT, SIG_IGN) ; /* Ignore Ctrl-C */
printf ("I am protected from Control-C now \n") ;
sleep (5) ;
signal (SIGINT, oldHandler) ; /* Restore old handler */
printf ("I can be Control-C'ed again \n") ;
sleep (5) ;
printf ("Bye!!!!!!!\n") ;
}
Now run the program by pressing Control-C twice while the program sleeps.

KILL SYSTEM CALL


#include <signal.h>
int kill(pid, sig) /* Send the signal to the named process */
int pid;
int sig;
In the previous sections we mainly discussed signals generated by the kernel as a result of some
exceptional event. It is also possible for one process to send a signal of any type to another
process. pid is the process-ID of the process to receive the signal; sig is the signal number. The
effective user-IDs of the sending and receiving processes must be the same, or else the effective
user-ID of the sending process must be the super user.

If pid is equal to zero, the signal is sent to every process in the same process group as the
sender. This feature is frequently used with the kill command (kill 0) to kill all background
processes without referring to their process-IDs. Processes in other process groups (such as a
DBMS you happened to have started) won't receive the signal.
96 | P a g e

If pid is equal to -1, the signal is sent to all processes whose real user-ID is equal to the effective
user-ID of the sender. This is a handy way to kill all processes you own, regardless of process
group.
In practice, kill is used 99% of the time for one of these purposes:

To terminate one or more processes, usually with SIGTERM, but sometimes with
SIGQUIT so that a core dump will be obtained.

To test the error-handling code of a new program by simulating signals such as


SIGFPE (floating-point exception).

kill is almost never used simply to inform one or more processes of something (i.e., for

interprocess communication), for the reasons outlined in the previous sections.


Note also that the kill system call is most often executed via the kill command. It isn't usually
built into application programs.

EXCERSICES
Execute the C programs given in the following problems. Observe and interpret the results. You
will learn about child and parent processes, and much more about UNIX processes in general by
performing the suggested experiments. UNIX Calls used in the following problems: signal( ),
alarm( ), pipe( ), sigkey( ), and exit( ).
1. Execute the following program and its suggested modifications. Observe and interpret the
results.
#include <signal.h>
void my_routine ( ) ;
main ( )
{
printf ("Process ID is: %d\n", getpid( ) ) ;
signal (SIGINT, my_routine) ;
for ( ; ; ) ;
}
void my_routine ( )
{
printf ("Have a good day !!!!!!\n") ;
}
Modifications:

1. Press the CTRL-C key. What happened? Why?


2. Omit the signal ( ) statement in the main program, run the program, observe the result.

97 | P a g e

3. In main ( ), replace the signal ( ) statement by: signal (SIGINT, SIG_IGN) ; Observe the
result. Relate the three parts and explain their results. If you get stuck, you can kill the
processes by pressing CTRL \.
4. The signal sent when CTRL \ is pressed is SIGQUIT and the name of the signal service
routine is sigkey ( ); Go back to the original code. Change the name my_routine to sigkey
and observe what happens when you press CTRL \.

2. Run the following program. Design some experiments. Describe your experiments, state
results and explain them.

#include <signal.h>
void my_routine ( ) ;
main ( )
{
signal (SIGINT, my_routine) ;
signal (SIGQUIT, my_routine) ;
for ( ; ; ) ;
}
void my_routine (signo)
int signo ;
{
printf ("The signal number is %d\n", signo) ;
}
3. Observe and explain the behavior of the following program.

#include <signal.h>
void my_routine ( ) ;
int pid ;
main ( )
{
pid = fork ( );
signal (SIGINT, my_routine) ;
for ( ; ; ) ;
}
void my_routine ( )
{

98 | P a g e

printf ("My pid = %d\n", pid) ;


}
4. Find out what this program does and explain it.
#include <signal.h>
#include <stdio.h>
char msg[100] ;
main (argc, argv)
int argc ;
char *argv[ ] ;
{
int time ;
void my_secretary ( ) ;
time = atoi (argv[2]) ;
strcpy (msg, argv[1]) ;
signal (SIGALRM, my_secretary) ;
alarm (time) ;
for ( ; ; ) ;
}
void my_secretary ( )
{
printf ("%s\n", msg) ;
exit (0) ;
}

4. Suspending and resuming processes. The SIGSTOP and SIGCONT signals suspend and
resume a process, respectively. They are used by the UNIX shells to implement built-in
commands like stop, fg, and bg. Observe and explain the behavior of the following program.

#include <stdio.h>
#include <signal.h>
main ( )
{
int pid1, pid2 ;
pid1 = fork ( ) ;
if (pid1 == 0)
{
99 | P a g e

/*first child */

while (1) /* infinite loop */


{
printf ("pid1 is alive\n") ;
sleep (1) ;
}
}
pid2 = fork ( ) ;
if (pid2 == 0)

/*second child */

{
while (1) /* infinite loop */
{
printf ("pid2 is alive\n") ;
sleep (1) ;
}
}
sleep (3) ;
kill (pid1, SIGSTOP) ;
sleep (3) ;
kill (pid1, SIGCONT) ;
sleep (3) ;
kill (pid1, SIGINT) ;
kill (pid2, SIGINT) ;
}

5. Discover the behavior by writing a main program and a signal handling routine to print a
message in case of an illegal instruction (e.g. division by zero). Including a division by zero in
main program. The signal sent for an illegal instruction is SIGILL.

LABORATORY12: INTER PROCESS COMMUNICATION (IPC)-USING


SHARED MEMORY
Objective:
The aim of this laboratory is to show you how the processes can communicate among
themselves using the Shared Memory regions. Shared Memory is an efficient means of passing
data between programs. One program will create a memory portion, which other processes (if
permitted) can access. A shared segment can be attached multiple times by the same process. A
shared memory segment is described by a control structure with a unique ID that points to an
area of physical memory. In this lab the following issues related to shared memory utilization
are discussed:
100 | P a g e

Creating a Shared Memory Segment


Controlling a Shared Memory Segment
Attaching and Detaching a Shared Memory Segment

WHAT IS SHARED MEMORY?


In the discussion of the fork ( ) system call, we mentioned that a parent and its children have
separate address spaces. While this would provide a more secured way of executing parent and
children processes (because they will not interfere each other), they shared nothing and have
no way to communicate with each other. A shared memory is an extra piece of memory that is
attached to some address spaces for their owners to use. As a result, all of these processes share
the same memory segment and have access to it. Consequently, race conditions may occur if
memory accesses are not handled properly. The following figure shows two processes and their
address spaces. The yellow rectangle is a shared memory attached to both address spaces and
both process 1 and process 2 can have access to this shared memory as if the shared memory is
part of its own address space. In some sense, the original address space is "extended" by
attaching this shared memory.

Shared memory is a feature supported by UNIX System V, including Linux, SunOS and Solaris.
One process must explicitly ask for an area, using a key, to be shared by other processes. This
process will be called the server. All other processes, the clients that know the shared area can
access it. However, there is no protection to a shared memory and any process that knows it can
access it freely. To protect a shared memory from being accessed at the same time by several
processes,
a
synchronization
protocol
must
be
setup.
A shared memory segment is identified by a unique integer, the shared memory ID. The shared
memory itself is described by a structure of type shmid_ds in header file sys/shm.h. To use this
file, files sys/types.h and sys/ipc.h must be included. Therefore, your program should start with
the following lines:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
101 | P a g e

A general scheme of using shared memory is the following:


For a server, it should be started before any client. The server should perform the following
tasks:
1.
2.
3.
4.
5.

6.

Ask for a shared memory with a memory key and memorize the returned shared memory ID.
This is performed by system call shmget( ).
Attach this shared memory to the server's address space with system call shmat( ).
Initialize the shared memory, if necessary.
Do something and wait for all clients' completion.
Detach the shared memory with system call shmdt( ).
Remove the shared memory with system call shmctl( ).

For the client part, the procedure is almost the same:


1. Ask for a shared memory with the same memory key and memorize the returned shared
memory ID.
2. Attach this shared memory to the client's address space.
3. Use the memory.
4. Detach all shared memory segments, if necessary.
5. Exit.

ASKING FOR A SHARED MEMORY SEGMENT - SHMGET( )


The system call that requests a shared memory segment is shmget( ). It is defined as follows:

shm_id = shmget (
key_t k,
int
size,
int
flag
);

/* the key for the segment */


/* the size of the segment */

/* create/use flag */

In the above definition, k is of type key_t or IPC_PRIVATE. It is the numeric key to be assigned to
the returned shared memory segment. size is the size of the requested shared memory. The
purpose of flag is to specify the way that the shared memory will be used. For our purpose, only
the following two values are important:
1. IPC_CREAT | 0666 for a server (i.e., creating and granting read and write access to the
server)
2. 0666 for any client (i.e., granting read and write access to the client)
Note that due to UNIXs tradition, IPC_CREAT is correct and IPC_CREATE is not!!!
If shmget( ) can successfully get the requested shared memory, its function value is a nonnegative integer, the shared memory ID; otherwise, the function value is negative.

102 | P a g e

The following is a server example of requesting a private shared memory of four integers:
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
.....
int shm_id; /* shared memory ID */
.....
shm_id = shmget (IPC_PRIVATE, 4*sizeof(int), IPC_CREAT | 0666);
if (shm_id < 0)
{
printf("shmget error\n");
exit(1);
}
/* now the shared memory ID is stored in shm_id */
If a client wants to use a shared memory created with IPC_PRIVATE, it must be a child process of
the server, created after the parent has obtained the shared memory, so that the private key
value can be passed to the child when it is created. For a client, changing IPC_CREAT | 0666 to
0666 works fine. A warning to novice C programmers: don't change 0666 to 666. The leading 0
of an integer indicates that the integer is an octal number. Thus, 0666 is 10110110 in binary. If
the leading zero is removed, the integer becomes six hundred sixty six with a binary
representation 1111011010.
Server and clients can have a parent/client relationship or run as separate and unrelated
processes. In the former case, if a shared memory is requested and attached prior to forking the
child client process, then the server may want to use IPC_PRIVATE since the child receives an
identical copy of the server's address space which includes the attached shared memory.
However, if the server and clients are separate processes, using IPC_PRIVATE is unwise since
the clients will not be able to request the same shared memory segment with a unique and
unknown key.
Keys:

UNIX requires a key of type key_t defined in file sys/types.h for requesting
resources such as shared memory segments, message queues and semaphores. A key
is simply an integer of type key_t; however, you should not use int or long, since the
length of a key is system dependent.
There are three different ways of using keys, namely:
1. a specific integer value (e.g., 123456)
2. a key generated with function ftok( )
3. a uniquely generated key using IPC_PRIVATE (i.e., a private key).
The first way is the easiest one; however, its use may be very risky since a process
can access your resource as long as it uses the same key value to request that
resource. The following example assigns 1234 to a key:

103 | P a g e

key_t SomeKey;
SomeKey = 1234;

The ftok( ) function has the following prototype:


key_t ftok (
const char *path, /* a path string */
int id
/* an integer value */
);
Function ftok( ) takes a character string that identifies a path and an integer (usually a
character) value, and generates an integer of type key_t based on the first argument with the
value of id in the most significant position. For example, if the generated integer is 35028A5D16
and the value of id is 'a' (ASCII value = 6116), then ftok( ) returns 61028A5D16. That is, 6116
replaces
the
first
byte
of
35028A5D16,generating
61028A5D16.
Thus, as long as processes use the same arguments to call ftok( ), the returned key value will
always be the same. The most commonly used value for the first argument is ".", the current
directory. If all related processes are stored in the same directory, the following call to ftok( )
will generate the same key value:
#include <sys/types.h>
#include <sys/ipc.h>
key_t SomeKey;
SomeKey = ftok(".", 'x');
After obtaining a key value, it can be used in any place where a key is required. Moreover, the
place where a key is required accepts a special parameter, IPC_PRIVATE. In this case, the system
will generate a unique key and guarantee that no other process will have the same key. If a
resource is requested with IPC_PRIVATE in a place where a key is required, that process will
receive a unique key for that resource. Since that resource is identified with a unique key
unknown to the outsiders, other processes will not be able to share that resource and, as a
result, the requesting process is guaranteed that it owns and accesses that resource exclusively.

ATTACHING A SHARED MEMORY SEGMENT TO AN ADDRESS SPACE SHMAT( )


Suppose process 1, a server, uses shmget( ) to request a shared memory segment successfully.
That shared memory segment exists somewhere in the memory, but is not yet part of the
address space of process 1. Similarly, if process 2 requests the same shared memory segment
with the same key value, process 2 will be granted the right to use the shared memory segment;
but it is not yet part of the address space of process 2. To make a requested shared memory
segment part of the address space of a process, use shmat( ).

104 | P a g e

After a shared memory ID is returned, the next step is to attach it to the address space of a
process. This is done with system call shmat( ). The use of shmat( ) is as follows:
shm_ptr = shmat (
int
shm_id,
char *ptr,
int
flag
);

/* shared memory ID */
/* a character pointer */

/* access flag */

System call shmat( ) accepts a shared memory ID, shm_id, and attaches the indicated shared
memory to the program's address space. The returned value is a pointer of type (void *) to the
attached shared memory. Thus, casting is usually necessary. If this call is unsuccessful, the
return value is -1. Normally, the second parameter is NULL. If the flag is SHM_RDONLY, this
shared memory is attached as a read-only memory; otherwise, it is readable and writable.
In the following server's program, it asks for and attaches a shared memory of four integers.
/* Lab10_1.c */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int
shm_id;
key_t mem_key;
int
*shm_ptr;
mem_key = ftok(".", 'a');
shm_id = shmget(mem_key, 4*sizeof(int), IPC_CREAT | 0666);
if (shm_id < 0)
{
printf("*** shmget error (server) ***\n");
exit(1);
}
shm_ptr = (int *) shmat(shm_id, NULL, 0); /* attach */
if ((int) shm_ptr == -1)
{
printf("*** shmat error (server) ***\n");
exit(1);
}
The following is the counterpart of a client.
105 | P a g e

/* Lab10_2.c */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
int
shm_id;
key_t mem_key;
int *shm_ptr;
mem_key = ftok(".", 'a');
shm_id = shmget(mem_key, 4*sizeof(int), 0666);
if (shm_id < 0)
{
printf("*** shmget error (client) ***\n");
exit(1);
}
shm_ptr = (int *) shmat(shm_id, NULL, 0);
if ((int) shm_ptr == -1)
{ /* attach */
printf("*** shmat error (client) ***\n");
exit(1);
}
Note that the above code assumes the server and client programs are in the current directory. In
order for the client to run correctly, the server must be started first and the client can only be
started after the server has successfully obtained the shared memory.
Suppose process 1 and process 2 have successfully attached the shared memory segment. This
shared memory segment will be part of their address space, although the actual address could
be different (i.e., the starting address of this shared memory segment in the address space of
process 1 may be different from the starting address in the address space of
process 2).

DETACHING AND REMOVING A SHARED MEMORY SEGMENT - SHMDT( ) AND


SHMCTL( )
System call shmdt( ) is used to detach a shared memory. After a shared memory is detached, it
cannot be used. However, it is still there and can be re-attached back to a process's address
space, perhaps at a different address. To remove a shared memory, use shmctl( ).

106 | P a g e

The only argument to shmdt( ) is the shared memory address returned by shmat( ). Thus, the
following code detaches the shared memory from a program:

shmdt (shm_ptr);
where shm_ptr is the pointer to the shared memory. This pointer is
returned by shmat( ) when the shared memory is attached. If the detach
operation fails, the returned function value is non-zero.

To remove a shared memory segment, use the following code:


shmctl (shm_id, IPC_RMID, NULL);
where shm_id is the shared memory ID. IPC_RMID indicates this is a
remove operation. Note that after the removal of a shared memory
segment, if you want to use it again, you should use shmget( ) followed
by shmat( ).
Program Examples:
Example#1:

Two different processes communicating via shared memory we develop two programs here
that illustrate the passing of a simple piece of memory (a string) between the processes if running
simultaneously:
/* shm_server.c */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSIZE 27
main()
{
char c;
int shmid;
key_t key;
char *shm, *s;
/* * We'll name our shared memory segment * "5678". */
key = 5678;
/* * create the segment.* */
107 | P a g e

if ((shmid = shmget(key, SHMSIZE, IPC_CREAT | 0666)) < 0)


{
perror("shmget");
exit(1);
}
/** Now we attach the segment to our data space.*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1)
{
perror("shmat");
exit(1);
}
/** Now put some things into the memory for the other process to read. */
s = shm;
for (c = 'a'; c <= 'z'; c++)
*s++ = c;
*s = NULL;
/** Finally, we wait until the other process
* Changes the first character of our memory
* to '*', indicating that it has read what
* we put there.
*/
while (*shm != '*')
sleep(1);
exit(0);
}
Simply creates the string and shared memory portion.
run it in background
/* shm_client.c */
/*
* shm-client - client program to demonstrate shared memory.
108 | P a g e

*/
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <stdio.h>
#define SHMSIZE 27
main()
{
int shmid;
key_t key;
char *shm, *s;
/*
* We need to get the segment named
* "5678", created by the server.
*/
key = 5678;
/*
* Locate the segment.
*/
if ((shmid = shmget(key, SHMSIZE, 0666)) < 0) {
perror("shmget");
exit(1);
}
/*
* Now we attach the segment to our data space.
*/
if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
perror("shmat");
exit(1);
}
/*
* Now read what the server put in the memory.
*/
for (s = shm; *s != NULL; s++)
putchar(*s);
109 | P a g e

putchar('\n');
/*
* Finally, change the first character of the
* segment to '*', indicating we have read
* the segment.
*/
*shm = '*';
printf ("\nIts done from client.\n\n\n");
exit(0);
}
Attaches itself to the created shared memory portion and prints the string.
Parent and Child processes communicating via shared memory

/*parent_child.c */
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main(void)
{
int shmid;
char *shmPtr;
int n;
if (fork( ) == 0)
{
sleep(5); /* UUPS */
if( (shmid = shmget(2041, 32, 0)) == -1 )
{
exit(1);
}
shmPtr = shmat(shmid, 0, 0);
if (shmPtr == (char *) -1)
exit(2);
printf ("\nChild Reading ....\n\n");
for (n = 0; n < 26; n++)
putchar(shmPtr[n]);
110 | P a g e

putchar('\n'); }
else
{
if( (shmid = shmget(2041, 32, 0666 | IPC_CREAT)) == -1 )
{
exit(1);
}
shmPtr = shmat(shmid, 0, 0);
if (shmPtr == (char *) -1)
exit(2);
for (n = 0; n < 26; n++)
shmPtr[n] = 'a' + n;
printf ("Parent Writing ....\n\n") ;
for (n = 0; n < 26; n++)
putchar(shmPtr[n]);
putchar('\n');
shmdt(NULL);

wait(NULL);

if( shmctl(shmid, IPC_RMID, NULL) == -1 )


{
perror("shmctl");
exit(-1);
}
}

exit(0);

}
One parent places characters in shared memory, and child reads it.

EXCERSICES
Write a program that creates a shared memory segment and waits until two other separate
processes writes something into that shared memory segment after which it prints what is
written in shared memory. For the communication between the processes to take place assume
that the process 1 writes 1 in first position of shared memory and waits; process 2 writes 2 in
first position of shared memory and goes on to write 'hello' and then process 3 writes 3 in first
position of shared memory and goes on to write 'memory' and finally the process 1 prints what
is in shared memory written by two other processes.

LABORATORY13: THREADS CREATION AND EXECUTION


Objective:
This lab examines aspects of threads and multiprocessing (and multithreading). The primary
objective of this lab is to implement the Thread Management Functions:
111 | P a g e

1.
2.
3.
4.
5.
6.

Creating Threads
Terminating Thread Execution
Passing Arguments To Threads
Thread Identifiers
Joining Threads
Detaching / Undetaching Threads

INTRODUCTION
WHAT IS THREAD?
A thread is a semi-process, that has its own stack, and executes a given piece of code. Unlike a
real process, the thread normally shares its memory with other threads (where as for processes
we usually have a different memory area for each one of them). A Thread Group is a set of
threads all executing inside the same process. They all share the same memory, and thus can
access the same global variables, same heap memory, same set of file descriptors, etc. All these
threads execute in parallel (i.e. using time slices, or if the system has several processors, then
really in parallel).

WHAT ARE PTHREADS?


Historically, hardware vendors have implemented their own proprietary versions of threads.
These implementations differed substantially from each other making it difficult for
programmers to develop portable threaded applications.
In order to take full advantage of the capabilities provided by threads, a standardized
programming interface was required. For UNIX systems, this interface has been specified by the
IEEE POSIX 1003.1c standard (1995). Implementations which adhere to this standard are
referred to as POSIX threads, or Pthreads. Most hardware vendors now offer Pthreads in
addition to their proprietary API's.
Pthreads are defined as a set of C language programming types and procedure calls. Vendors
usually provide a Pthreads implementation in the form of a header/include file and a library
which you link with your program.

112 | P a g e

WHY PTHREADS?
1. The primary motivation for using Pthreads is to realize potential program performance
gains. When compared to the cost of creating and managing a process, a thread can
be created with much less operating system overhead. Managing threads requires fewer
system resources than managing processes.

2. All threads within a process share the same address space. Inter-thread communication is
more efficient and in many cases, easier to use than inter-process communication.

3. Threaded applications offer potential performance gains and practical advantages over nonthreaded applications in several other ways:

1. Overlapping CPU work with I/O: For example, a program may have sections where it
is performing a long I/O operation. While one thread is waiting for an I/O system
call to complete, CPU intensive work can be performed by other threads.
Priority/real-time scheduling: tasks which are more important can be scheduled to
supersede or interrupt lower priority tasks.

2. Asynchronous event handling: tasks which service events of indeterminate


frequency and duration can be interleaved. For example, a web server can both
transfer data from previous requests and manage the arrival of new requests.

4. Multi-threaded applications will work on a uniprocessor system, yet naturally take


advantage of a multiprocessor system, without recompiling. In a multiprocessor
environment, the most important reason for using Pthreads is to take advantage of
potential parallelism. This will be the focus of the remainder of this session.

THE PTHREADS API


The subroutines which comprise the Pthreads API can be informally grouped into three major
classes:
1. Thread management: The first class of functions work directly on threads - creating,
detaching, joining, etc. They include functions to set/query thread attributes (joinable,
scheduling etc.) .
2. Mutexes: The second class of functions deal with a coarse type of synchronization, called a
"mutex", which is an abbreviation for "mutual exclusion". Mutex functions provide for
creating, destroying, locking and unlocking mutexes. They are also supplemented by mutex
attribute functions that set or modify attributes
associated with mutexes.
3. Condition variables: The third class of functions deal with a finer type of synchronization based upon programmer specified conditions. This class includes functions to create,
destroy, wait and signal based upon specified variable values. Functions to set/query
condition variable attributes are also included.

113 | P a g e

Naming conventions: All identifiers in the threads library begin with pthread_
pthread_

Threads themselves and miscellaneous subroutines

pthread_attr

Thread attributes objects

pthread_mutex

Mutexes

pthread_mutexattr Mutex attributes objects.


pthread_cond

Condition variables

pthread_condattr

Condition attributes objects

pthread_key

Thread-specific data keys

THREAD MANAGEMENT FUNCTIONS:


The function pthread_create is used to create a new thread, and the function pthread_exit is
used by a thread to terminate itself. The function pthread_join is used by a thread to wait for
termination of another thread.

Function:
(

int pthread_create

pthread_t * threadhandle, /* Thread handle returned by reference */


pthread_attr_t *attribute, /* Special Attribute for starting thread, may be NULL */
void *(*start_routine)(void *), /* Main Function which thread executes */
void *arg
/* An extra argument passed as a pointer */
);
Request the PThread library for creation of a new thread. The return value is 0 on
success. The return value is negative on failure. The pthread_t is an abstract
datatype that is used as a handle to reference the thread.

Function:
void pthread_exit
(
void *retval /* return value passed as a pointer */
);
This Function is used by a thread to terminate. The return value is passed as a
pointer. This pointer value can be anything so long as it does not exceed the size of
(void *). Be careful, this is system dependent. You may wish to return an address of
a structure, if the returned data is very large.

114 | P a g e

Function:
int pthread_join
(
pthread_t threadhandle, /* Pass threadhandle */
void **returnvalue /* Return value is returned by ref. */
);
Return 0 on success, and negative on failure. The returned value is a pointer
returned by reference. If you do not care about the return value, you can pass NULL
for the second argument.

THREAD INITIALIZATION

Include the pthread.h library : #include <pthread.h>

Declare a variable of type pthread_t : pthread_t the_thread

When you compile, add -lpthread to the linker flags :


cc or gcc threads.c -o threads -lpthread

Initially, threads are created from within a process. Once created, threads are peers, and may
create other threads. Note that an "initial thread" exists by default and is the thread which runs
main.

TERMINATING THREAD EXECUTION:

int pthread_cancel (pthread_t thread )


pthread_cancel sends a cancellation request to the thread denoted by the
thread argument. If there is no such thread, pthread_cancel fails.
Otherwise it returns 0.
A cancel is a mechanism by which a calling thread informs either itself or the called thread to
terminate as quickly as possible. Issuing a cancel does not guarantee that the canceled thread
receives or handles the cancel. The canceled thread can delay processing the cancel after
receiving it. For instance, if a cancel arrives during an important operation, the canceled thread
can continue if what it is doing cannot be interrupted at the point where the cancel is requested.
The programmer may specify a termination status, which is stored as a void pointer for any
thread that may join the calling thread.

115 | P a g e

There are several ways in which a Pthread may be terminated:


1. The thread returns from its starting routine (the main routine for the initial thread). By
default, the Pthreads library will reclaim any system resources used by the thread. This is
similar to a process terminating when it reaches the end of main.
2. The thread makes a call to the pthread_exit subroutine (covered below).
3. The thread is canceled by another thread via the pthread_cancel routine (not covered here).
4. The thread receives a signal that terminates it
5. The entire process is terminated due to a call to either the exec or exit subroutines.

THREAD ATTRIBUTES
Threads have a number of attributes that may be set at creation time. This is done by filling a
thread attribute object attr of type pthread_attr_t, then passing it as second argument to
pthread_create. Passing NULL is equivalent to passing a thread attribute object with all
attributes set to their default values.
Attribute objects are consulted only when creating a new thread. The same attribute object can
be used for creating several threads. Modifying an attribute object after a call to pthread_create
does not change the attributes of the thread previously created.

int pthread_attr_init (pthread_attr_t *attr)


pthread_attr_init initializes the thread attribute object attr and fills it
with default values for the attributes. Each attribute attrname can be
individually set using the function pthread_attr_setattrname and
retrieved using the function pthread_attr_getattrname.

int pthread_attr_destroy (pthread_attr_t *attr)


pthread_attr_destroy destroys the attribute object pointed to by attr
releasing any resources associated with it. attr is left in an undefined
state, and you must not use it again in a call to any pthreads function
until it has been reinitialized.

int pthread_attr_setattr (pthread_attr_t *obj, int value)


Set attribute attr to value in the attribute object pointed to by obj. See
below for a list of possible attributes and the values they can take.
On success, these functions return 0.

int pthread_attr_getattr (const pthread_attr_t *obj, int *value)

116 | P a g e

Store the current setting of attr in obj into the variable pointed to by
value. These functions always return 0.

The following thread attributes are supported:

`detachstate'
Choose whether the thread is created in the joinable state (value PTHREAD_CREATE_JOINABLE)
or in the
detached state (PTHREAD_CREATE_DETACHED). The default is
PTHREAD_CREATE_JOINABLE. In the joinable state, another thread can synchronize on the
thread termination and recover its termination code using pthread_join, but some of the thread
resources are kept allocated after the thread terminates, and reclaimed only when another
thread performs pthread_join on that thread. In the detached state, the thread resources are
immediately freed when it terminates, but pthread_join cannot be used to synchronize on the
thread termination. A thread created in the joinable state can later be put in the detached thread
using pthread_detach.

`schedpolicy'
Select the scheduling policy for the thread: one of SCHED_OTHER (regular, non-realtime
scheduling), SCHED_RR (realtime, round-robin) or SCHED_FIFO (realtime, first-in first-out). The
default is SCHED_OTHER. The realtime scheduling policies SCHED_RR and SCHED_FIFO are
available only to processes with superuser privileges. pthread_attr_setschedparam will fail and
return ENOTSUP if you try to set a realtime policy when you are unprivileged. The scheduling
policy of a thread can be changed after creation with pthread_setschedparam.

`schedparam'
Change the scheduling parameter (the scheduling priority) for the thread. The default is 0. This
attribute is not significant if the scheduling policy is SCHED_OTHER; it only matters for the
realtime policies SCHED_RR and SCHED_FIFO. The scheduling priority of a thread can be
changed after creation with pthread_setschedparam.

THREAD IDENTIFIERS:
pthread_self ( )
Returns the unique thread ID of the calling thread. The returned data
object is opaque cannot be easily inspected.

pthread_equal ( thread1, thread2 )


Compares two thread IDs: If the two IDs are different 0 is returned,
otherwise a non-zero value is returned. Because thread IDs are opaque
objects, the C language equivalence operator == should not be used to
compare two thread IDs.

117 | P a g e

Example: Pthread Creation and Termination:


//Lab13_1.c
#include <stdio.h>
#include <pthread.h>
void *kidfunc(void *p)
{
printf ("Kid ID is ---> %d\n", getpid( ));
}
main ( )
{
pthread_t kid ;
pthread_create (&kid, NULL, kidfunc, NULL) ;
printf ("Parent ID is ---> %d\n", getpid( )) ;
pthread_join (kid, NULL) ;
printf ("No more kid!\n") ;
}
Sample output: Are the process id numbers of parent and child thread the same or
different?
Parent ID is ---> 29085
Kid ID is ---> 29085
No more kid!

//Lab13_2.c
#include <stdio.h>
#include <pthread.h>
int glob_data = 5 ;
void *kidfunc(void *p)
{
printf ("Kid here. Global data was %d.\n", glob_data) ;
glob_data = 15 ;
printf ("Kid Again. Global data was now %d.\n", glob_data) ;
}
main ( )
{
pthread_t kid ;
pthread_create (&kid, NULL, kidfunc, NULL) ;
printf ("Parent here. Global data = %d\n", glob_data) ;

118 | P a g e

glob_data = 10 ;
pthread_join (kid, NULL) ;
printf ("End of program. Global data = %d\n", glob_data) ;
}
Sample output
Do the threads have separate copies of glob_data?
Parent here. Global data = 5
Kid here. Global data was 10.
Kid Again. Global data was now 15.
End of program. Global data = 15

//File lab13_3.c
/* Multithreaed C Program Using the Pthread API */
#include<ptread.h>
#include<stdio.h>
int sum; /*This data is shared by the thread(s) */
void *runner(void *param); /* the thread */
main(int argc, char *argv[])
{
pthread_t tid; /* the thread identifier */
pthread_attr_t attr;

/* set of thread attributes */

if(argc != 2)
{
fprintf(stderr,"usage: a.out <integer value>\n");
exit();
}
if(atoi(argv[1]) < 0)
{
fprintf(stderr, "%d must be >= 0 \n", atoi(argv[1]));
exit();
}
/* get the default attributes */
pthread_attr_init(&attr);
/*create the thread */
pthread_create(&tid,&attr,runner,argv[1]);
119 | P a g e

/* Now wait for the thread to exit */


pthread_join(tid,NULL);
printf("sum = %d\n",sum);
}
/*The thread will begin control in this function */
void *runner(void *param)
{
int upper = atoi(param);
int i;
sum=0;
if(upper > 0)
{
for(i=1; i <= upper;i++)
sum += i;
}
pthread_exit(0);
}

>gcc lab13_3.c -o lab13_3 -lpthread


>lab13_3 10
sum = 55

Explanation:
Above Program creates a separate thread that determines the summation of a non-negative
integer. In a thread program, separate thread begins execution in a specified function. In above
program it is the runner function. When this program begins, a single thread of control begins in
main. After some initialization, main creates a second thread that begins control in the summer
function.
All Pthread programs must include the pthread.h header file. The statement pthread_t tid
declares the identifier for the thread we will create. Each thread has a set of attributes including
stack size and scheduling information. The pthread_attr_t attr declaration represents the
attributes for the thread. We will set the attributes in the function
call pthread_attr_init(&attr) . Because we did not explicitly set any attributes, we will use the
default attribute provided.
A separate thread is created with the pthread_create function call. In addition to passing the
thread identifier and the attributes for the thread. We also pass the name of the function where
the new thread will execution, in this case runner function. Lastly, we pass the integer
parameter that was provided on the command line, argv[1].

120 | P a g e

At this point , the program has two threads : the initial thread in main and the thread
performing the summation in the runner function. After creating the second thread, the main
thread will wait for the runner thread to complete by calling the pthread_join function. The
runner thread will complete when it calls the function pthread_exit.
Multiple Threads:
The simple example code below creates 5 threads with the pthread_create( ) routine. Each
thread prints a "Hello World!" message, and then terminates with a call to pthread_exit( ).
//Lab13_4.c
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 5
void *PrintHello(void *threadid)
{
printf("\n%d: Hello World!\n", threadid);
pthread_exit(NULL);
}
int main( )
{
pthread_t threads [NUM_THREADS];
int rc, t;
for(t=0; t < NUM_THREADS; t++) {
printf ("Creating thread %d\n", t);
rc = pthread_create (&threads[t], NULL, PrintHello, (void *) t );
if (rc) {
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}
Sample output
>./ lab11_4
Creating thread 0
Creating thread 1
Creating thread 2
Creating thread 3
Creating thread 4
0: Hello World!
1: Hello World!
2: Hello World!
3: Hello World!
121 | P a g e

4: Hello World!

Difference between process and threads:


//Lab13_5.c
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
int this_is_global;
void thread_func( void *ptr );
int main( ) {
int local_main;
int pid, status;
pthread_t thread1, thread2;
printf("First, we create two threads to see better what context they
share...\n");
this_is_global=1000;
printf("Set this_is_global=%d\n",this_is_global);
pthread_create( &thread1, NULL, (void*)&thread_func, (void*) NULL);
pthread_create(&thread2, NULL, (void*)&thread_func, (void*) NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("After threads, this_is_global=%d\n",this_is_global);
printf("\n");
printf("Now that the threads are done, let's call fork..\n");
local_main=17; this_is_global=17;
printf("Before fork(), local_main=%d, this_is_global=%d\n",local_main,
this_is_global);
pid=fork();
if (pid == 0) { /* this is the child */
printf("In child, pid %d: &global: %X, &local: %X\n", getpid(), &this_is_global,
&local_main);
local_main=13; this_is_global=23;
printf("Child set local main=%d, this_is_global=%d\n",local_main,
this_is_global);
exit(0);
}
else { /* this is parent */
printf("In parent, pid %d: &global: %X, &local: %X\n", getpid(),
&this_is_global, &local_main);
wait(&status);
printf("In parent, local_main=%d, this_is_global=%d\n",local_main,
this_is_global);

122 | P a g e

}
exit(0);
}
void thread_func(void *dummy) {
int local_thread;
printf("Thread %d, pid %d, addresses: &global: %X, &local: %X\n",
pthread_self(),getpid(),&this_is_global, &local_thread);
this_is_global++;
printf("In Thread %d, incremented this_is_global=%d\n", pthread_self(),
this_is_global);
pthread_exit(0);
}
Sample output
> ./lab11_5
First, we create two threads to see better what context they
share...
Set this_is_global=1000
Thread 4, pid 2524, addresses: &global: 20EC8, &local: EF20BD6C
In Thread 4, incremented this_is_global=1001
Thread 5, pid 2524, addresses: &global: 20EC8, &local: EF109D6C
In Thread 5, incremented this_is_global=1002
After threads, this_is_global=1002
Now that the threads are done, let's call fork..
Before fork(), local_main=17, this_is_global=17
In child, pid 2525: &global: 20EC8, &local: EFFFFD34
Child set local main=13, this_is_global=23
In parent, pid 2524: &global: 20EC8, &local: EFFFFD34
In parent, local_main=17, this_is_global=17

//Lab13_6.c
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
int tot_items = 0 ;
struct kidrec {
int data ;
pthread_t id ;
123 | P a g e

};
#define NKIDS 50
void *kidfunc(void *p)
{
int *ip = (int *)p ;
int tmp, n ;
tmp = tot_items ;
for (n = 50000; n--; )
tot_items = tmp + *ip ;
}
main ( )
{
struct kidrec kids[NKIDS] ;
int m ;
for (m=0; m<NKIDS; ++m)
{
kids[m].data = m+1 ;
pthread_create (&kids[m].id, NULL, kidfunc, &kids[m].data) ;
}
for (m=0; m<NKIDS; ++m)
pthread_join (kids[m].id, NULL) ;
printf ("End of Program. Grand Total = %d\n", tot_items) ;
}
Sample output
Run it several times until you see different output. How many times is the line?
tot_items = tmp + *ip ;
executed? What values does *ip have during these executions?
Passing Arguments to Threads:
The pthread_create( ) routine permits the programmer to pass one argument to the thread start
routine. For cases where multiple arguments must be passed, this limitation is easily overcome
by creating a structure which contains all of the arguments, and then passing a pointer to that
structure in the pthread_create( ) routine.
All arguments must be passed by reference and cast to (void *).
Important: threads initially access their data structures in the parent thread's memory space.
That data structure must not be corrupted/modified until the thread has finished accessing it.
The following example passes a simple integer to each thread.

124 | P a g e

Example: pthread_create( ) argument passing :


//Lab13_7.c
#include <pthread.h>
#include <stdio.h>
#define NUM_THREADS 7
char *messages[NUM_THREADS];
void *PrintHello(void *threadid)
{
int *id_ptr, taskid;

sleep(1);
id_ptr = (int *) threadid;
taskid = *id_ptr;
printf("\n %s from thread %d \n\n", messages[taskid], taskid);
pthread_exit(NULL);

int main( )
{
pthread_t threads[NUM_THREADS];
int *taskids[NUM_THREADS];
int rc, t;
messages[0] = "English: Hello World!";
messages[1] = "French: Bonjour, le monde!";
messages[2] = "Spanish: Hola al mundo";
messages[3] = "Klingon: Nuq neH!";
messages[4] = "German: Guten Tag, Welt!";
messages[5] = "Russian: Zdravstvytye, mir!";
messages[6] = "Japan: Sekai e konnichiwa!";
messages[7] = "Latin: Orbis, te saluto!";
for(t=0;t<NUM_THREADS;t++)
{
taskids[t] = (int *) malloc(sizeof(int));
*taskids[t] = t;
printf("Creating thread %d\n", t);
rc = pthread_create(&threads[t], NULL, PrintHello, (void *) taskids[t]);
if (rc)
{
printf("ERROR; return code from pthread_create() is %d\n", rc);
exit(-1);
}
}
pthread_exit(NULL);
}

125 | P a g e

Sample output
Creating thread 0
Creating thread 1
Creating thread 2
Creating thread 3
Creating thread 4
Creating thread 5
Creating thread 6
English: Hello World! from thread 0
French: Bonjour, le monde! from thread 1
Spanish: Hola al mundo from thread 2
Klingon: Nuq neH! from thread 3
German: Guten Tag, Welt! from thread 4
Japan: Sekai e konnichiwa! from thread 6
Russian: Zdravstvytye, mir! from thread 5

EXCERSICES
1. The following Box #1 program demonstrates a simple program where the main thread
creates another thread to print out the numbers from 1 to 20. The main thread waits till the
child thread finishes.
Compile and execute the Box #1 program and show the output and explain why is the
output so?
/* Box #1: Simple Child Thread */
#include <pthread.h>
#include <stdio.h>
void ChildThread(void *argument)
{
int i;
for ( i = 1; i <= 20; ++i )
{ printf(" Child Count - %d\n", i);
pthread_exit(0);
}

int main(void)

126 | P a g e

{
pthread_t hThread;

int ret;

ret=pthread_create(&hThread, NULL, (void *)ChildThread, NULL); /* Create Thread */


if (ret < 0) {

printf("Thread Creation Failed\n"); return 1;

pthread_join (hThread, NULL); /* Parent waits for */


printf("Parent is continuing....\n");
return 0;
}

2. In the Box #2 modify the above Box #1 program such that the main program passes the
count as argument to the child thread function and the child thread function prints that
many count print statements.
Compile and Execute the Box #2 program and show the output and explain why is the
output so?
/* Box #2 : Passing Thread Arguments */
#include <pthread.h>
#include <stdio.h>
void ChildThread (int argument)
{
int i;
.......................
pthread_exit(0);
}

int main(void)
{
pthread_t hThread;
pthread_create (.............................);
pthread_join (hThread, NULL);
printf ("Parent is continuing....\n");
}

127 | P a g e

return 0;

3. Write a program Box #3 by removing pthread_exit function from child thread function and
check the output? Is it the same as output of Box #2? If so Why? Explain?
/* Box #3: Implicit Thread Exit */
#include <pthread.h>
#include <stdio.h>
void ChildThread (int argument)
{
int i;
...............................
/* No pthread_exit function */
}

int main(void)
{
pthread_t hThread;
pthread_create (...........................................);
pthread_join (hThread, NULL);
printf ("Parent is continuing....\n");
}

128 | P a g e

return 0;

APPENDIX A

Keyboard Control Keys


Control Key

Description

^U

Erase entire command line

^W

Erases last word on command line

^C

Interrupts many programs and shell scripts

^Z

Suspends many programs and shell scripts

^S

Stops output and running programs; prevents output from running off end
of screen

^Q

Resumes output from program stopped by ^S

^O

Throw away output from program without interrupting the program

^D

End-of-file character used for logout; also terminates file input

^\

Quits program and saves images of program in file called core

^ =ctrl key

Wildcard Characters
Wildcard characters can be used to represent many other characters. Use them whenever you
need to define a string of characters, such as a filename, for use with a command.
Symbol

Description

matches any sequence of zero of more characters


match any single character

?
[ ]

129 | P a g e

match one of the enclosed characters

REFERENCES
[1] UNIX Tutorial for Beginners, http://www.ee.surrey.ac.uk/Teaching/Unix/
[2] http://www.unixtutorial.org/basic-unix-commands/
[3] Delve into UNIX process creation, http://www.ibm.com/developerworks/aix/library/auunixprocess.html
[4] Operating System lab Manual KUFUPM, K.S.A.
[5] Operating System lab Manual- COMSATS ABBOTTA BAD, PAKISTAN.

130 | P a g e

APPENDIX A: RULES TO FALLOW BY COMPUTER LAB USERS

The loud conversations / discussion that disturbing the other users is prohibited.

Audio CDs or applications with audio output may only be used with headphones with
minimum volume that it should not be disturb other users.

All cell phones are to be turned off or set to silent while in the lab. If you receive a phone
call, you should exit the lab before answering your cell phone.

Do not bring food or beverages inside the lab.

Any file saved on the computer hard drive will be deleted without notice. Students should
save their work onto an external storage device such as USB drive or CD.

Changing hardware and software configurations in the computer labs is prohibited. This
includes modifications of the settings, modification of system software, unplugging
equipment, etc.

Open labs are reserved for academic use only. Use of lab computers for other purposes, such
as personal email, non-academic printing, instant messaging, playing games, and listening to
music is not permitted.

Please leave the computer bench ready for the next patron. Leave the monitor on the login
screen, and do not forget to take goods related to you. While leaving computer bench please
push the chair inside the computer bench.

Users are responsible for their own personal belongings and equipment. Do not leave
anything in the Computer Lab unattended for any length of time. The Computer Labs staffs
are not responsible for lost or stolen items.

Users are not allowed to clear paper jams in the printer by themselves.

Operate the lab equipments with care.

After using white-board the user must clean for other user.

Thanks for your cooperation.


Information Science Department

131 | P a g e

APPENDIX B: CERTIFICATION

LABORARTORY MANUAL FOR COURSE ISC 357


#
1

Instructor name

Prof. Mohd. Sarfraz

Dr. Kalim Qureshi

132 | P a g e

Remarks

Signature

Date

Vous aimerez peut-être aussi