Reputation: 38654
Consider the following test program
#include <csignal>
#include <iostream>
volatile std::sig_atomic_t signal_raised = 0;
void set_signal_raised(int signal) {
signal_raised = 1;
}
void check(std::sig_atomic_t expected) {
if (signal_raised != expected) {
std::cerr << signal_raised << " != " << expected << std::endl;
abort();
}
}
int main() {
using namespace std;
check(0);
std::signal(SIGINT, set_signal_raised);
check(0);
std::raise(SIGINT);
check(1);
signal_raised = 0;
check(0);
std::raise(SIGINT);
check(1);
cerr << "OK.\n";
}
With GCC and Clang, it outputs "OK." However, with Visual Studio 2015, it outputs nothing.
The signal handler is reset after handling the first signal. This can be verified by adding
auto prev = std::signal(SIGINT, set_signal_raised);
if (prev != set_signal_raised) {
std::cerr << "Unexpected handler." << std::endl;
abort();
}
to the check function. Is this allowed and expected?
Upvotes: 2
Views: 739
Reputation: 121417
Reset of the signal disposition is the behaviour that Unix System V used. But the BSD (currently glibc) do not reset the signal disposition. Either behaviour is allowed by POSIX standard allowed. C standard doesn't specify whether the "reset" is allowed.
From signal(2)
:
POSIX.1 solved the portability mess by specifying sigaction(2), which provides explicit control of the semantics when a signal handler is invoked; use that interface instead of signal().
In the original UNIX systems, when a handler that was established using signal() was invoked by the delivery of a signal, the disposition of the signal would be reset to SIG_DFL, and the system did not block delivery of further instances of the signal. This is equivalent to calling sigaction(2) with the following flags:
sa.sa_flags = SA_RESETHAND | SA_NODEFER;
System V also provides these semantics for signal(). This was bad because the signal might be delivered again before the handler had a chance to reestablish itself. Furthermore, rapid deliveries of the same signal could result in recursive invocations of the handler.
So, it seems Visual studio follows the System V behaviour.
Is this allowed and expected?
It's allowed but certainly not desired. For this reason, POSIX introduced sigaction()
. If you have sigaction()
then use it.
Otherwise, you just need to reinstall the handler everytime inside the signal handler:
void set_signal_raised(int signal) {
std::signal(SIGINT, set_signal_raised);
signal_raised = 1;
}
Upvotes: 2