NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
kern/60846: fork() disrupts futex
>Number: 60846
>Category: kern
>Synopsis: fork() disrupts futex
>Confidential: no
>Severity: serious
>Priority: high
>Responsible: kern-bug-people
>State: open
>Class: sw-bug
>Submitter-Id: net
>Arrival-Date: Sat Oct 03 18:00:01 +0000 2026
>Originator: Thomas Klausner
>Release: NetBSD 11.99.9/20261002
>Organization:
>Environment:
Architecture: x86_64
Machine: amd64
>Description:
Still trying to get a Linux program running, I found a weird bug in the futex handling.
A thread gets started and waits for a private futex;
the main thread wakes the private futex - this works.
However, when in between the thread start and the futex wake,
a child is forked (and reaped), the futex wake is not received by the
waiting thread.
>How-To-Repeat:
Save the test program below as futex-test.c and compile it on Linux,
or with pkgsrc/emulators/suse_gcc12 with:
/emul/linux/usr/bin/gcc-12 -o futex-test futex-test.c -lpthread
By default, it does not fork, but if the first command line argument is 'fork' it does.
Running it both ways on Debian 12.15 gives:
--- Linux output ---
# ./futex-test ; echo; ./futex-test fork
cc -o futex-test futex-test.c -lpthread
thread: futex waiting on address 0x557c663b0078
main: waking futex on address 0x557c663b0078
main: futex wake returned 1; joining
thread: futex wait return value 0 errno 0
RESULT: woken OK
thread: futex waiting on address 0x55ec13905078
main: forking child
child: sleeping
child: exiting
main: child reaped, return value 1971108, status 0
main: waking futex on address 0x55ec13905078
main: futex wake returned 1; joining
thread: futex wait return value 0 errno 0
RESULT: woken OK
--- end Linux output ---
while running it both ways on NetBSD-current's Linux emulation gives
--- NetBSD output ---
./futex-test; echo; ./futex-test fork
/emul/linux/usr/bin/gcc-12 -o futex-test futex-test.c -lpthread
thread: futex waiting on address 0x602090
main: waking futex on address 0x602090
main: futex wake returned 1; joining
thread: futex wait return value 0 errno 0
RESULT: woken OK
thread: futex waiting on address 0x602090
main: forking child
child: sleeping
child: exiting
main: child reaped, return value 8019, status 0
main: waking futex on address 0x602090
main: futex wake returned 0; joining
RESULT: WAKE LOST (join timed out)
--- end NetBSD output ---
--- begin futex-test.c ---
#define _GNU_SOURCE
#include <errno.h>
#include <linux/futex.h>
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/syscall.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>
static volatile int __attribute__((aligned(4))) word = 1;
static void *waiter(void *arg)
{
(void)arg;
errno = 0;
fprintf(stdout, "thread: futex waiting on address %p\n", &word);
long r = syscall(SYS_futex, &word, FUTEX_WAIT_PRIVATE, 1, NULL, NULL, 0);
printf("thread: futex wait return value %ld errno %d\n", r, errno);
return NULL;
}
int main(int argc, char **argv)
{
pthread_t tw;
struct timespec dl;
int do_fork = (argc > 1 && strcmp(argv[1], "fork") == 0);
pthread_create(&tw, NULL, waiter, NULL);
/* give thread time to block */
usleep(500 * 1000);
if (do_fork) {
printf("main: forking child\n");
pid_t c = fork();
if (c == 0) {
printf("child: sleeping\n");
usleep(1000 * 1000);
printf("child: exiting\n");
_exit(0);
}
usleep(1000 * 1000);
int status, ret;
ret = waitpid(c, &status, 0);
printf("main: child reaped, return value %d, status %d\n", ret, status);
}
word = 2;
fprintf(stdout, "main: waking futex on address %p\n", &word);
long nw = syscall(SYS_futex, &word, FUTEX_WAKE_PRIVATE, 1, NULL, NULL, 0);
printf("main: futex wake returned %ld; joining\n", nw);
clock_gettime(CLOCK_REALTIME, &dl);
dl.tv_sec += 3;
if (pthread_timedjoin_np(tw, NULL, &dl) == 0) {
printf("RESULT: woken OK\n");
return 0;
}
printf("RESULT: WAKE LOST (join timed out)\n");
return 1;
}
--- end ---
>Fix:
Yes, please!
>Unformatted:
Home |
Main Index |
Thread Index |
Old Index