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