6

I am working with multi processes and signals and I just found out yesterday that printf is not a re-entrant function so there is a risk by using it with signal handlers. Is there anything I can do about it? Is there any re-entrant variation of printf or any re-entrant syscall that could replace printf?

Thanks!

Daniel Oliveira
  • 1,280
  • 14
  • 36
  • 1
    check this answer out for an amazingly detailed explanation: http://stackoverflow.com/questions/3941271/why-are-malloc-and-printf-said-as-non-reentrant – bruceg Oct 11 '16 at 21:40
  • 1
    Just wondering why you want to enable having two or more processes write to something at the same time. WaHrAeT yAoRuE cYoOmUpTlHeItNeKlIyN Gm?ad? – Tibrogargan Oct 11 '16 at 21:41
  • `write` is async-safe, so can be used from a signal handler... – Chris Dodd Oct 11 '16 at 22:21
  • @ChrisDodd Can I really just safely use [`write(STDOUT_FILENO, "...")`](https://man7.org/linux/man-pages/man2/write.2.html) from signal handler to print to stdout instead of using`printf()`? – pevik Aug 06 '21 at 08:06
  • 1
    @pevik: Yes, though you need to be aware that `write` might write less than you request, and the data written might appear in the middle of some `printf` in the main program, depending on when the signal hits and other things that might occur. But it won't crash – Chris Dodd Aug 06 '21 at 15:48

1 Answers1

5

Signal handlers are highly tricky in general. So highly tricky, that usually the only safe operation to do within them is to set a flag "signal was received" and then let the main loop (or in a multi threaded application a special signal handling thread) of the program do the actual signal handling.

Bodo Thiesen
  • 2,476
  • 18
  • 32
  • If I only set a flag (like a static variable) on my signal handler then when my code goes back to the printf it will print the rest of the message? If yes why does it happen? – Daniel Oliveira Oct 11 '16 at 21:55
  • 1
    The signal handler interrupts whatever is going on. If the interrupted printf is currently in a syscall, the kernel typically aborts operation (i.e. resets everything back in the state prior to syscall invocation) and return with errno set to ERESTART (Interrupted system call should be restarted). Library functions like printf will just return that error (i.e. return with -1 and leave errno as it is). If the function is not within a syscall, it will just continue once the signal handler returns and the only way to detect the occurrence of the signal is to check your flag. – Bodo Thiesen Oct 11 '16 at 22:06
  • I understand. So how could I use my flag to restarts the printf if it is interrupted by a signal from the kernel? – Daniel Oliveira Oct 11 '16 at 22:13
  • @BodoThiesen: Actually the problem comes about if printf is running NOT in a system call when the signal occurs -- if it has copied some data into a buffer but not updated the pointers yet, the signal handler will see an apparently corrupt FILE object, or will overwrite data that hasn't yet been written by the kernel. – Chris Dodd Oct 11 '16 at 22:24
  • 1
    The error code "ERESTART" actually indicates, what you should do: Just recall the function. I.e. if you have an printf statement somewhere, you actually have to do this: int r = printf(...); if (r==-1) { error handling -> in case of ERESTART maybe goto just in front of the printf line; } The flag on the other hand is to you can handle your signal, like "while (!quit_requested) { do some productive stuff in this main loop; if (signal_term_received_flag) { save_work(); quit_requested=true; } } – Bodo Thiesen Oct 11 '16 at 22:25
  • @ChrisDodd: I know. But that was not, what I was telling there. He asked what printf will do after the signal handler returns and since I told, he can pretty much do nothing except for setting the flag, I guess, he now just want's to know what to expect from the interrupted printf call (without reentering it in the signal handler) – Bodo Thiesen Oct 11 '16 at 22:27
  • @BodoThiesen: unless you go out of your way with clearing the SA_RESTART flag, the system call will be restarted automatically after the signal is delivered. But as I said above, that's not the problem with trying to call printf from a signal handler -- the problem is the FILE object being in an indeterminate state, leading to corruption and possibly a crash. – Chris Dodd Oct 11 '16 at 22:28
  • @ChrisDodd: The reentrance is off of the table since my answer. The comments have nothing to do with reentrance. Please re-read the convesations in the comments, especially the first part of Daniels first comment: "If I only set a flag (like a static variable) on my signal handler then [...]" – Bodo Thiesen Oct 11 '16 at 22:34
  • @DanielOliveira: BTW: Setting a static variable - if you mean a file scope static variable, it's fine (it doesn't have to be static thou). A function scope static variable on the other hand won't help, you can't reach it from outside of the signal handler. – Bodo Thiesen Oct 11 '16 at 22:35
  • The answer to the first comment is simply wrong: after the signal handler returns, whatever was running will resume. There's no need to check errno after printf for EINTR (there's no such thing as ERESTART), as, unless you've gone out of your way to change it, the system call will be restarted after the interrupt. – Chris Dodd Oct 11 '16 at 22:40
  • In regards to EINTR, you're right, I mixed it up. For the rest, you should pay attention to the fact, that linux is not the only operating system out there. http://man7.org/linux/man-pages/man7/signal.7.html "The details vary across UNIX systems". And even for Linux: "The following interfaces are never restarted after being interrupted by a signal handler, regardless of the use of SA_RESTART; they always fail with the error EINTR when interrupted by a signal handler". And for me, this discussion is over now, it doesn't help the OP and Stack Overflow is already asking me to move this to a chat. – Bodo Thiesen Oct 11 '16 at 22:50