2.3.3. Message Passing

Message passing is a mechanism that can send a message from one process to another. The advantage of message passing is that it can be used between processes on a single system as well as between processes on multiple systems connected by a network without having to change the interface between the processes and message passing.

Message passing is synchronous when the procedure that sends a message can not return until the message is received. Message passing is asynchronous when the procedure that sends a message can return before the message is received.

The procedures that send or receive a message are blocking when they can wait before returning, and non blocking when they do not wait before returning. When a non blocking procedure needs to wait, it can replace blocking by polling or callbacks.

Message passing can use symmetrical, asymmetrical and indirect addressing. The symmetrical addressing requires both the sender and the receiver to specify the address of the other party. The asymmetrical addressing requires the sender to specify the address of the receiver. The indirect addressing requires both the sender and the receiver to specify an address of the same message queue.

The message sent from the sender to the receiver can be anything from a single integer number through an unformatted stream of bytes to a formatted structure of records.

2.3.3.1. Example: Posix Signals

Signals are messages that can be delivered to processes or threads. A signal is identified by a number, with numbers from 1 to 31 allocated to standard signals with predefined meaning and numbers from SIGRTMIN to SIGRTMAX allocated to real time signals.

Figure 2.14. Standard Signals

NameNumberMeaning
SIGHUP1Controlling terminal closed
SIGINT2Request for interrupt sent from keyboard
SIGQUIT3Request for quit sent from keyboard
SIGILL4Illegal instruction
SIGTRAP5Breakpoint instruction
SIGABRT6Request for abort
SIGBUS7Illegal bus cycle
SIGFPE8Floating point exception
SIGKILL9Request for kill
SIGUSR110User defined signal 1
SIGSEGV11Illegal memory access
SIGUSR212User defined signal 2
SIGPIPE13Broken pipe
SIGALRM14Timer alarm
SIGTERM15Request for termination
SIGTERM16Illegal stack access
SIGCHLD17Child process status changed
SIGCONT18Request to continue when stopped
SIGSTOP19Request to stop
SIGTSTP20Request for stop sent from keyboard
SIGTTIN21Input from terminal when on background
SIGTTOU22Output to terminal when on background

Signals are processed by signal handlers. A signal handler is a procedure that is called by the operating system when a signal occurs. Default handlers are provided by the operating system. New handlers can be registered for some signals.

Figure 2.15. Signal Handler Registration System Call

typedef void (*sighandler_t) (int);

sighandler_t signal (int signum, sighandler_t handler);
  • SIG_DFL - use default signal handler

  • SIG_IGN - ignore the signal

struct sigaction
{
  void (*sa_handler) (int);
  void (*sa_sigaction) (int, siginfo_t *, void *);
  sigset_t sa_mask;
  int sa_flags;
}

struct siginfo_t
{
  int      si_signo;    // Signal number
  int      si_errno;    // Value of errno
  int      si_code;     // Additional signal code
  pid_t    si_pid;      // Sending process PID
  uid_t    si_uid;      // Sending process UID
  int      si_status;   // Exit value
  clock_t  si_utime;    // User time consumed
  clock_t  si_stime;    // System time consumed
  sigval_t si_value;    // Signal value
  int      si_int;      // Integer value sent with signal
  void *   si_ptr;      // Pointer value sent with signal
  void *   si_addr;     // Associated memory address
  int      si_fd;       // Associated file descriptor
}

int sigaction (int signum, const struct sigaction *act, struct sigaction *oldact);
  • sa_handler - signal handler with limited arguments

  • sa_sigaction - signal handler with complete arguments

  • sa_mask - what other signals to mask while in signal handler

  • SA_RESETHAND - restore default signal handler after one signal

  • SA_NODEFER - allow recursive invocation of this signal handler

  • SA_ONSTACK - use alternate stack for this signal handler


Due to the ability of signals to interrupt processes at arbitrary times, the actions that can be taken inside a signal handler are severely limited. Access to shared variables and system calls are not safe in general. This can be somewhat alleviated by masking signals.

Figure 2.16. Signal Masking System Call

int sigprocmask (int how, const sigset_t *set, sigset_t *oset);
int pthread_sigmask (int how, const sigset_t *set, sigset_t *oset);
  • SIG_BLOCK - add blocking to signals that are not yet blocked

  • SIG_UNBLOCK - remove blocking from signals that are blocked

  • SIG_SETMASK - replace existing mask


Signals are usually reliable, even though unreliable signals did exist. Signals are delivered asynchronously, usually on return from system call. Multiple instances of some signals may be queued.

Figure 2.17. Signal Send System Call

int kill (pid_t pid, int sig);
int pthread_kill (pthread_t thread, int sig);

union sigval
{
  int sival_int;
  void *sival_ptr;
}

int sigqueue (pid_t pid, int sig, const union sigval value);

2.3.3.2. Example: System V Message Passing

Jako první příklad message passing lze asi uvést System V message passing API. Zpráva tam vypadá jednoduše, na začátku je long message type, za ním následuje pole bajtů, jejichž délka se udává jako další argument při volání API. Volání jsou pak triviální:

int msgsnd (int que, message *msg, int len, int flags);
int msgrcv (int que, message *msg, int len, int type, int flags);

Při odesílání zprávy lze specifikovat, zda se má při zaplnění bufferu zablokovat volající proces nebo vrátit chyba, jako drobný detail i zablokovanému volajícímu procesu se může vrátit chyba třeba pokud se zruší message queue.

Při příjmu zprávy se udává maximální velikost bufferu, flagy říkají zda se větší zprávy mají oříznout nebo zda se má vrátit chyba. Typ zprávy může být buď 0, což znamená any message, nebo konkrétní typ, pak se ve flazích dá říci zda se vrátí první zpráva uvedeného nebo jiného než uvedeného typu. Záporný argument pak znamená přijmout zprávu s nejnižším typem menším než je absolutní hodnota argumentu. Ve flazích se samozřejmě dá také říci, zda se čeká na zprávu.

Adresuje se pomocí front zpráv. Fronta se vytvoří voláním int msgget (key, flags), ve kterém se uvádí identifikátor fronty a flagy. Identifikátor je globální, případně může mít speciální hodnotu IPC_PRIVATE, která zaručuje vytvoření nové fronty. Přístup ke frontě ovlivňují access rights ve flazích, ty jsou stejné jako například u souborů.

int msgget (key_t key, int msgflg);

2.3.3.3. Example: D-Bus Message Passing

To be done.

2.3.3.4. Example: Mach Message Passing

V Machu jsou procesy vybaveny frontami zpráv spravovanými kernelem, těmto frontám se říká porty. Oprávnění k práci s portem jsou uložena v tabulkách pro každý proces spravovaných kernelem, těmto oprávněním se říká capabilities. Proces identifikuje port jeho handlerem, což je index do příslušné tabulky capabilities. Capability může opravňovat číst z portu, zapisovat do portu, nebo jednou zapsat do portu. Pouze jeden proces může mít právo číst z portu, to je jeho vlastník. Při startu je proces vybaven několika významnými porty, například process portem pro komunikaci s kernelem, syscalls jsou pak posílání zpráv na tento port.

Zpráva v Machu se skládá z hlavičky, ta obsahuje destination a reply port handler, velikost zprávy, kernelem ignorované message kind a function code pole, a potom posloupnost datových polí tvořících zprávu. Zvláštností Machu je, že data zprávy jsou tagged, tedy před každou položkou je napsáno co je zač. Tag obsahuje out of line flag, velikost dat v počtu položek, velikost položky v bitech, a konečně typ položky, ten je ze standardních typů plus handler portu. Kernel interpretuje předání handleru portu jako předání příslušné capability.

Pro odeslání a příjem zpráv slouží volání mach_msg, to má jako argument adresu hlavičky zprávy, flags s bity jako expect reply, enable timeout, enable delivery notification, velikost zprávy, velikost místa na odpověď, plus porty.