Introduction To Unix Internals and Socket Programming Introductory Session On OS's and Processes
Introduction To Unix Internals and Socket Programming Introductory Session On OS's and Processes
Programming
Introductory Session On OS’s and
Processes
Prof NB Venkateswarlu
B.Tech(SVU), M.Tech(IIT-K), Ph.D(BITS, Pilani), PDF(U of Leeds,UK)
IT Banking Airline
Application programs
Web browser
system reservation
Command
Comp. Sci. Compilers Editors
interpreter System programs
Operating system
Machine language
Microprogramming Hardware
Comp. Engg
Physical devices
5
General Structuring of OS
Monolithic
Layered
Micro-Kernel
6
Structuring of Operating Systems-
Monolithic
App App
Unstructured
User Mode
System services
from user mode into
kernel mode
OS
procedures
Hardware
7
Kernel- and User Mode Programs
Typical functionality implemented in either mode:
Kerne Spacel:
Privileged mode
Strict assumptions about reliability/security of code
Memory resident
CPU-, memory-, Input/Output managment
Multiprocessor management, diagnosis, test
Parts of file system and of the networking interface
User Space:
More flexible
Simpler maintenance and debugging
Compiler, assembler, interpreter, linker/loader
File system management, telecommunication, network management
Editors, spreadsheets, user applications
8
Structuring of Operating Systems-
Layered OS
Each layer is given access only to lower-level
interfaces
Kernel Mode
System Services
File System
Processor Scheduling
Hardware
9
Structuring of Operating Systems-
Microkernel OS (Client/server OS)
Client Memory Network
App Server Server
Kernel implements:
Scheduling Process File Display
Server Server Server
Memory
Management User Mode
Kernel Mode
Interprocess
communication request
(IPC) Microkernel
reply
User-mode servers
Hardware
10
Mach Microkernel OS
Extended Memory Managment
Map memory object
Paging (vm_map())
client kernel
handled by
page faults
user-space
server upcalls handle faults
Lookup get
Service memory and
object consistency
Port: comm.
endpoint, netmsgsrv pager
Advertise service
network-wide
11
A Peep Into Unix Internals
To Where the value returned by main
goes?
Ans: It is available in positional variable
$?.
#include<stdio.h>
int main(){
return 10; What happens if we call
} exit (10) or
_exit(10);
The exit() system call ends a process and returns a value to it parent. The prototype for the exit() system call is:
void exit(status)
int status;
#include<stdio.h>
#include<errno.h>
int main(){
int i;
extern int errno;
for(i=0;i<1024;i++){
errno=i;
perror("error");
}
return 0;
}
Error Handling
#include<stdio.h>
#include<string.h>
int main(){
int i;
for(i=0;i<1024;i++){
strerror(i);
}
return 0;
}
exit and _exit functions and exit handlers.
Observation: We don’t get Hello on screen
when we run with _exit as it don’t flush the
streams unlike exit.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<unistd.h>
int main()
{
printf("Hello");
_exit(10);
/* Replace the above with exit(10) */
}
When we replace _exit with exit, we get the methods XYZ, PQR, and IJK executed
in reverse order of their registration. With _exit, we don’t get any result
indicating that _exit will not execute exit handlers.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<unistd.h>
void XYZ(){
printf("XYZ\n");
}
void PQR(){
printf("PQR\n");
}
void IJK(){
printf("IJK\n");
}
int main(){
int i=0;
atexit(XYZ);
atexit(PQR);
atexit(IJK);
_exit(10);
/* Replace the above with exit(10) */
}
The following program when we comment setvbuf line and run, we get the
message Hello after sleep. However, using setvbuf, we are making printf as
unbuffered type. Thus, we get Hello before sleeping.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<unistd.h>
int main()
#include<stdio.h>
{
#include<stdlib.h>
printf("Hello");
#include<math.h>
/* observer what
#include<unistd.h>
happens if we add
int main(){
newline at the end*/
char buf[BUFSIZ];
/* printf uses line
setvbuf(stdout, buf, _IONBF, BUFSIZ);
buffering*/
printf("Hello");
sleep(10);
sleep(10);
exit(10);
exit(10);
}
/* The above program demonstrates the setvbuf
to demonstrate the unbufferred output */
}
The following program to demonstrate that the printf uses line buffering. That
is, when we write some matter and followed by new line it will display the
content. We wanted to find the buffer size used by printf. At 201 it will not give
any output, but at 202 it displays all, indicating the buffer size is 200.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<unistd.h>
int main(){
int i=0;
/* Make 202 to 201 and run*/
/* This indicates that printf is using a buffer of 200 */
for(i=0;i<202; i++)
{
if (('A'+i) !='\n') printf("%c", 'A'+i);
}
sleep(10);
_exit(10);
/* Replace the above with exit(10) */
}
What is a Process?
Processes
• A process has
text: machine instructions
(may be shared by other processes)
data
stack
• Process may execute either in user mode or in kernel
mode.
• Process information are stored in two places:
Process table
User table
22
What is Address Spaces?
Demonstration of these two commands to display text and data
segments.
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<unistd.h>
//int x[10];
size command //run size command with
un-//commenting the above
strip command int main(){
int A=10, B=10;
float X;
return 0;
}
Demonstrating the following
errors with some programs to
explain what is text area.
Missing text file ( We use sqrt method but don’t use –lm option
while compiling)
Text file busy (While trying to compile a program which is running)
User mode and Kernel mode
• At any given instant a computer running the Unix system
is either executing a process or the kernel itself is running
• The computer is in user mode when it is executing
instructions in a user process and it is in kernel mode
when it is executing instructions in the kernel.
• Executing System call ==> User mode to Kernel mode
perform I/O operations
system clock interrupt
26
Process Table
• Process table: an entry in process table has the following
information:
process state:
A. running in user mode or kernel mode
B. Ready in memory or Ready but swapped
C. Sleep in memory or sleep and swapped
PID: process id
UID: user id
scheduling information
signals that is sent to the process but not yet handled
a pointer to per-process-region table
27
• There is a single process table for the entire system
User Table (u area)
• Each process has only one private user table.
• User table contains information that must be accessible
while the process is in execution.
A pointer to the process table slot
parameters of the current system call, return values
error codes
file descriptors for all open files
current directory and current root
process and file size limits.
• User table is an extension of the process table.
28
PCB (Process Control Block)
29
Context Switch
Context switch (or process switch)
• The act of switching the CPU from one process
to another.
• Administrative overhead
– saving and loading registers and memory maps
– flushing and reloading the memory cache
– updating various tables and lists, etc.
• Context switch overhead is dependent on
hardware support.
– Multiple register sets in UltraSPARC.
– Advanced memory management techniques may
require extra data to be switched with each
context.
• 100s or 1000s of switches/s typically.
Process is said to be Heavy-weight? How Many Kgs?.
• A process includes many things:
– An address space (all the code and data pages)
– OS resources (e.g., open files) and accounting info.
– Hardware execution state (PC, SP, registers, etc.)
• Creating a new process is costly because all of the
data
structures must be allocated and initialized
– Linux: over 100 fields in task_struct
(excluding page tables, etc.)
• Inter-process communication is costly, since it must
usually go through the OS
– Overhead of system calls and copying data
• Cooperating processes are expensive to use.
Process Kernel user
table address address
space space
Active process
resident
swappable
Region
text
table
u area data
stack
Per-process
region table 33
Shared Program Text and
Software Libraries
• Many programs, such as shell, are often being
executed by several users simultaneously.
• The text (program) part can be shared.
• In order to be shared, a program must be compiled using
a special option that arranges the process image so that
the variable part(data and stack) and the fixed part (text)
are cleanly separated.
• An extension to the idea of sharing text is sharing
libraries.
• Without shared libraries, all the executing programs
contain their own copies. 34
Process Region
table table
text
data
stack
Active process
Reference
count = 2
text
data
stack
Per-process
region table 35
System Call
• A process accesses system resources through system call.
• System call for
Process Control:
fork: create a new process
wait: allow a parent process to synchronize its
execution with the exit of a child process.
exec: invoke a new program.
exit: terminate process execution
File system:
File: open, read, write, lseek, close
inode: chdir, chown chmod, stat fstat 36
others: pipe dup, mount, unmount, link, unlink
System call: fork()
• fork: the only way for a user to create a process in Unix
operating system.
• The process that invokes fork is called parent process
and the newly created process is called child process.
• The syntax of fork system call:
newpid = fork();
• On return from fork system call, the two processes have
identical copies of their user-level context except for the
return value pid.
• In parent process, newpid = child process id
• In child process, newpid = 0; 37
Function fork() causes the UNIX system to create a new process which can
be called as the "child process", with a new process ID. The contents of the
child process are identical to the contents of the parent process. Entire
address space of the parent process is duplicated for child process. All the
statements after fork() are executed in both the process; child and parent. Thus,
child behaviour is same as the parent process. The new process inherits
several characteristics of the old process
vfork() system call though available it is just fork() internally in
todays systems.
$ cc forkEx1.c -o forkEx1
$ forkEx1
/* forkEx1.c */ Before forking ...
#include <stdio.h> Child Process fpid=0
After forking fpid=0
main() Parent Process fpid=14707
{ After forking fpid=14707
int fpid; $
printf("Before forking ...\n");
fpid = fork();
if (fpid == 0) {
printf("Child Process fpid=%d\n", fpid);
} else {
printf("Parent Process fpid=%d\n", fpid);
}
printf("After forking fpid=%d\n", fpid);
}
40
Here, what will be the value of
$? ?. Is it the one coming from
parent or child?.
#include<stdio.h>
int main()
{
int rv;
rv=fork();
if(rv==0)
printf("Hello %d\n", getpid());
else
printf("Hi %d\n", getpid());
return 10;
}
How Many Processes will be created?.
Ans: 8. We get a process tree to be
created.
#include<stdio.h>
int main()
{
fork();
fork();
fork();
printf("Hello\n");
return 10;
}
How Many Processes will be created?.
Ans: 4. Process chain will be created.
#include<stdio.h>
int main(){
if(fork()==0){
if(fork()==0){
if( fork()==0){
printf("Hello\n");
}
}
Parent Child Child Child
}
return 0;
}
How Many Processes we can really
create?. What will be the output of the
following program?
Ans: We get an error such as unable to
fork or virtual memory exhausted as
the program will be crossing limit on
number of processes which a process
can create.
#include<stdio.h>
int main(){
while(1)fork();
return 0;
}
The following shell program also we may get unable to fork or virtual memory
exhausted as it will be crossing system limits.
echo Hello
$0
Now, run the same from the dollar prompt (shell prompt) by typing its name
like:
xxx
Or
./xxx
$ forkEx2
/* forkEx2.c */ Before forking ...
#include <stdio.h> PID TTY TIME CMD
14759 pts/9 0:00 tcsh
main() 14778 pts/9 0:00 sh
{ 14777 pts/9 0:00 forkEx2
int fpid; PID TTY TIME CMD
printf("Before forking ...\n"); 14781 pts/9 0:00 sh
system("ps"); 14759 pts/9 0:00 tcsh
fpid = fork(); 14782 pts/9 0:00 sh
system("ps"); 14780 pts/9 0:00 forkEx2
printf("After forking 14777 pts/9 0:00 forkEx2
fpid=%d\n", fpid); After forking fpid=14780
} $ PID TTY TIME CMD
14781 pts/9 0:00 sh
14759 pts/9 0:00 tcsh
14780 pts/9 0:00 forkEx2
After forking fpid=0
$ ps
PID TTY TIME CMD
14759 pts/9 0:00 tcsh
$
46
System Call: getpid() getppid()
• Each process has a unique process id (PID).
• PID is an integer, typically in the range 0 through 65535.
• Kernel assigns the PID when a new process is created.
• Processes can obtain their PID by calling getpid().
• Each process has a parent process and a corresponding
parent process ID.
• Processes can obtain their parent’s PID by calling
getppid().
47
/* pid.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
main()
{
printf("pid=%d ppid=%d\n",getpid(), getppid());
}
$ cc pid.c -o pid
$ pid
pid=14935 ppid=14759
$
48
/* forkEx3.c */
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
main()
{
int fpid;
printf("Before forking ...\n");
if((fpid = fork())== 0) {
printf("Child Process fpid=%d pid=%d ppid=%d\n",
fpid, getpid(), getppid());
} else {
printf("Parent Process fpid=%d pid=%d ppid=%d\n",
fpid, getpid(), getppid());
}
printf("After forking fpid=%d pid=%d ppid=%d\n",
fpid, getpid(), getppid());
}
49
$ cc forkEx3.c -o forkEx3
$ forkEx3
Before forking ...
Parent Process fpid=14942 pid=14941 ppid=14759
After forking fpid=14942 pid=14941 ppid=14759
$ Child Process fpid=0 pid=14942 ppid=1
After forking fpid=0 pid=14942 ppid=1
$ ps
PID TTY TIME CMD
14759 pts/9 0:00 tcsh
50
System Call: wait()
• wait system call allows a parent process to wait
for the demise of a child process.
• See forkEx4.c
51
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
main()
{
int fpid, status;
printf("Before forking ...\n");
fpid = fork();
if (fpid == 0) {
printf("Child Process fpid=%d pid=%d ppid=%d\n",
fpid, getpid(), getppid());
} else {
printf("Parent Process fpid=%d pid=%d ppid=%d\n",
fpid, getpid(), getppid());
}
wait(&status);
printf("After forking fpid=%d pid=%d ppid=%d\n",
fpid, getpid(), getppid());
}
52
$ cc forkEx4.c -o forkEx4
$ forkEx4
Before forking ...
Parent Process fpid=14980 pid=14979 ppid=14759
Child Process fpid=0 pid=14980 ppid=14979
After forking fpid=0 pid=14980 ppid=14979
After forking fpid=14980 pid=14979 ppid=14759
$
53
System Call: exec()
• exec() system call invokes another program by replacing
the current process
• No new process table entry is created for exec() program.
Thus, the total number of processes in the system isn’t
changed.
• Six different exec functions:
execlp, execvp, execl, execv, execle, execve,
(see man page for more detail.)
• exec system call allows a process to choose its successor.
54
int execl(file_name, arg0 [, arg1, ..., argn], NULL)
char *file_name, *arg0, *arg1, ..., *argn;
int execv(file_name, argv)
char *file_name, *argv[];
int execle(file_name, arg0 [, arg1, ..., argn], NULL, envp)
char *file_name, *arg0, *arg1, ..., *argn, *envp[];
int execve(file_name, argv, envp)
char *file_name, *argv[], *envp[];
int execlp(file_name, arg0 [, arg1, ..., argn], NULL)
char *file_name, *arg0, *arg1, ..., *argn;
int execvp(file_name, argv)
char *file_name, *argv[];
55
/* execEx1.c */
#include <stdio.h>
#include <unistd.h>
main()
{
printf("Before execing ...\n");
execl("/bin/date", "date", 0);
printf("After exec\n");
}
$ execEx1
Before execing ...
Sun May 9 16:39:17 CST 1999
$ 56
/* execEx2.c */
#include <sys/types.h>
#include <unistd.h>
#include <stdio.h> $ execEx2
Before execing ...
main() After exec and fpid=14903
{ $ Sun May 9 16:47:08 CST 1999
int fpid; $
printf("Before execing ...\n");
fpid = fork();
if (fpid == 0) {
execl("/bin/date", "date", 0);
}
printf("After exec and fpid=%d\n",fpid);
} 57
Do we get Hi?.
What is the return value of this program?
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("Hello\n");
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("Hello\n");
#include<stdio.h>
#include<unistd.h>
int main()
{
char *a[3];
a[0]="ls";
a[1]="-a";
a[2]=0;
printf("Hello\n");
execv("/bin/ls", a);
printf("Hi\n");
return 10;
}
Program which demonstrates the
loading of our program aaaa.
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("Hello\n");
#include<stdio.h>
#include<unistd.h>
int main()
{
printf("Hello\n");
fork();
execl("/bin/ls", "ls" "-a", 0);
printf("Hi\n");
return 10;
}
Program which demonstrates how to run
more than one program concurrently
#include<stdio.h>
int main()
{
if(fork()==0)
execl("/bin/ls", "ls", 0);
else
execl("/bin/date", "date", 0);
return 10;
}
Program which demonstrates the fact that
child will inherit the environment variables.
#include<stdio.h>
int main(int argc, char**argv, char**env)
{
int i=0;
fork();
for(i=0; env[i]!=NULL; i++)
printf("%s\n", env[i]);
return 10;
}
Program demonstrates the use of
getenv and putenv system calls.
#include<stdio.h>
int main(int argc, char**argv, char**env){
int i=0;
putenv("TMPP=/tmp");
if(fork()==0){
printf("%s\n", getenv("TMPP") );
putenv("TMPP=/bin");
printf("%s\n", getenv("TMPP") );
}
else{
wait(&i);
printf("%s\n", getenv("TMPP") );
}
return 10;
}
Program demonstrates the fact that environment
variables are inherited to child.
#include<stdio.h>
int main(int argc, char**argv, char**env)
{
int i=0;
putenv("TMPP=/tmp");
fork();
printf("%s\n", getenv("TMPP") );
return 10;
}
Program that demonstrates the fact that
command line arguments are inherited to child.
#include<stdio.h>
int main(int argc, char**argv, char**env)
{
int i=0;
fork();
for(i=0; i<argc; i++)
printf("%s\n", argv[i]);
return 10;
}
Program that demonstrates the fact
that opened files are inherited to child.
#include<stdio.h>
int main(int argc, char**argv,
char**env)
{
int i=0;
FILE * op;
op=fopen("hello", "w");
fork();
fprintf(op, "Hello Hi\n");
return 10;
}
Program explains file descriptors and
fork.
#include<stdio.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
int main(int argc, char**argv, char**env)
{
int i=0;
char xx[10]="Hi";
int op;
op=open("hello1", O_CREAT|O_WRONLY);
fork();
printf("%d\n", op);
write(op, xx, 2);
return 10;
}