I read user input from stdin
via std::getline()
, and I want to be able to exit the program by SIGINT. Unfortunately, std::getline()
does not seem to wake up on any signal. Hence, the code below only aborts after pressing CTRL-C and RETURN.
#include <csignal>
#include <string>
#include <iostream>
bool abort_ = false;
void SigIntHandler(int signum) {
std::cout << "Received SIGINT" << std::endl;
abort_ = true;
}
int main(int argc, char *argv[]) {
signal(SIGINT, SigIntHandler);
while (!abort_) {
std::string line;
std::cout << "> ";
std::getline(std::cin, line);
if (!std::cin)
std::cin.clear();
std::cout << line << std::endl;
}
}
Why is that so? Do I have any chance to wake up std::getline()
except by user input? Or is there any other way to read from stdin
, that is also responsive to signals?
std::getline
, and the input/output library in general, does not have a specified behavior when the process receives a signal. The C++ library, and language, does not specify any particular behavior. Signals are only briefly mentioned in passing, with the most notable reference being only that:
A call to the function signal synchronizes with any resulting invocation of the signal handler so installed.
That, and the enumeration of the header file, is the sum total of references to signals in the C++ library. Signals are a highly operating system-specific feature, that's simply not covered by the C++ library.
None of the C++ library functions and classes discussed here are signal-safe. In the shown code, the signal handler cannot do anything to the input stream, because its internal state is indeterminate, and the whole thing is not signal-safe.
As such, to deal with signals it will be necessary to resort to low level operating system-specific calls, like open()
, read()
, and write()
, instead of using the C++ input/output library. Of course, one of the options is write your own subclass of std::streambuf
, implementing its functionality using low level system calls, and handling signals appropriately. Your own implementation will be appropriately blocking on input and handling any received signal by setting the stream buffer to failed state (or, perhaps, simulating receiving an ENTER
key, hey, it's your show) and returning.