There are some problems with notify_fork() API that make it not really safe to use on (at least) Linux.
After a fork() system call the child can safely call only async-signal-safe functions (at least until it calls execve()).
There are some examples in Asio where this requirement isn't obeyed.
For example the epoll reactor calls at least timerfd_create(), epoll_create() and epoll_ctl() directly, timerfd_settime() via update_timeout() and eventfd() via eventfd_select_interrupter_.recreate().
It also calls POSIX mutex functions via mutex::scoped_lock.
None of these functions is guaranteed to be async-signal-safe.
Not to mention many other methods called from these handlers which likely also contain non-async-signal-safe code.
This limitation technically applies only to multi-threaded programs, however in practice third-party libraries (even glibc) can silently create helper threads, so it's hard to be 100% certain that a program stays single-threaded.
Since these third-party library fork() calls obviously won't be wrapped in notify_fork(), every io_context would need registering with pthread_atfork().
With some trickery to de-register them after usage, since POSIX does not provide an API to do that directly.
However, even in this case it's not possible to satisfy the notify_fork() API requirement of:
This function must not be called while any other execution_context function, or any function associated with the execution_context's derived class, is being called in another thread.
That's because a third-party library can call fork() even if another thread currently calls some execution_context function.
There are some problems with
notify_fork()
API that make it not really safe to use on (at least) Linux.After a
fork()
system call the child can safely call only async-signal-safe functions (at least until it callsexecve()
).There are some examples in Asio where this requirement isn't obeyed. For example the epoll reactor calls at least
timerfd_create()
,epoll_create()
andepoll_ctl()
directly,timerfd_settime()
viaupdate_timeout()
andeventfd()
viaeventfd_select_interrupter_.recreate()
. It also calls POSIX mutex functions viamutex::scoped_lock
.None of these functions is guaranteed to be async-signal-safe.
Same goes, for example, for the io_uring_service or even the service_registry.
Not to mention many other methods called from these handlers which likely also contain non-async-signal-safe code.
This limitation technically applies only to multi-threaded programs, however in practice third-party libraries (even glibc) can silently create helper threads, so it's hard to be 100% certain that a program stays single-threaded.
Since these third-party library
fork()
calls obviously won't be wrapped innotify_fork()
, everyio_context
would need registering withpthread_atfork()
. With some trickery to de-register them after usage, since POSIX does not provide an API to do that directly.However, even in this case it's not possible to satisfy the
notify_fork()
API requirement of:That's because a third-party library can call
fork()
even if another thread currently calls someexecution_context
function.