C++ printing in signal handlers?

Viewed 513

I searched a lot but none answered my question, I read that it's not safe to use cout in signal handlers like this:

void ctrlZHandler(int sig_num) {
    //SIGTSTP-18
    std::cout << "smash: got ctrl-Z" << std::endl;
    SmallShell::route_signal(sig_num);
}
  1. will it solve the problem if I move the printing inside route_signal?

  2. Is there a lists of safe-to-call functions in C++11?

  3. What if the only solution to use write, can you show me short example, and let's say route_signal have 100 printings should I replace all with write()? that sounds exhausting with the need to allocate memory and free...

3 Answers

The reason why using std::cout inside signal handlers isn't recommented is because signals might interrupt your running code whenever and std::cout::operator << is not reentrant.

This means if you are executing std::cout::operator << when a signal is raised that also uses it within it's execution, the result is undefined.

So, no. Moving it into route_signal would not solve this and you should replace every call of std::cout within!

One workaround would be to set a flag that this signal was received and create a output outside the signal handler after it returned.

Signal handlers need to run quickly and be reentrant, which is why they shouldn’t call output stream functions like cout <<, either directly or indirectly.

If you are doing this temporarily under controlled conditions for testing, it might be okay, but make sure the signal you are handling is not triggered again until the handler has finished and be aware that stream functions can be slow, which might mess up your tests as well.

  1. will it solve the problem if I move the printing inside route_signal?

No.

  1. Is there a lists of safe-to-call functions in C++11?

For practical purposes, the only safe thing you can do is set a volatile sig_atomic_t or lock-free atomic flag inside a signal handler. (N3690 intro.execution §1.9 ¶6)

I'm no C nor C++ language lawyer, but I believe anything permitted in a conforming C application is allowed in a C++11 signal handler. However, that set is very, very limited: abort, quick_exit, _Exit, and signal. (ISO/IEC 9899:2011 §7.14.1.1 ¶5).

  1. What if the only solution to use write, can you show me short example, and let's say route_signal have 100 printings should I replace all with write()? that sounds exhausting with the need to allocate memory and free...

A better solution is to redesign your program to use sigwait or to check that a flag safely set inside the signal handler.

If you insist on using write, and if you trust that it is safe to call inside a signal handler in your C++ implementation — which it probably is but, again, is not guaranteed by C++ itself — then you simply have a coding problem. You'll need to figure out formatting yourself, bearing in mind that even on POSIX-conforming systems malloc and free are not async-signal-safe. It can certainly be done.

Related