[newlib-cygwin] Cygwin: fork: Call pthread::atforkprepare() in lock_pthread()
Takashi Yano via Cygwin-cvs <[email protected]> Fri, 29 May 2026 02:34:52 +0000 (GMT)
| Newsgroups | gmane.os.cygwin.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D52d033095e6= 7d52e23a185c029e40fd2edbfe30f commit 52d033095e67d52e23a185c029e40fd2edbfe30f Author: Takashi Yano <[email protected]> Date: Tue May 19 16:43:21 2026 +0900 Cygwin: fork: Call pthread::atforkprepare() in lock_pthread() =20 Since the commit 5f515cf3d6e3, if one thread calls fclose() while another thread calls fork(), a deadlock can occur. The mechanism is as follows. 1) fclose() first calls __sfp_lock_acquire() and, then calls lock_process::locker.acquire() via cygheap_fdget(). 2) fork() first calls lock_process::locker.acquire() via the constructor of the lock_process class in the hold_everything class, and then calls __sfp_lock_acquire() via __fp_lock_all() in atforkprepare(). 3) As a result, the thread calling fclose() tries to acquire the lock_process lock while holding __sfp_lock, and the thread calling fork() tries to acquire __sfp_lock while holding the lock_process lock. This leads to a deadlock. Before the commit 5f515cf3d6e3, __sfp_lock was acquired in the constructor of the lock_pthread class in the hold_everything class, and since lock_pthread is defined before lock_process, this deadlock did not occur. =20 This patch moves the atforkprepare() call back into the constructor of the lock_pthread class, restoring the previous lock acquisition order. =20 Fixes: 5f515cf3d6e3 ("Cygwin: add _Fork() system call per POSIX.1-2024") Signed-off-by: Takashi Yano <[email protected]> Reviewed-by: Johannes Schindelin <[email protected]> Diff: --- winsup/cygwin/local_includes/sigproc.h | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/winsup/cygwin/local_includes/sigproc.h b/winsup/cygwin/local_i= ncludes/sigproc.h index 92cda94dc..21367877c 100644 --- a/winsup/cygwin/local_includes/sigproc.h +++ b/winsup/cygwin/local_includes/sigproc.h @@ -131,7 +131,15 @@ class lock_pthread { bool bother; public: - lock_pthread (): bother (1) {} + lock_pthread (bool do_atfork_handlers): bother (1) + { + /* POSIX.1-2024: _Fork() does not call any handler established + by pthread_atfork(). */ + if (do_atfork_handlers) + dont_bother (); + else + prepare (); + } void prepare () { pthread::atforkprepare (); @@ -166,15 +174,8 @@ class hold_everything lock_process process; =20 public: - hold_everything (bool& x, bool do_atfork_handlers): ischild (x) - { - /* POSIX.1-2024: _Fork() does not call any handler established - by pthread_atfork(). */ - if (do_atfork_handlers) - pthread.dont_bother (); - else - pthread.prepare (); - } + hold_everything (bool& x, bool do_atfork_handlers): ischild (x), + pthread (do_atfork_handlers) {} operator int () const {return signals;} =20 ~hold_everything()