Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
0% found this document useful (0 votes)
131 views60 pages

Unit 8: Inter Process Communication

Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
Download as ppt, pdf, or txt
You are on page 1/ 60

UNIT 8

INTER PROCESS COMMUNICATION

The only way for the process to exchange information is by passing open files across 1)fork. 2)Exec. 3)filesystem. Different types of inter process communication are 1) Pipes (half duplex). 2) FIFOs (named pipes). 3) Stream pipes (full duplex). 4) Named stream pipes. 5) Message queues. 6) Semaphores. 7) Shared memory. 8) Sockets. 9) Streams. (1-7) are restricted to ipc b/w process on same host

Pipes are the oldest form of UNIX ipc and are provided by all unix systems. Pipes have two limitations. 1) They are half duplex. Data flows only in one direction. 2) They can be used only between process that have a common ancestor. Pipe creation Whenever a process calls fork, a pipe is created between parent and child. (fork creates a child process, a parent process will not die until a child is terminated, we can kill the parent process abruptly)

PIPES

A pipe is created by calling the pipe function. #include<unistd.h> int pipe(int filedes[2]); Returns 0 if ok. -1 on error. Two file descriptors are returned through the filedes argument. Filedes[0]:- open for reading Filedes[1]:- open for writing. **The output of filedes[1] is the input for filedes[0].

Two ends of a pipe connected in a single process.

Fd[0]

Fd[1]

Showing data flowing through the kernel


User process Read Fd[0] write Fd[1]

pipe

kernel

Half duplex pipe after fork


parent fork Read Fd[0] write Fd[1] child Read Fd[0] write Fd[1]

pipe

parent fork Read Fd[0] write Fd[1]

child Read Fd[0] write Fd[1]

pipe

Pipe from parent to child

Fd[1]

Fd[0]

When one end of a pipe is closed, the following rules apply. Reading from a pipe whose Write end closed, after all the data has been read, read returns 0 to indicate the end of file. If we write to a pipe whose read end has been closed, the signal sigpipe is generated. If we ignore or catch the signal, the return value for write will be set to errno EPIPE.

(implementation of above diagram) #include<unistd.h> Int main(void) { Int n,fd[2]; Pid_t pid; Char line[MAXLINE]; If (pipe(fd) <0) err_sys(pipe error); if ( (pid=fork())<0) err_sys(fork error); else If(pid >0) { /* parent */ Close(fd[0]); Write(fd[1],hello world); } else { /* child */ Close(fd[1]); n=read(fd[0],line,MAXLINE); Write(STDOUT_FILENO,Line,n); } Exit(0); }

Popen() and pclose()


Popen() pclose() functions handle the following operations which are done by pipe(). 1) Creation of pipe. 2) The fork of a child. 3) Closing the unused ends of the pipe. 4) Execing the shell to execute the command. 5) Waiting for the command to terminate. Syntax:#include<stdio.h> FILE *popen( const char *cmdstring, const char *type); Returns File pointer if ok -1 on error Int pclose(FILE *fp); Returns Termination status of cmdstring if ok -1 on error

If type is r the file pointer is connected to the standard o/p of cmdstring. If type is w the file pointer is connected to the standard i/p of cmdstring.

parent

child Stdout

fp

Result of fp=popen(ls *.c,r);


parent

child
Stdin

fp

Result of fp=popen(ls *.c,w);

parent Popen pipe Stdout

Filter program

stdout stddin

prompt

User input

User at a terminal

Transforming input using popen()

FIFO
1) 2) 3) 4) FIFOS are also called named pipes. FIFOS are used between unrelated process to exchange data, whereas pipes are used between related process. FIFO is a type of a file. st_mode of stat() system call tells, whether the file is a fifo or not. Use S_ISFIFO macro in open(), in mode argument to test the file is FIFO or not. If file type is FIFO, in $ls l, the first column will have p i.e. it is a fifo file.

5)

Creating a FIFO. Creating a FIFO is similar to creating a file. (unix system V.4) #include<sys/stat.h> #include<sys/types.h> int mkfifo (const char *pathname, mode_t mode); Returns 0 if ok -1 on error

Note:Open is used to create an ordinary file. Mkfifo() is used to create a special file FIFO. UNIX system V.3 uses mknod() to create FIFO files. int mknod (const char *pathname, int mode); Returns 0if ok -1on error.

Arguments:1) 2) The pathname argument is the name of the FIFO file to be created. The mode argument specifies the access permission for user, group and others, to be assigned to the file. The permissions are set in the same way as open(), but instead of specifying O_RDONLY|O_RDWR|O_WRONLY the symbolic constant S_ISFIFO is used. S_IRWXU,S_IRWXO,S_IRGRP etc. are used

3)

Opening closing, reading, writing FIFOS


1) Once we have created a FIFO using mkfifo() we open it using open(). Normal file I/O functions open(), close(), read(), write(), unlink() etc all work with FIFOs.

2)

EXAMPLE:1) To create a FIFO file called FIFO5 with access permission of read write execute for everyone. mkfifo( FIFO5, S_ISFIFO|S_IRWXU|S_IRWXG|S_IRWXO);

2) Create a FIFO in /tmp/fifo1 with rwx permission to user and write permission to group. mkfifo( /tmp/fifo1,S_ISFIFO|S_IRWXU|S_IWGRP);

O_NONBLOCK flag is specified/ unspecified in open() function Not specified 1) Opens for read only blocks, until some other process opens FIFO for writing. 2) Opens for write only blocks, until some other process opens FIFO for reading. Specified 1) 2) Open for read only returns immediately. Open for write only returns an error with errno of ENXIO, if no other process has the FIFO open for reading.

Open for reading:


If we write to a FIFO that has no process open for reading the signal SIGPIPE is generated. When the last writer for a FIFO closes the FIFO, an end of the file is generated for the reader of the FIFO. We can have multiple writers for a FIFO. PIPE_BUF specifies the max amount of data that can be automatically written to a FIFO.

USES:1) FIFOS are used by shell commands to pass data from one shell pipeline to another, without creating intermediate temporary files.

2)

FIFOS are used in a client server application to pass data between the clients and server.

Examples of FIFOS Using FIFOS to duplicate o/p streams.


$mkfifo fifo1 $prog3 <fifo1& $Prog1 <infile |tee fifo1 |prog2

prog3 i/p file prog1 prog2

Procedure that process a filtered input stream twice

FIFO1 i/p file

PROG3

PROG1

tee PROG2

Using a FIFO and tee to send a stream to two different processes

Client server example using FIFO

SERVER

READ REQUEST

WELL KNOWN FIFO

WRITE

WRITE CLIENT

CLIENT

FIG:- Client sending requests to a server using a FIFO

SERVER Write req READ REQUEST FIFO client specific FIFO client specific WRITE CLIENT CLIENT Read replies Write req

WELL KNOWN FIFO

Read replies

WRITE

Fig:-client server communication using FIFOS

Program for creation of fifo

Message queues
Message queue are linked list of messages stored within the kernel and identified by message queue identifier. A new message queue is created, or an existing message queue is opened by msgget. New messages are added to the end of a queue by msgsnd.

Every message has a positive long integer type field, a non-negative length, and the actual data bytes all of which are specified to msgsnd when the message is added to the queue. Messages are fetched from a message queue by msgrcv.
We dont have to fetch the messages in first in first out order. Instead we can fetch the messages on their type field.

kernel Struct msqid_ds Msg_perm structure link


Type=100

link
Type=300 Length=1

link
Type=200 Length=1

Length=1
data

data

data

Msg_first Msg_last

Msg_ctime Fig:- msg Q structure in kernel

Each message queue has the following data structure associated with it. This data structure defines the current status of the queue struct msqid_ds { struct ipc_perm msg_perm; struct msg *msg_first; struct msg *msg_last; ulong msg_cbytes; ulong msg_qnum; ulong msg_qbytes; pid_t msg_lspid; pid_t msg_lrpid; time_t msg_stime; time_t msg_rtime; time_t msg_ctime; };

/* permission structure */ /* ptr to first msg on msg queue */ /* ptr to last msg on msg queue */ /* current no. of bytes on msg queue */ /* no. of msgs on msg queue */ /* Max no. of bytes on msg queue */ /* pid of last msgsnd() */ /* pid of last msgrcv() */ /*last msgsnd() time */ /*last msgrcv() time */ /*last change time */

Struct ipc_perm { uid_t uid; gid_t gid; uid_t cuid; gid_t cgid; mode_t mode; ulong seq; key_t key; };

/*owners effective userid */ /*owners effective group id */ /*creators effective userid */ /*creators effective group id */ /* access modes */ /*slot usage sequence number */ /*key */

To modify user id and group id fields we use msgctl . The two pointers msg_first and msg_last are worthless to a user process, as these point to where the corresponding messages are stored with in the kernel. Message queues are 1)Connection oriented. 2)Reliable 3)Flow control. 4)Stores as records. 5)Can assign priorities. System limits:Limits are set in the file /etc/conf/cf.d/mtune. In system limit file we have max and min values of messages, semaphores etc. MSGMAX:- size in bytes of largest message we can send. MSGMNB:- MAX size in bytes of a particular queue (i.e. sum of all messages on queue) MSGMNI:- Max no. of message qs system wide. MSGQTL:- MAX no. of messages system wide.

OPENING AN EXISITING MESSAGE QUEUE OR CREATING A NEW MESSAGE QUEUE


Msgget is used to open a message queue (or) create new #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> Int msgget( key_t key, int flag); Return Msg q id if ok -1 on error

Key:1) Each ipc structure in the kernel is referred by a non-negative integer identifier. To send or fetch a message to or from a message queue, we need to know the identifier.

2) Ipc identifiers are not small integers.


3) When a given ipc structure is created or removed, the identifier associated with that structure continually increases until it reaches maximum positive value for an integer, and then wraps around to 0.

Slot usage sequence number:The identifier is remembered even after the ipc_structure is deleted, and increemented each time the structure is used. This is called slot usage sequence number. Whenever an ipc structure is created, a key must be specified. The data type of this key is primitive system/data type key_t, which is often defined as long integer in the header <sys/types.h>. This key is converted into the identifier by the kernel. New ipc structure is created if either 1)Key is IPC_PRIVATE. 2)Key is currently associated with an ipc structure of particular type and the IPC_CREAT bit of a flag is specified.

INITIALIZATIONS FOR NEW MESSAGE QUEUE


When a new message Queue is created the following members of the msqid_ds structure are initialized.
1) Mode is specified from corresponding permission bits. Permissions User read User write GROUP READ GROUP WRITE OTHER READ OTHER WRITE message queues MSG_R MSG_W MSG_R>>3 MSG_W>>3 MSG_R>>6 MSG_W>>6

2) msg_qnum, msg_lspid msg_lrpid msg_stime msg_rtime are all set to 0 3) msg_ctime is set to the current time. 4) msg_qbytes is set to the system limit.

Msgctl
The msgctl function performs various options on a queue. #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> Int msgctl( int msqid, int cmd, struct msqid_ds *buf); Returns O if ok. -1 on error. Arguments The cmd argument specifies the command to be performed, on the queue specified by msqid. IPC_STAT, IPC_SET, IPC_RMID IPC_STAT:Fetch the msqid_ds structure for this message queue storing it in the structure pointed to by buf.

IPC_SET:Sets the following four field 1) msg_perm.uid


2) msg_perm.gid 3) msg_perm.mode 4) msg_qbytes IPC_RMID:Removes the message queue from the system and any data still on the queue. This removal is immediate. IPC_SET & IPC_STAT:This can be executed only by the process whose Effective user id==msg_perm.uid Or by a process with super user privilleges

Msgsnd:Data is placed onto a message queue by calling msgsnd #include<sys/types.h> #include<sys/ipc.h> #include<sys/msg.h> Int msgsnd( int msqid, const void *ptr, size_t nbytes, int flag); Returns 0 if ok -1 on error Arguments :Ptr points to a long integer that contains the positive integer message type and it is immediately followed by the message type. Struct my_mesg { long mtype; /* positive message type */ Char mtext[512]; /* message data, of length nbytes */ }; Ptr is pointer to structure my_mesg.

Msgrcv:Messages are retrived from a queue by msgrcv #include<sys/ipc.h> #include<sys/types.h> #include<sys/msg.h> Int msgrcv( int msqid, void *ptr,size_t nbytes, long type, int flag); Returns Size of data portion of message if ok -1 on error. msgrcv(msgid,(void *) &some_data, BUFSIZ, msg_to_receive, 0) The type argument lets us specify which message we want Type==0 the first message on the queue is returned. Type>o the first message on queue whose message type == type is returned. the first message on the queue whose message type is the lowest value less than or equal to the absolute value of type is returned

Type <0

semaphore
Semaphore value is stored in the kernel. To obtain a shared resource, a process needs to do the following: 1. Test the semaphore that controls the resource.
2. If the value of the semaphore is positive, the process can use the resource. In this case, the process decrements the semaphore value by 1, indicating that it has used one unit of the resource. Otherwise, if the value of the semaphore is 0, the process goes to sleep until the semaphore value is greater than 0. When the process wakes up, it returns to step 1. When a process is done with a shared resource that is controlled by a semaphore, the semaphore value is incremented by 1. If any other processes are asleep, waiting for the semaphore, they are awakened.

3.

4.

semaphore
Semaphore value is stored in the kernel. Steps to obtain a shared resource by a process. 1. Test the semaphore that controls the resource. 2. value of the semaphore is positive. process decrements the semaphore value by 1. 3. value of the semaphore is 0, process goes to sleep. until the semaphore value is greater than 0 4. process is done with a shared resource that is controlled by a semaphore, the semaphore value is incremented by 1

Fig:- semaphore value stored in the kernel

Process A

Process B

Semaphore

0 or 1

kernel

kernel

Struct semid_ds semid

Sem_perm strucutre

semval sempid

semncnt
Sem_base Sem_nsems Sem_otime semzcnt semval sempid semcnt semzcnt

Sem_ctime
Fig:- Kernel data structure for semaphore set

binary semaphore: It controls a single resource, and its value is initialized to 1. In general, however, a semaphore can be initialized to any positive value, with the value indicating how many units of the shared resource are available for sharing. The kernel maintains a semid_ds structure for each semaphore set: struct semid_ds { struct ipc_perm sem_perm; Struct sem *sem_base; unsigned short sem_nsems; time_t sem_otime; time_t sem_ctime; . . . };

/* permissions */ /* ptr to first semaphore in the set */ /* # of semaphores in set */ /* last-semop() time */ /* last-change time */

Struct { unsigned short semval; /* semaphore value, always >= 0 */ pid_t sempid; /* pid for last operation */ unsigned short semncnt; /* # processes awaiting semval>curval */ unsigned short semzcnt; /* # processes awaiting semval==0 */ . . . }; System limits that effect semophore sets SEMVMX: The maximum value of any semaphore SEMAEM: The maximum value of any semaphore's adjust-on-exit value SEMMNI: The maximum number of semaphore sets, systemwide SEMMNS: The maximum number of semaphores, systemwide SEMMSL: The maximum number of semaphores per semaphore set SEMMNU: The maximum number of undo structures, systemwide SEMUME: The maximum number of undo entries per undo structures SEMOPM: The maximum number of operations per semop call

The first function to call is semget to obtain a semaphore ID. #include <sys/sem.h> int semget(key_t key, int nsems, int flag); Returns: semaphore ID if OK, -1 on error The mode member of this structure is set to the corresponding permission bits of flag. sem_otime is set to 0. sem_ctime is set to the current time. sem_nsems is set to nsems.

The semctl function is the catchall for various semaphore operations. #include <sys/sem.h> int semctl(int semid, int semnum, int cmd,... /* union semun arg */); Returns : For all the GET commands other than GETALL the function returns the corresponding value For remaining commands the return value is 0.

The fourth argument is optional, depending on the command requested. The value of semnum is 0 to nsems-1.
union semun { int val; /* for SETVAL */ struct semid_ds *buf; /* for IPC_STAT and IPC_SET */ unsigned short *array; /* for GETALL and SETALL */ };

For cmd argument IPC_STAT Fetch the semid_ds structure for this set, storing it in the structure pointed to by arg.buf. GETVAL Return the value of semval for the member semnum. SETVAL Set the value of semval for the member semnum. The value is specified by arg.val. GETPID Return the value of sempid for the member semnum. GETNCNT Return the value of semncnt for the member semnum. IPC_SET
Set the 1) sem_perm.uid, 2) sem_perm.gid, and 3) sem_perm.mode fields from the structure pointed to by arg.buf

IPC_RMID: Remove the semaphore set from the system. This removal is
immediate

The function semop atomically performs an array of operations on a semaphore set.

#include <sys/sem.h> int semop(int semid, struct sembuf semoparray[], size_t nops); Returns: 0 if OK, 1 on error
The semoparray argument is a pointer to an array of semaphore operations, represented by sembuf structures:

struct sembuf { unsigned short sem_num; /* member # in set (0, 1, ..., nsems-1) */ short sem_op; /* operation (negative, 0, or positive) */ short sem_flg; /* IPC_NOWAIT, SEM_UNDO */ }; The nops argument specifies the number of operations (elements) in the array.

Shared Memory
Shared memory allows two or more processes to share a given region of memory

This is the fastest form of IPC, because the data does not need to be copied between the client and the server. If the server is placing data into a shared memory region, the client shouldn't try to access the data until the server is done. Often, semaphores are used to synchronize shared memory access

struct shmid_ds { struct ipc_perm shm_perm; /* Permissions */ size_t shm_segsz; /* size of segment in bytes */ pid_t shm_lpid; /* pid of last shmop() */ pid_t shm_cpid; /* pid of creator */ shmatt_t shm_nattch; /* number of current attaches */ time_t shm_atime; /* last-attach time */ time_t shm_dtime; /* last-detach time */ time_t shm_ctime; /* last-change time */ : : : };

client

server

Output file

FIFO, pipe or message

Input file

Fig:- typical movement of data between client and server

client

Shared memory

server

Output file

Input file

Fig: movement of data between client and server using shared memory

The first function called is usually shmget, to obtain a shared memory identifier. #include <sys/shm.h> int shmget(key_t key, size_t size, int flag); Returns: shared memory ID if OK, -1 on error

The shmctl function is the catchall for various shared memory operations. #include <sys/shm.h> int shmctl(int shmid, int cmd, struct shmid_ds *buf); Returns: 0 if OK, -1 on error
The cmd argument specifies one of the following five commands to be performed, on the segment specified by shmid. IPC_STAT Fetch the shmid_ds structure for this segment, storing it in the structure pointed to by buf. IPC_SET Set the following three fields from the structure pointed to by buf in the shmid_ds structure associated with this shared memory segment: shm_perm.uid, shm_perm.gid, and shm_perm.mode. This command can be executed only by a process whose effective user ID equals shm_perm.cuid or shm_perm.uid or by a process with superuser privileges.

IPC_RMID Remove the shared memory segment set from the system.
Since an attachment count is maintained for shared memory segments (the shm_nattch field in the shmid_ds structure), the segment is not removed until the last process using the segment terminates or detaches it.

SHM_LOCK Lock the shared memory segment in memory. This command


can be executed only by the superuser.

SHM_UNLOCK Unlock the shared memory segment. This command can


be executed only by the superuser.

System limits that effect shared memory SHMMAX: The maximum size in bytes of a shared memory segment. SHMMIN: The minimum size in bytes of a shared memory segment SHMMNI: The maximum number of shared memory segments,
systemwide.

SHMSEG:
process

The maximum number of shared memory segments, per

Once a shared memory segment has been created, a process attaches it to its address space by calling shmat. #include <sys/shm.h> void *shmat(int shmid, const void *addr, int flag); Returns: pointer to shared memory segment if OK, -1 on error

The address in the calling process at which the segment is attached depends on the addr argument and whether the SHM_RND bit is specified in flag. If addr is 0, the segment is attached at the first available address selected by the kernel. This is the recommended technique. If addr is nonzero and SHM_RND is not specified, the segment is attached at the address given by addr. If addr is nonzero and SHM_RND is specified, the segment is attached at the address given by (addr - (addr modulus SHMLBA)). The SHM_RND command stands for "round." SHMLBA stands for "low boundary address multiple" and is always a power of 2. What the arithmetic does is round the address down to the next multiple of SHMLBA.

#include <sys/shm.h> int shmdt(void *addr); Returns: 0 if OK, -1 on error The addr argument is the value that was returned by a previous call to shmat. If successful, shmdt will decrement the shm_nattch counter in the associated shmid_ds structure. The addr argument is the value that was returned by a previous call to shmat. If successful, shmdt will decrement the shm_nattch counter in the associated shmid_ds structure.

Namespaces
The set of possible names for a given type of IPC is called its namespace.

Ipc_type
Pipe FIFO Message queue Shared memory Semaphore Socked (unix domain) Socket (other domain)

Name space
(no name) Pathname Key_t key Key_t key Key_t key Pathname (domain dependent)

identification
File descriptor File descriptor Identifier Identifier Identifier File descriptor File descriptor

The function ftok() is provided by the system V standard C library to convert the pathname and project identifier into a system V IPC. #include<sys/types.h> #include<sys/ipc.h> Key_t ftok( char *pathname, char proj); Key_t is a 32 bit integer.

Char *path Char proj

Ftok()

Key_t key

Msgget() Semget() Shmget()

Int id

Fig:-generating IPC id`s using ftok()

Start here

OK CREATE NEW ENTRY RETURN ID Error return

Key==IPC_PRIVATE no

yes

System tables full ?

Errno=ENOSPC

DOES KEY ALREADY EXIST


yes Are both IPC_CREAT and IPC_EXCL set? no Is the acess permission OK ? yes Ok return id

no

IPC_CREAT set?

Error return Errno=ENOENT

yes

Error return Errno=EEXIST

no

Error return Errno=EACESS

Fig:- Logic for opening or creating an IPC channel.

MESSAGE QUEUES Include file System call to create or open System call to create or open System calls for IPC operations <sys/msg.h> Msgget Msgctl Msgsnd Msgrcv

SEMAPHORE SHARED MEMORY <sys/sem.h> semget Semctl semop <sys/shm.h> Shmget Shmctl Shmat shmdt

Fig:- summary of System V IPC system calls

Permission
User read User write(alter) Group read Group-write(alter)

Message queue MSG_R MSG_W MSG_R>>3 MSG_W>>3

Semaphore Shared memory SEM_R SHM_R SEM_W SHM_R SEM_R>>3 SHM_R>>3 SEM_R>>3 SHM_W>>3

Other read Other write( alter)

MSG_R>>6 MSG_R>>6

SEM_R>>6 SHM_R>>6 SEM_R>>6 SHM_W>>6

FIG:- System V IPC permissions

You might also like