struct ipc_namespace {

I have omitted a large number of elements devoted to observing resource consumption and setting resource limits. The kernel, for instance, restricts the maximum number of shared memory pages, the maximum size for a shared memory segment, the maximum number of message queues, and so on. All restrictions apply on a per-namespace basis and are documented in the manual pages msgget(2), shmget(2), and semget(2), so I will not discuss them further here. All are implemented by simple counters.

More interesting is the array ids. One array position per IPC mechanism — shared memory, semaphores, and messages — exists, and each points to an instance of struct ipc_ids that is the basis to keep track of the existing IPC objects per category. To prevent getting lost in search of the proper array index per category, the kernel provides the auxiliary functions msg_ids, shm_ids, and sem_ids. But just in case you were wondering, semaphores live in position 0, followed by message queues and then by shared memory.

struct ipc_ids is defined as follows: ipc/util.h struct ipc_ids {

int in_use; unsigned short seq; unsigned short seq_max; struct rw_semaphore rw_mutex; struct idr ipcs_idr;

The first elements hold general information on the status of the IPC objects:

□ in_use holds the number of IPC objects currently in use.

□ seq and seq_id allow generating userspace IPC identifiers sequentially. Note that the identifiers are not identical with the sequence numbers, though. The kernel identifies an IPC object internally with an identifier managed per resource type, that is, one identifier for message queues, one for semaphores, and one for shared memory objects. Each time a new IPC object is created, the sequence number is incremented by 1 (wrapping is handled automatically).

The identifier visible to userland is given by s*SEQ_MULTiPLiER+i, where s is the current sequence number and i is the kernel-internal identifier. The sequence multiplier is set to the upper limit for IPC objects. If an internal ID is reused, a different userspace identifier is generated this way because the sequence number is reused. This minimizes the risk of using a wrong resource when a stale ID is passed from userland.

□ rw_mutex is a kernel semaphore. It is used to implement semaphore operations and safeguards against race conditions in userspace. The mutex appropriately protects the data structures that contain, for instance, the semaphore value.

Each IPC object is represented by an instance of kern_ipc_perm to which we come in a moment. Each object has a kernel-internal ID, and ipcs_idr is used to associate an ID with a pointer to the corresponding kern_ipc_perm instance. Since the number of used IPC objects can grow and shrink dynamically, a static array would not serve well to manage the information, but the kernel provides a radix-tree-like (see Appendix C) standard data structure in lib/idr.c for this purpose. How the entries are managed in detail is not relevant for our purposes; it suffices to know that each internal ID can be associated with the respective kern_ipc_perm instance without problems.

The elements of kern_ipc_perm hold information on semaphore "owners" and on access permissions. <ipc.h>

struct kern_ipc_perm {















unsigned long


The structure can be used not only for semaphores but also for other IPC mechanisms. You will come across it frequently in this chapter.

□ key holds the magic number used by user programs to identify the semaphore, and id is the kernel-internal identifier.

□ uid and gid specify the user and group ID of the owner. cuid and cgid hold the same data for the process that generated the semaphore.

□ seq is a sequence number that was used when the object was reserved.

□ mode holds the bitmask, which specifies access permissions in accordance with the owner, group, others scheme.

The above data structures are not sufficient to keep all information required for semaphores. A special per-task element is required:

Continue reading here: Semh

Was this article helpful?

0 0