The POSIX article for sigaction
states:
If SA_SIGINFO is set in sa_flags, then subsequent occurrences of sig generated by sigqueue() or as a result of any signal-generating function that supports the specification of an application-defined value (when sig is already pending) shall be queued in FIFO order until delivered or accepted; the signal-catching function shall be invoked with three arguments. The application specified value is passed to the signal-catching function as the si_value member of the siginfo_t structure.
This says nothing about merging of occurrences of the same signal (signo
). And even if it meant merging, then the phrase about FIFO would be incomplete. For example, if the FIFO is [SIGALRM, SIGIO, SIGUSR1, SIGIO]
, what would it be after merging, [SIGALRM, SIGIO, SIGUSR1]
or [SIGALRM, SIGUSR1, SIGIO]
?
However, I saw several reports (0, 1, 2) that Linux indeed merges occurrences of the same signal. I also wrote a small test program that confirms that occurrences of the same signal sent with sigqueue
when that signal is blocked are merged on ArchLinux. A signal handler was installed with sigaction
.
Linux [skipped] 5.3.8-arch1-1 #1 SMP PREEMPT [skipped] x86_64 GNU/Linux
If occurrences of the same signal are merged, then transmitting information via union sigval
does not make sense because this information may be unpredictably lost.
Is my understanding of POSIX incorrect, or is Linux implementing it incorrectly?
[Update 2019-11-09 09:51:32+00:00. I found another chunk of documentation that corroborates my point. According to the article “2. General Information”,
If a subsequent occurrence of a pending signal is generated, it is implementation-defined as to whether the signal is delivered or accepted more than once in circumstances other than those in which queuing is required.
If SA_SIGINFO is set for signo and if the resources were available to queue the signal, the signal shall be queued and sent to the receiving process.
The sigqueue() function shall fail if:
[EAGAIN] No resources are available to queue the signal. The process has already queued {SIGQUEUE_MAX} signals that are still pending at the receiver(s), or a system-wide resource limit has been exceeded.
I used sigaction
with SA_SIGINFO
set and sigqueue
. The function sigqueue
did not return EAGAIN
.]
[Update 2019-11-09 17:45:25+00:00. My test program. The sigprint
functions are for printing using write
and a statically allocated buffer; they are not important.
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include "sigprint.h"
void signal_handler(int signo, siginfo_t *info, void *context) {
sigprint_string("|");
sigprint_long(info->si_value.sival_int);
sigprint_flush();
}
void sigqueue_check(pid_t pid, int signo, union sigval value) {
if (sigqueue(pid, signo, value) == -1) {
printf(" returned error code %d which is %s to EAGAIN.\n",
errno, errno == EAGAIN ? "==" : "!=");
exit(24);
}
}
int main() {
struct sigaction sigaction0;
union sigval sigval0;
sigset_t sigset0, sigset1;
sigaction0.sa_sigaction = &signal_handler;
sigemptyset(&sigaction0.sa_mask);
sigaction0.sa_flags = SA_SIGINFO | SA_RESTART;
sigaction(SIGALRM, &sigaction0, NULL);
sigemptyset(&sigset0);
sigaddset(&sigset0, SIGALRM);
sigprocmask(SIG_BLOCK, &sigset0, &sigset1);
sigval0.sival_int = 10;
sigqueue_check(getpid(), SIGALRM, sigval0);
sigval0.sival_int = 11;
sigqueue_check(getpid(), SIGALRM, sigval0);
sigval0.sival_int = 12;
sigqueue_check(getpid(), SIGALRM, sigval0);
sigprocmask(SIG_SETMASK, &sigset1, NULL);
sleep(1);
return 0;
}
]