How to make a function async-signal-safe?
You can use fcntl() as an alternative to flock().
Signal handler async safe functions
Technically you can call or write any function(s) inside the signal handler there is nothing preventing you from doing it.
The reason why its discouraged is that, when a signal handler is handling your operation, there could be another signal raised which could make the signal handler jump to the higher priority signal handler.
This kind of leads to race and hard to debug problems as we are not aware of the ordering of the handling of signals.
Thats the reason why the signal handlers are supposed to be light to avoid hard to debug race conditions and usually we set flags to indicate a signal has been raised and handle it in the main or another thread that reads these flags.
Do functions which are not defined as async-safe, such as mmap(2), effect other async-safe functions called in signal handler?
Yes.
If your substitute open()
calls a function that is not async-signal-safe, then it is not safe for a signal handler to call your function. That it has the same name and signature as a standard function that is async-signal-safe is irrelevant. That it calls the replaced function or other async-signal-safe functions is irrelevant. That the prospective signal handler's call to a function that is not async-signal-safe would not be a direct one is irrelevant.
In response to the question update: in the event that the function presented in the question is called as a signal handler, it has undefined behavior on account of its call to mmap()
. The details of that UB cannot be predicted, at least not from the relevant standards. That's what "undefined" means. There is no reason whatever to suppose that the actual and apparent effects of the open()
call would be somehow protected from interference. Nor the general signal-handling mechanism. Nor anything else in the program.
The further you get from the locus of the UB, the less likely is any noticeable effect, and the more likely the OS is to contain it, but UB is not something to mess with. In principle, it may manifest as any behavior or behaviors within the power of your computer to produce, such as wiping your disk, turning off your CPU fan, or mailing your password to hackers.
Why can only async-signal-safe functions be called from signal handlers safely?
Say a thread within process A is calling printf and another thread
receives the signal and then calls printf. Is it possibly because the
kernel here will not know what to do because it will not be able to
distinguish between the two calls.
It's not the kernel that will have issues. It's your application itself. printf
is not a kernel function. It's a function in the C library, that your application uses. printf
is actually a fairly complicated function. It supports a wide variety of output formatting.
The end result of this formatting is a formatted output string that's written to standard output. That process in and of itself also involves some work. The formatted output string gets written into the internal stdout
file handle's output buffer. The output buffer gets flushed (and only at this point the kernel takes over and writes a defined chunk of data to a file) whenever certain defined conditions occur, namely when the output buffer is full, and/or whenever a newline character gets written to the output stream.
All of that is supported by the output buffer's internal data structures, which you don't have to worry about because it's the C library's job. Now, a signal can arrive at any point while printf
does its work. And I mean, at any time. It might very well arrive while printf
is in the middle of updating the output buffer's internal data structure, and they're in a temporarily inconsistent state because printf
hasn't yet finished updating it.
Example: on modern C/C++ implementations, printf
may not be signal-safe, but it is thread safe. Multiple threads can use printf
to write to standard output. It's the threads' responsibility to coordinate this process amongst themselves, to make sure that the eventual output actually makes sense, and it's not jumbled up, at random, from multiple threads' output, but that's beside the point.
The point is that printf
is thread safe, and that typically means that somewhere there's a mutex involved in the process. So, the sequence of events that might occur is:
printf
acquires the internal mutex.printf
proceeds with its work with formatting the string and writing it tostdout
's output buffer.before
printf
is done, and can release the acquired mutex, a signal arrives.
Now, the internal mutex
is locked. The thing about signal handlers is that it's generally not specified which thread, in a process, gets to handle the signal. A given implementation might pick a thread at random, or it might always pick the thread that's currently running. In any case, it can certainly pick the thread that has locked the printf
, here, in order to handle the signal.
So now, your signal handler runs, and it also decides to call printf
. Because printf
's internal mutex is locked, the thread has to wait for the mutex to get unlocked.
And wait.
And wait.
Because, if you were keeping track of things: the mutex is locked by the thread that was interrupted to service the signal. The mutex won't get unlocked until the thread resumes running. But that won't happen until the signal handler terminates, and the thread resumes running, but the signal handler is now waiting for the mutex to get unlocked.
You're boned.
Now, of course, printf
might use the C++ equivalent of std::recursive_mutex
, to avoid this problem, but even this won't solve all possible deadlocks that could get introduced by a signal.
To summarize, the reason why it's "unsafe to receive a signal and call a non async safe function from within that signal handler" is because it's not, by definition. It's not safe to call a non-async safe function from within the signal handler" because the signal is an asynchronous event, and since it's not an async-safe function, you can't, by definition. Water is wet because it's water, and an async-unsafe function cannot be called from an asynchronous signal handler.
Async safe writing functions for Signal handler on windows
There is little authoritative information on this in general, even on POSIX. Instead, I'd suggest posting to a queue/signaling a condition from inside the async handler (using safe primitives) and doing the rest elsewhere.
TTBOMK this abstraction is already present and ready-to-use in Boost:
- Boost Asio
signal_set
Also, for your particular purpose it does appear that Boost Stacktrace has helper functions that are expressly async-safe: Handling terminates, aborts and Segmentation Faults:
#include <signal.h> // ::signal, ::raise
#include <boost/stacktrace.hpp>
void my_signal_handler(int signum) {
::signal(signum, SIG_DFL);
boost::stacktrace::safe_dump_to("./backtrace.dump");
::raise(SIGABRT);
}
Is sysinfo() async. signal safe?
sysinfo
is just thin system call wrapper and async-signal-safe:
00000000000feb00 <sysinfo@@GLIBC_2.2.5>:
feb00: mov $0x63,%eax
feb05: syscall
feb07: cmp $0xfffffffffffff001,%rax
feb0d: jae feb10 <sysinfo@@GLIBC_2.2.5+0x10>
feb0f: retq
feb10: mov 0xbf359(%rip),%rcx
feb17: neg %eax
feb19: mov %eax,%fs:(%rcx)
feb1c: or $0xffffffffffffffff,%rax
feb20: retq
But there is no vDSO acceleration for it, so it is going to be much slower than clock_gettime
with either CLOCK_REALTIME
or CLOCK_MONOTONIC
on current systems.
Print int from signal handler using write or async-safe functions
If you really insist on doing the printing from a signal handler, you basically have 2 options:
Block the signal except in a dedicated thread you create for handling the signal. This special thread can simply perform
for (;;) pause();
and sincepause
is async-signal-safe, the signal handler is allowed to use any functions it wants; it's not restricted to only async-signal-safe functions. On the other hand, it does have to access shared resources in a thread-safe way, since you're now dealing with threads.Write your own code for converting integers to decimal strings. It's just a simple loop of using
%10
and/10
to peel off the last digit and storing them to a short array.
However, I would highly recommend getting this operation out of the signal handler, using the self-pipe trick or similar.
C write async unsafe code in signal handler
In a signal handler you can only use a set of safe functions which in many cases is sufficient for complicated functionality started within a handler. You can check man pages for your system for 'signal-safety' or similar. Here is a pointer on the web: https://man7.org/linux/man-pages/man7/signal-safety.7.html
pthread synchronization functions are not on the list.
However, One of the function listed there is sem_post
: https://man7.org/linux/man-pages/man3/sem_post.3.html
sem_post() is async-signal-safe: it may be safely called within a
signal handler.
So, you can implement mutex-like synchronization using semaphores within the signal handler.
Related Topics
Windows 7 Timing Functions - How to Use Getsystemtimeadjustment Correctly
Is Std::Cout Guaranteed to Be Initialized
C++ Convert from 1 Char to String
Check If a String Is Palindrome
Is Inline Assembly Language Slower Than Native C++ Code
Difference Between Std::System_Clock and Std::Steady_Clock
Effective C++ Item 23 Prefer Non-Member Non-Friend Functions to Member Functions
C++ Delete Vector, Objects, Free Memory
Std::Map Emplace Without Copying Value