Difference Between Posix Reliable Signals and Posix Real-Time Signals in Linux

Are pthread condition signals the same or different from POSIX real-time signals?

Though the term "signal" is used when speaking of both mechanisms, POSIX realtime signals and pthread condition variables are different.

POSIX or operating signals are "software interrupts" with relatively rich semantics and history. They may be ignored (SIG_IGN), delivered (sa_sigaction), accepted, or blocked, except when they can't be. They may have their own stack for user-defined disposal, though what one can safely do during disposal is quite limited. They might take aim at an individual thread or at a whole process. They interrupt some functions, but not others, sometimes at the end-user's discretion (SA_RESTART). Realtime extensions allow signals to queue and perhaps deliver a word of data. There's more.

By contrast, POSIX pthread condition variables are synchronization mechanisms protecting some predicate. Here, the "signal" is the user-initiated action of waking one thread waiting on the condition variable, if such a thread exists.

It's perhaps unfortunate that the same term is used in different senses when we talk about these mechanisms, but so it is.

Who uses POSIX realtime signals and why?

First of all, note that Ben's answer is correct. As far as I can tell, the whole purpose of realtime signals in POSIX is as a realtime delivery mechanism for AIO, message queue notifications, timer expirations, and application-defined signals (both internal and inter-process).

With that said, signals in general are a really bad way to do things:

  • Signal handlers are asynchronous, and unless you ensure they do not interrupt an async-signal-unsafe function, they can only use async-signal-safe functions, which severely limits what they can do.
  • Signal handlers are global state. A library cannot use signals without a contract with the calling program regarding which signals it's allowed to use, whether it's allowed to make them syscall-interrupting, etc. And in general, global state is just A Bad Thing.
  • If you use sigwait (or Linux signalfd extension) rather than signal handlers to process signals, they're no better than other IPC/notification mechanisms, and still potentially worse.

Asynchronous IO is much better accomplished by ignoring the ill-designed POSIX AIO API and just creating a thread to perform normal blocking IO and call pthread_cond_signal or sem_post when the operation finishes. Or, if you can afford a little bit of performance cost, you can even forward the just-read data back to yourself over a pipe or socketpair, and have the main thread process asynchronously-read regular files with select or poll just like you would sockets/pipes/ttys.

Posix Reliable Signals between two processes using SIGUSR1

You haven't indicated what's actually happening, but to answer your questions:

"Is kill the right command to use to implement SIGUSR1?"
Yes.

"Do I need to know the PID of each the client and server in order for them to communicate?"
Yes.

"Am I totally just doing the wrong thing?"
Yes.

The main issue with using signal is that 1) it arrives at any time in the execution of your program, and 2) you are only ready to handle it at certain times.

The code you have above will only process the signal correctly if it happens to be in sigsuspend(), waiting. This isn't true at every moment! When you're in the other parts of the loop, i.e. when you send a kill() to the other process, consider what will happen if the other process kill()'s back before you arrive at sigsuspend again... you won't be waiting for the signal and it will come and go. Your implementation isn't reliable.

A more reliable implementation would be to use a socket connection between the processes; you could communicate the signal or even the data itself through such a connection. In fact there are many ways to do this, see http://en.wikipedia.org/wiki/Inter-process_communication (and you seem to be using POSIX interfaces above).

The upshot is that signal is asynchronous, interrupts the flow of any program, and specific to your program, you're not always ready for it, and if you miss it, it's gone. With sockets (or pipes or some other thing with an actual file descriptor) the data (your signal) will cause select() or poll() to return, instead of just flying by.

Real-time signals received in reversed order on Linux

Your problem is that you are permitting other signals to interrupt your running signal handler:

sigemptyset(&action.sa_mask);

The sa_mask field specifies the set of signals that aren't allowed to interrupt the execution of this handler.

This means that you get SIGRTMIN + 1 and before you can do anything about it you get another, lower-priority signal which you then start to handle. That signal in turn then gets interrupted in by yet another signal, and so on.

To fix this, disallow any other signals from interrupting your handler:

sigfillset(&action.sa_mask);

When several signals arrive at a process, what is the order between the process handling the signals?

SIGCONT has special semantics.

Regardless of whether SIGCONT is caught, is ignored, or has default disposition, its generation will clear all pending stop signals and resume execution of a stopped process. [IEEE Std 1003.1-2017] Again, this resumption happens before any other signals are delivered, and even before SIGCONT's handler (if any) is invoked.

(This special “dispositionless” semantic makes sense. In order for a process to execute a signal handler, the process must itself be executing.)

POSIX is clearer than APUE here, saying that "[t]he default action for SIGCONT is to resume execution at the point where the process was stopped, after first handling any pending unblocked signals."

As others have mentioned, the actual order in which pending signals are delivered is implementation-specific. Linux, at least, delivers basic UNIX signals in ascending numeric order.

To demonstrate all this, consider the following code. It STOPs a process, then sends it several signals, then CONTinues it, having installed handlers for all catchable signals so we can see what is handled when:

#define _POSIX_SOURCE
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>

static int signals[] = { SIGSTOP, SIGURG, SIGUSR1, SIGHUP, SIGCONT, 0 };

static void
handler(int signo) {
// XXX not async-signal-safe
printf("<signal %d>\n", signo);
}

int
main(int argc, char **argv) {
int *sig = signals;
struct sigaction sa = { .sa_flags = 0, .sa_handler = handler };

sigfillset(&sa.sa_mask);

sig++; // can't catch SIGSTOP
while (*sig) {
sigaction(*sig, &sa, NULL); // XXX error check
sig++;
}

if (fork() == 0) { // XXX error check
sleep(2); // faux synchronization - let parent pause()

sig = signals;
while (*sig) {
printf("sending signal %d\n", *sig);
kill(getppid(), *sig);
sig++;
}
exit(0);
}

pause();

return 0;
}

For me, this prints

sending signal 19
sending signal 23
sending signal 10
sending signal 1
sending signal 18
<signal 1>
<signal 10>
<signal 18>
<signal 23>

man page with list of posix signals?

Section 7 of manual gives the list of signals. Use:

man 7 signal

Significance of Real time Signal?

According to the signal(7) manpage, there are several differences:

   Real-time signals are distinguished by the following:

1. Multiple instances of real-time signals can be queued. By con-
trast, if multiple instances of a standard signal are delivered
while that signal is currently blocked, then only one instance is
queued.

2. If the signal is sent using sigqueue(2), an accompanying value
(either an integer or a pointer) can be sent with the signal. If
the receiving process establishes a handler for this signal using
the SA_SIGINFO flag to sigaction(2) then it can obtain this data
via the si_value field of the siginfo_t structure passed as the
second argument to the handler. Furthermore, the si_pid and si_uid
fields of this structure can be used to obtain the PID and real
user ID of the process sending the signal.

3. Real-time signals are delivered in a guaranteed order. Multiple
real-time signals of the same type are delivered in the order they
were sent. If different real-time signals are sent to a process,
they are delivered starting with the lowest-numbered signal.
(I.e., low-numbered signals have highest priority.)

If both standard and real-time signals are pending for a process, POSIX
leaves it unspecified which is delivered first. Linux, like many other
implementations, gives priority to standard signals in this case.


Related Topics



Leave a reply



Submit