Unit 8: Inter Process Communication
Unit 8: Inter Process Communication
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].
Fd[0]
Fd[1]
pipe
kernel
pipe
pipe
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); }
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
child
Stdin
fp
Filter program
stdout stddin
prompt
User input
User at a terminal
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)
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.
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.
PROG3
PROG1
tee PROG2
SERVER
READ REQUEST
WRITE
WRITE CLIENT
CLIENT
SERVER Write req READ REQUEST FIFO client specific FIFO client specific WRITE CLIENT CLIENT Read replies Write req
Read replies
WRITE
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.
link
Type=300 Length=1
link
Type=200 Length=1
Length=1
data
data
data
Msg_first Msg_last
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.
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.
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.
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.
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
Process A
Process B
Semaphore
0 or 1
kernel
kernel
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
#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
Input file
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.
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
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.
Ftok()
Key_t key
Int id
Start here
Key==IPC_PRIVATE no
yes
Errno=ENOSPC
no
IPC_CREAT set?
yes
no
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
Permission
User read User write(alter) Group read Group-write(alter)
Semaphore Shared memory SEM_R SHM_R SEM_W SHM_R SEM_R>>3 SHM_R>>3 SEM_R>>3 SHM_W>>3
MSG_R>>6 MSG_R>>6