Signals and Message Queues
April 8, 2013 Inter-Process Communication • Why IPC? Allows for processes to work together, but remain otherwise isolated.
• Segment-based IPC – Ex: memory-mapped files, shared memory
• Stream-based IPC – Ex: pipes, fifos, network sockets
• Message-based IPC – Ex: signals, message queues, message passing Signals are “events” • Signals communicate asynchronous events Signal Event Default Action SIGINT “Interactive Attention” (usually Ctrl+C) Process termination SIGSEGV Non-mapped Memory Access (seg. fault) Process termination SIGTERM Request for process termination (eg: Process termination system is being shut down) SIGCHLD Child process terminated, stopped, or Nothing (ignored) continued SIGSTOP* Stops process execution Stop SIGKILL* Kills process Process termination SIGALRM System alarm clock expired Process termination SIGUSR1 User-defined event Process termination SIGUSR2 User-defined event Process termination
Inter-Process Communication • On Friday, we replaced the default signal handler with a custom-defined signal handler.
• Problem: What if we get a signal while we are in our signal handler? Signal Mask • A signal mask is a mask that will preserve the existence of a signal, but block it from being handled until the mask is removed.
INT QUIT SEGV TERM USR1 USR2 Signal Bitmap: 0 0 0 0 1 0 ... Signal Mask: 1 0 1 0 1 0 ...
Every process has its own unique signal bitmap and mask! Modifying the Signal Mask
Examine and change blocked signals: sigprocmask(int how, const sigset_t *set, sigset_t *oldset);
Manipulate the sigset_t set: sigemptyset(sigset_t *set); sigfullset (sigset_t *set); sigaddset (sigset_t *set, int sig); sigdelset (sigset_t *set, int sig); sigismember(sigset_t *set, int sig);
Signal Handlers and Signal Masks • As part of installing a custom signal handler, we also specify a custom signal mask to be applied while we handle the signal. How? • Using the easy way to handle a signal, using signal(): – The signal mask applied to our signal handler blocks only the signal that was delivered.
• The proper way: int sigaction( int signum, struct sigaction *act, struct sigaction *oldact);
struct sigaction { void (*sa_handler)(int); sigset_t sa_mask; ... };
A Signal’s Lifecycle Code Example void handler(int sig) { printf(“In signal handler!”); while (1) { } } int main() { signal(SIGINT, handler); while (1) { } return 0; } Some Other Common Uses of Signals
• System Call: int alarm(int seconds) – Set an alarm clock for the delivery of a signal. – Usage: Log system state every X seconds to a log file.
• Debugging: Many programs use a signal to print debugging information. – In Java: Pressing Ctrl+\ (SIGQUIT) on a Java process will print out the current state of every thread.
• Interrupting blocking calls: Many C system calls will return if a signal is delivered to your process. – Eg: write(), sleep(), etc. Common Interview Question
• If they only IPC mechanism you have are signals, how can I create a program to send a long message (eg: any string) from a server to a client? Message Queues • The POSIX solution to passing a message: message queues. – Multiple processes register to the same message queue using mq_open().
– A process sends a message with mq_send(). • Sends a string up to a system-defined length (~8 KB)
– A process can receive a message by: • Calling mq_receive(), a blocking call. • Calling mq_notify(), setting up for a signal to be sent when a message is received. Message Queues • Why are message queues rarely used?