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