NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

Re: kern/56828 (futex calls in Linux emulation sometimes hang)



The following reply was made to PR kern/56828; it has been noted by GNATS.

From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
To: Hauke Fath <hf%spg.tu-darmstadt.de@localhost>
Cc: gnats-bugs%netbsd.org@localhost, kern-bug-people%netbsd.org@localhost,
	gnats-admin%netbsd.org@localhost, Thomas Klausner <wiz%NetBSD.org@localhost>,
	Chuck Silvers <chs%NetBSD.org@localhost>, Jason Thorpe <thorpej%NetBSD.org@localhost>
Subject: Re: kern/56828 (futex calls in Linux emulation sometimes hang)
Date: Sun, 21 Dec 2025 01:34:01 +0000

 Here's what the failing test test_wake02 does, in the main thread:
 
 1. pthread_create a bunch of children that do futex_wait(0x1234)
 2. wait a moment and do futex_wake(0x1234, 1) to wake one child
 3. wait a moment and do futex_wake(0x1234, 2) to wake two children
 and so on, until all the children are woken, verifying that futex_wake
 woke the correct number each time (it returns the number of wakeups).
 
 I tried mapping this to a native NetBSD program that does the same
 thing, and it works fine.  So what's the difference?
 
 First, although the Linux program uses FUTEX_PRIVATE_FLAG, we strip
 that off in compat_linux for some reason:
 
 https://nxr.netbsd.org/xref/src/sys/compat/linux/common/linux_misc.c?r=3D1.=
 267#1702
 
 But it works fine in NetBSD with or without FUTEX_PRIVATE_FLAG.
 
 I instrumented with dtrace to print the futex key in
 futex_lookup_by_key, and I found that the futex keys all matched in
 NetBSD, but the futex key shared by all the _children_ (non-main
 threads) in futex_wait didn't match the futex key used by the _parent_
 in futex_wake.  So the wakeups would never happen.
 
 The futex key is a tuple of (VM object, offset), where the VM object
 is either a struct uvm_object pointer tagged with 0x1 in the low bits,
 or a struct vm_anon pointer tagged with 0x2 in the low bits:
 
 https://nxr.netbsd.org/xref/src/sys/uvm/uvm_map.c?r=3D1.429#4920
 
 The object in the children and the parent is a struct vm_anon pointer
 in both cases (tagged 0x2), but it's a _different_ struct vm_anon
 pointer for the children and the parent (though same for all
 children).
 
 I bet if we changed the test to do the futex_wake from one of the
 children, it would pass.
 
 Why might this be happening?
 
 My best guess so far is that it has to do with this:
 
 - glibc pthread_create works by clone(CLONE_VM|...), which works kind
   of like the fork1(FORK_SHAREVM|...) inside vfork(2), making a pass
   through uvm_proc_fork -> uvmspace_share(parent, child).
 
 - NetBSD pthread_create works by _lwp_create, which doesn't go through
   fork1 at all.
 
 But I tried instrumenting uvm_voaddr_acquire to print the arguments,
 and...they're the _same arguments_ in the parent and child!  Same
 struct vm_map pointer, same va.  So how could uvm_voaddr_acquire be
 returning a different object in different (compat_linux) threads??
 


Home | Main Index | Thread Index | Old Index