3.5. POSIX vs. System V IPC¶

Throughout this book, we try to focus on platform-independent concepts and code examples as much as possible. In particular, we tend to focus on the POSIX interface specification, given its broad base of support across the major modern OS. IPC is the exception that proves the rule. Some OS (e.g., macOS in particular) provide little or no support for POSIX IPC; instead, these OS uses the System V interface for IPC. In this section, we will continue to focus on POSIX and describe the relevant interfaces for message queues, semaphores, and shared memory. Appendix B describes the System V IPC interfaces for reference and comparison.

Bug Warning

POSIX IPC code will not work successfully on macOS. macOS does not provide the required header files for POSIX message queues, so the code will not successfully compile. Even worse, macOS provides the header files for POSIX unnamed semaphores (allowing the code to compile), but the implementation consists of empty stub functions. That is, the semaphore functions will simply return without actually acting like semaphores. To avoid these issues, code intended to run on macOS should use the System V IPC interface instead. Pre-processor directives can be used to switch between the code required at compile time.

3.5.1. POSIX IPC Fundamentals¶

All POSIX IPC functions identify and refer to IPC objects with a string that adheres to a given format. The string must start with an initial slash, then have one or more non-slash characters. For instance, /OpenCSF_mqueue is a valid name, presumably for a message queue. Each object’s name must be unique, so application designers need to ensure that any name they choose is unlikely to conflict with other applications.

IPC objects are often represented as a file within a particular directory in the file system. In Linux, information related to the /OpenCSF_mqueue message queue would be stored in /dev/mqueue/OpenCSF_mqueue, for example. These files can be accessed using the standard file commands, such as ls, cat, or rm. However, manipulating these files with these standard utilities may cause unexpected behavior, as running processes may be relying on these files.

In addition to a name, all of the functions for opening a POSIX IPC connection accept at least two other bit mask parameters: oflag and mode. The oflag parameter specifies the requested access needed (O_RDONLY, O_WRONLY, O_RDWR); note that these are identical to the standard options for opening a file with open(). Similarly, the mode parameter uses the standard file permissions (e.g., S_IRUSR, S_IWGRP) to set the permissions on a newly created object.

If a new object is being created, the O_CREAT flag must be included in the oflag bit mask. If O_CREAT is omitted and the object does not exist, an error will be returned. In addition, the O_EXCL flag controls the behavior when attempting to create an object, but one with the specified name already exists. If O_EXCL is included and an object exists, the open fails and an error is returned. If O_EXCL is omitted, no object is created, but the open returns a connection to the existing object. Note that passing O_EXCL without O_CREAT is undefined in the POSIX specification and should not be used. The following examples illustrate how to use these options:

• shm_open ("/shared_mem", O_CREAT | O_RDWR, S_IWUSR | S_IRGRP);
Create and/or open shared memory; if it doesn’t exist, set permissions to 0420 (user has write, group has read).
• shm_open ("/shared_mem", O_CREAT | O_EXCL, S_IWUSR | S_IRUSR);
Create but do not open shared memory with 0600 permissions. Fail if it already exists.
• shm_open ("/shared_mem", O_RDONLY);
Open a read-only connection to shared memory. If it does not exist, fail.

Bug Warning

The POSIX IPC implementations are typically provided within the POSIX Real-time Library (librt). As such, the -lrt flag must be passed to gcc when compiling and linking programs that use these mechanisms.