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 03:29:54 +0000
This is a multi-part message in MIME format.
--=_LF0R1FFWgpNWTy7tDsnl9sFJlFnD3FDt
> Date: Sun, 21 Dec 2025 02:18:10 +0000
> From: Taylor R Campbell <riastradh%NetBSD.org@localhost>
>
> So something is overwriting entry->aref.ar_map->am_slots[0] in the
> time between the children all run and the time when the parent runs.
> [...]
> I bet there's a bug in the uvm_voaddr_acquire logic which we're only
> hitting in compat_linux for some reason.
I tried a similar native NetBSD program that uses clone(2), and it
worked just fine too like the native pthread version. The same
instrumentation showed that entry->aref.ar_map->am_slots[0] is _not_
changing between the children and the parent.
--=_LF0R1FFWgpNWTy7tDsnl9sFJlFnD3FDt
Content-Type: text/plain; charset="ISO-8859-1"; name="futest_clone"
Content-Transfer-Encoding: quoted-printable
Content-Disposition: attachment; filename="futest_clone.c"
//#include <sys/futex.h>
#include <err.h>
#include <errno.h>
#include <dirent.h>
#include <limits.h>
#include <pthread.h>
#include <sched.h>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#define CLONE_SYSVSEM 0
#define CLONE_THREAD 0
#define CLONE_SETTLS 0
#define CLONE_PARENT_SETTID 0
#define CLONE_CHILD_CLEARTID 0
static int futex =3D 0;
static volatile int threads_flags[55];
#include <sys/syscall.h>
#define SYS___futex 166
#define FUTEX_WAIT 0
#define FUTEX_WAKE 1
#define FUTEX_PRIVATE_FLAG 0 //__BIT(7)
static int
futex_wait(volatile int *uaddr, int val, struct timespec *timeout, int flag=
s)
{
return syscall(SYS___futex, /*uaddr*/uaddr, /*op*/FUTEX_WAIT|flags,
/*val*/val, /*timeout*/timeout, /*uaddr2*/NULL, /*val2*/0,
/*val3*/0);
}
static int
futex_wake(volatile int *uaddr, int nr_wake, int flags)
{
return syscall(SYS___futex, /*uaddr*/uaddr, /*op*/FUTEX_WAKE|flags,
/*val*/nr_wake, /*timeout*/NULL, /*uaddr2*/NULL, /*val2*/0,
/*val3*/0);
}
static int
startthread(void *cookie)
{
unsigned i =3D (unsigned)(uintptr_t)cookie;
// fprintf(stderr, "thread %u wait\n", i);
futex_wait(&futex, futex, NULL, FUTEX_PRIVATE_FLAG);
threads_flags[i] =3D 1;
// fprintf(stderr, "thread %u woken\n", i);
_exit(0);
}
static unsigned
nawake(void)
{
unsigned i, n;
for (i =3D 0, n =3D 0; i < __arraycount(threads_flags); i++) {
if (threads_flags[i])
n++;
}
return n;
}
static void
clear_awake(void)
{
unsigned i;
for (i =3D 0; i < __arraycount(threads_flags); i++)
threads_flags[i] =3D 0;
}
static unsigned
nsleeping(void)
{
unsigned pid =3D getpid();
char path[PATH_MAX];
DIR *dir;
struct dirent *dirent;
unsigned nsleeping =3D 0;
if ((size_t)snprintf(path, sizeof(path), "/proc/%u/task", pid)
>=3D sizeof(path))
err(EXIT_FAILURE, "pid too large");
dir =3D opendir(path);
if (dir =3D=3D NULL)
err(EXIT_FAILURE, "opendir(%s)", path);
while ((errno =3D 0, dirent =3D readdir(dir)) !=3D NULL) {
unsigned tid =3D atoi(dirent->d_name);
FILE *fp;
char stat =3D '\0';
if (tid =3D=3D pid || tid =3D=3D 0)
continue;
if ((size_t)snprintf(path, sizeof(path),
"/proc/%u/task/%u/stat", pid, tid)
>=3D sizeof(path))
err(EXIT_FAILURE, "tid too large");
fp =3D fopen(path, "r");
if (fp =3D=3D NULL)
err(EXIT_FAILURE, "fopen(%s)", path);
fscanf(fp, "%*u %*s %c", &stat);
if (fclose(fp) =3D=3D EOF)
err(EXIT_FAILURE, "fclose");
if (stat =3D=3D 'S')
nsleeping++;
else
fprintf(stderr, "thread %u not yet asleep\n", tid);
}
if (errno)
err(EXIT_FAILURE, "readdir");
if (closedir(dir) =3D=3D -1)
err(EXIT_FAILURE, "closedir");
return nsleeping;
}
int
main(void)
{
pid_t t[55];
unsigned i, j;
for (i =3D 0; i < __arraycount(t); i++) {
void *const stack =3D malloc(65536);
if (stack =3D=3D NULL)
err(EXIT_FAILURE, "malloc stack");
t[i] =3D __clone(&startthread, stack,
(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SYSVSEM|
CLONE_SIGHAND|CLONE_THREAD|
CLONE_SETTLS|CLONE_PARENT_SETTID|
CLONE_CHILD_CLEARTID),
(void *)(uintptr_t)i);
if (t[i] =3D=3D -1)
err(EXIT_FAILURE, "clone");
}
sched_yield();
sleep(1);
while (nsleeping() =3D=3D 0)
break;
for (i =3D 1; i <=3D 10; i++) {
clear_awake();
// fprintf(stderr, "wake %u threads\n", i);
if ((j =3D futex_wake(&futex, i, FUTEX_PRIVATE_FLAG)) !=3D i) {
if (j =3D=3D (unsigned)-1) {
err(EXIT_FAILURE, "futex_wake");
} else {
errx(EXIT_FAILURE,
"futex_wake returned %u, expected %u",
j, i);
}
}
for (j =3D 0; j < 10; j++) {
if (nawake() =3D=3D i)
break;
sleep(1);
}
}
if ((j =3D futex_wake(&futex, 1, FUTEX_PRIVATE_FLAG)) !=3D 0)
errx(EXIT_FAILURE, "futex_wake returned %u, expected 0", j);
fflush(stdout);
return 0;
}
--=_LF0R1FFWgpNWTy7tDsnl9sFJlFnD3FDt--
Home |
Main Index |
Thread Index |
Old Index