Next Previous Contents

5. System V IPC

5.1 Introduction

System V IPC is meant to provide and entire IPC mechanism. As such, it is more heavyweight than BSD mmap, and provides three methods of communication: message queues, semaphores, and shared segments. Like BSD mmap, System V IPC uses files to identify shared segments. Unlike BSD, System V uses these files only for naming. Ther contents have nothing to do with the initialization of the shared segment.

5.2 Common Ground

The three System V IPC mechanisms share some common ground when it comes to creation and permissions. This section will attempt to give you an overview the creation process.

Synopsis

#include <sys/types.h>
#include <sys/ipc.h>

key_t ftok(char *pathname, char proj);
IPC_PRIVATE

struct ipc_perm
{
   key_t  key;
   ushort uid;   /* owner euid and egid */
   ushort gid;
   ushort cuid;  /* creator euid and egid */
   ushort cgid;
   ushort mode;  /* lower 9 bits of access modes */
   ushort seq;   /* sequence number */
};

IPC_CREAT
IPC_EXCL

        

Description

All three IPC methods provided by the System V IPC are assocated with system-wide integers, called keys. While it is not required, these keys are traditionnaly obtained via ftok(2). ftok(2) takes a filename and a project argument to generate a unique key that describes an instance of an IPC mechanism. The project argument allows you to have multiple IPC mechanisms associated with the same filename. You may also specify a key of IPC_PRIVATE that will be used only by your process and it's children.

When you request an IPC instance using an appropriate key value, you may specify the flags IPC_EXCL and IPC_CREAT. If you specify IPC_CREAT, if a segment for the key does not exist, it is created. If you also specify IPC_EXCL, you are guanteed a new segment or an error will be returned. (It doesn't not prevent others from requesting the segment as well).

Permissions are set upon requesting a segment, and are in the traditional UNIX rwx bitwise scheme. That is:

#define PERM_UREAD      0400
#define PERM_UWRITE     0200
#define PERM_GREAD      0040
#define PERM_GWRITE     0020
#define PERM_OREAD      0004
#define PERM_OWRITE     0002
        

5.3 Shared segments

Synopsys

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int shmget(key_t key, int size, int shmflg);
void *shmat(int shmid, const void *shmaddr, int shmflg);
int shmdt(const void *shmaddr);
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
IPC_STAT
IPC_SET
IPC_RMID
struct shmid_ds;
            

Overview

Shared segments in System V are a bit different than those obtained with BSD's mmap. First of all, while you do need a key for a segment which is usually obtained by running ftok(2) on some file in the filesyetem, System V shared segments exist only in memory. Because of this, System V shared segments must persist after the termination of a process. It is the responsibility of the programmer to ensure that all of his segments are removed from the system, otherwise his memory leaks become system wide.

Creation

To create a shared memory segment, you must use the shmget(2) system call. It takes a key, a size, and a flag paramater and returns an integer id for your segment. The flag can be combinations of IPC_CREAT and IPC_EXCL, as well as the permissions bits on the segment as described above.

Usage

Once the segment is created and you have it's id, you must attach it, or map it into memory. This is done with shmat(2). shmat works much the same as mmap in that you can specify an address to map to, but the address must be a multiple of SHMLBA, unless you specify SHM_RND in the flags paramater.

Various operations can be performed using shmctl(2) IPC_STAT can be used to fill in the struct shmid_ds structure. You can then set various fields (including changing ownership and premissions of ipc_perm) using IPC_SET. But perhaps the most important ctl operation is IPC_RMID. When all of your programs are done using a segment, you MUST shmctl it with IPC_RMID (the shmid_ds structure may be NULL), or else the segment will remain in memory forever.

5.4 Message Queues

Overview

Message queues provide a memory based FIFO between two processes. The primary difference between a System V message queue and a socket or named pipe is that message queues may have multiple processes reading and writing from and to them, or no readers at all.

Synopsys

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/msg.h>

int msgget(key_t key, int msgflg);
int msgsnd(int msgid, struct msgbuf *msgp, int msgsz,
       int msgflg);

int msgrcv(int msgid, struct msgbuf  *msgp,  int  msgsz,
       long msgtyp, int msgflg );

struct msgbuf {
    long mtype;     /* message type, must be > 0 */
    char mtext[msgsz];  /* message data */
};

MSGMAX
MSGMNB

int msgctl(int msqid, int  cmd, struct msqid_ds *buf);
IPC_STAT
IPC_SET
IPC_RMID
struct msgid_ds;

            

Creation

Much like for shared memory, you must create a message queue using the msgget(2) system call. It takes a key and a flag paramater and returns an integer id for your segment. The flag can be combinations of IPC_CREAT and IPC_EXCL, as well as the permissions bits on the segment as described above.

Usage

The System V IPC provides two symmetric system calls for sending and receiving messages: msgsnd and msgrcv respectively.

5.5 Semaphores

Synopsys

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget ( key_t key, int nsems, int semflg );
int semop ( int semid, struct sembuf *sops, unsigned nsops);
struct sembuf {
            short sem_num;  /* semaphore number: 0 = first */
            short sem_op;   /* semaphore operation */
            short sem_flg;  /* operation flags */
};

int  semctl  (int  semid, int semnum, int cmd, union semun arg);
  union semun {
               int val;                    /* value for SETVAL */
               struct semid_ds *buf;       /* buffer for IPC_STAT, IPC_SET */
               unsigned short int *array;  /* array for GETALL, SETALL */
               struct seminfo *__buf;      /* buffer for IPC_INFO */
       };

IPC_STAT
IPC_SET
IPC_RMID
GETALL
SETALL
SETVAL
struct semid_ds;
            

Overview

Semaphores are data structures that are used for synchronization between two or more processes. Basically they can be viewed as a single integer that represents the amout of resources avaialable. When a process wants a resource, it checks the value of the semaphore, and if it it nonzero, it decrements the appropriate number from the semaphore in accordance to the amout of resources it wishes to use. The kernel will block the process if the semaphore is zero or doesn't have a value high enough for the decrement. In System V IPC, you may request a set or an array of semaphores at once.

Creation

To create a set of semaphores, you must use the semget(2) system call. It takes a key, a number of semaphores to create, and a flag paramater and returns an integer id for your segment. The flag can be combinations of IPC_CREAT and IPC_EXCL, as well as the permissions bits on the segment as described above.

Usage

Once you call semget and have the semaphore set's ID, you can perform operations on this set using semop(2). The struct sembuf has fields that are filled in to represent the requested action on the semaphore. The first field specifies the number of the semaphore in the set you wish to operate on. The second field (sem_op) contains the operation you wish to do. If sem_op is positive, the value is added to the semaphore (ie release of resources). If sem_op is less than or equal to zero, semop(2) will block until the semaphore reaches abs(sem_op). You may also specify various options in sem_flg, including IPC_NOWAIT, which tells semop(2) NOT to block. When SEM_UNDO is specified, all actions are undone when the current process exits. Undo is guaranteed with private semaphores only.

Notice that unlike the other IPC operations, the third argument to semctl is a union, not a simple struct. This is because the various options must occurr on different data. Various operations can be performed using semctl(2) IPC_STAT can be used to fill in the struct semid_ds structure. You can then set various fields (including changing ownership and premissions of ipc_perm) using IPC_SET. But perhaps the most important ctl operation is IPC_RMID. When all of your programs are done using a semaphore, you MUST semctl it with IPC_RMID (the shmid_ds structure may be NULL), or else the semaphore will remain in memory forever. You may also set and get specific values of the semaphore using GETVAL, SETVAL, GETALL, and SETALL.


Next Previous Contents