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.
and another one on sigqueue
,
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;
}
]
The documented behavior on Linux is to not queue duplicate blocked signals.
From man 7 signal:
Standard signals do not queue. If multiple instances of a standard signal are generated while that signal is blocked, then only one instance of the signal is marked as pending (and the signal will be delivered just once when it is unblocked). In the case where a standard signal is already pending, the siginfo_t structure (see sigaction(2)) associated with that signal is not overwritten on arrival of subsequent instances of the same signal. Thus, the process will receive the information associated with the first instance of the signal.
However... the man page also says:
Multiple instances of real-time signals can be queued. By contrast, if multiple instances of a standard signal are delivered while that signal is currently blocked, then only one instance is queued.
Are you looking at the POSIX documentation for real time signals and testing with standard ones?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With