fix(device): bypass foreign atfork handlers in reattach helper - #11
Merged
Conversation
glibc's fork() runs every pthread_atfork() handler registered anywhere in the process, in the child, on every call -- it does not matter which library called fork() or why. cerastream links libuvc next to libsrt, whose child handler (srt::CUDTUnited::cleanupAtFork) locks an SRT mutex. A fork carries only the calling thread into the child, so whenever another SRT thread held that mutex at the instant of the guard's fork it was locked in the child with no thread left alive to release it. gdb on a stuck child on an RK3588 board: pthread_mutex_lock <- CUDT::closeInternal <- cleanupAllSockets <- cleanupAtFork <- fork <- uvc_reattach_guard_create, with strace showing an untimed FUTEX_WAIT_PRIVATE. helper_main() never ran, so nothing was reattached AND nothing was closed -- the child kept the ~99 descriptors the fork had copied, including the usbfs node and the ALSA capture device, and ignored every SIGTERM. The next run then found its audio device busy and its camera taken, and systemd logged a left-over process in the control group on essentially every restart. fork(2) is defined as clone(2) with flags of just SIGCHLD, and __run_fork_handlers() is reached only from glibc's fork() wrapper, so issuing that clone directly is the same process creation with none of the handlers. Skipping glibc's own post-fork repairs costs nothing here: this child is post-fork code in a multi-threaded process and was already restricted to async-signal-safe calls that touch none of that state. The double-fork topology, the waitpid() handshake and everything helper_main() does are unchanged. The new regression case registers such a handler in the victim and holds its mutex hostage on a second thread across the fork; against the fork() code it fails on a bounded wait and then times out, because the victim never reaches its own SIGKILL. Board-Evidence-SHA256: bdb689aa53eb82d9e1c13b34531a4d9d7f03b063d97f18d346c0b69575e9dec5
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Replace the reattach helper\047s
fork()calls with rawclone(2)syscalls.Why
glibc\047s
fork()wrapper runs process-widepthread_atfork()handlers. In the cerastream process, libsrt\047s child handler could lock a mutex held by a thread absent from the child, leaving the helper wedged with roughly 99 inherited descriptors and orphaning camera/audio resources. Rawclone(SIGCHLD, ...)preserves the required process topology while bypassing that handler chain.How to verify
***Timeout 30.03 sec; restoring it producedPassed 0.11 sec.cerastreamprocess with no left-over-process journal entry.task-reattach-raw-clone-board-proof.md, SHA256bdb689aa53eb82d9e1c13b34531a4d9d7f03b063d97f18d346c0b69575e9dec5.Risks
Raw clone intentionally skips glibc post-fork repair, but the child path is already restricted to async-signal-safe operations and does not touch malloc, loader, or stdio state. The board evidence covers the production reattach path.