Hi Takashi,

On Jan  3 23:05, Takashi Yano wrote:
> On Sun, 28 Dec 2025 11:52:36 -0800
> Nahor <[email protected]> wrote:
> > Attached is a reproducible example.
> > The example just calls `fork()` then open/flock/close a directory and
> > repeats (fork/open/flock/close). The forks optionally sleep then
> > open/flock/close the same directory and exit.
> > 
> > There is no issue if either the parent or the children don't call `flock()`.
> > Without sleeping, the example deadlocks immediately on my system 100%
> > of the time. Killing the child allow the parent to proceed, fork the
> > next child, which triggers the next deadlock.
> > When sleeping, _sometimes_ one child will deadlock with the parent.
> > Killing that child allows the parent and remaining children to proceed
> > (and potentially trigger another deadlock). Killing the parent also
> > unblocks all the children.
> 
> Thanks for the report and the test case.
> I looked into the issue and found the cause. I also confirmed that
> the patch attached solves the issue.
> 
> Could anyone please review the patch?
> 
> -- 
> Takashi Yano <[email protected]>

> From 5b0a3fac8c6f4f56626d108a2dfa9738f73ecf6b Mon Sep 17 00:00:00 2001
> From: Takashi Yano <[email protected]>
> Date: Sat, 3 Jan 2026 21:53:36 +0900
> Subject: [PATCH] Cygwin: close: Do not lock fdtab
> 
> Otherwise, a deadlock can occur if the child process attempts to
> lock a file while the parent process is closing the same file, which
> is already locked. The deadlock mechanism is as follows.
> 
> When the child process attempts to lock a file, it notifies the parent
> process by calling CreateRemoteThread(), which creates a remote thread
> in the parent. That thread checks whether the file being locked is
> currently opened in the parent. During the operation, cygheap->fdtab
> is temporarily locked in order to enumerate the file descriptors.
> 
> However, if the parent process is closing the same file at that moment,
> it also locks fdtab via cygheap_fdget cfd(fd, true) in __close().
> If the parent acquires th fdtab lock first, it proceeds to call
> del_my_locks(), which attempts to lock the inode in inode_t:get().
> 
> At this point, the inode is already locked in the child,
> so the parent waits for the child to release the inode. Meanwhile,
> the child is waiting to acquire the fdtab lock, which is still held
> by the parent. As a result, the parent and child become deadlocked.
> 
> However, since close_all_files() and close_range() do not lock fdtab,

close_all_files() is called from _exit(), so there's no reason to lock
fdtab.  close_range() locks fdtab explicitly right after EINVAL
handling.

Since close() is a process manipulating the fdtab, I have a bad feeling
to perform the action unlocked.  Wouldn't it make more sense to
enumerate without locking in create_lock_in_parent()?


Thanks,
Corinna

Reply via email to