mirror of
https://github.com/RhapsodiOS/RhapsodiOS.git
synced 2026-11-03 22:01:40 -07:00
[GH-ISSUE #49] fork from a multithreaded (cthreads) process: child sometimes hangs in malloc under load #40
Labels
No labels
bug
documentation
enhancement
enhancement
good first issue
help wanted
help wanted
pull-request
question
wontfix
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
github-starred/RhapsodiOS#40
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @raynorpat on GitHub (Oct 14, 2026).
Original GitHub issue: https://github.com/RhapsodiOS/RhapsodiOS/issues/49
Symptom
A child forked from a multithreaded (cthreads) process sometimes hangs. It never completes a plain
malloc(1 MB)+ fill + check +_exit(0). The parent waits 10 s and gives up.Seen in the stress suite's
stress-thread forktest (ffs-perf branch,src/Commands/stress/thread/thread.c). The setup:mutex_tand incrementing counters;fork()s while they run;malloc, fill, check, then_exit(0).thread/runtests, with all six thread tests running at once. It passed when run alone. No console or serial message accompanied it.What the source already does (so the obvious cause is not it)
The fork path is meant to be safe for exactly this case:
fork()(src/Libc-1/sys.subproj/i386.subproj/fork.s) calls_cthread_fork_prepareand__dyld_fork_preparebefore the syscall._cthread_fork_child,__dyld_fork_childand_dyld_fork_child_final._cthread_fork_prepare(threads.subproj/cthreads.c:362) takescthread_lock,cthread_free_lock, and malloc's lock through_malloc_fork_prepare(gen.subproj/malloc.c:2642)._cthread_fork_child(cthreads.c:387) releases them and resets cthreads state.So the plain "malloc lock held by another thread at fork time" explanation should not apply. The real cause is not known yet.
Candidates to check
spin_lockormutex_theld by a parent thread at fork time that the child later needs and that isn't in_cthread_fork_prepare(e.g.mig_support.creply-port state,stack.c,lookupd/_lu_port, the zone allocator's region locks ifnxzone*uses its own);733bbd587). Blocked signals are inherited across fork, so check whether the child restores the mask.forkof a task with several Mach threads, and whether the child's single thread can deadlock with a copied but never-released kernel-side lock;A triage run on the stress suite is reproducing this in isolation and under load. It will post its findings here: where the child is blocked, and the call chain if it can be captured.
Reproduce
Related: #42 (fork exhaustion panic), and the dyld signal-lock fix (
733bbd587).@raynorpat commented on GitHub (Oct 14, 2026):
Triage result from the stress-suite run: not a hang, and not a Libc or kernel bug as far as the evidence goes.
fork.scalls the cthreads fork hooks, which take and reset malloc's lock (threads.subproj/cthreads.c:362-400,gen.subproj/malloc.c:2642). malloc is fork-safe here._exit(0), taking 6-15 s under the concurrent-test load and 7.2 s even when run alone, against the test's 10 s bound.97199346con ffs-perf). A rerun with the same seed under the same load passed.The one thing still worth a look is why a fork plus 1 MB touch takes about 7 s in a 4-thread process on the TCG guest. That is a performance question, not a correctness bug. Recommend closing this issue, and opening a performance one if that timing matters.