Re: futex(2) not working in inherited mmap'd anon memory

2021-11-19 Thread Thomas Munro
On Fri, Nov 5, 2021 at 9:19 AM Thomas Munro  wrote:
> On Tue, Oct 26, 2021 at 11:29 PM Thomas Munro  wrote:
> > When I do mmap(MAP_ANONYMOUS | MAP_SHARED) and then fork(), it seems
> > that futex(2) wakeups are not delivered between child and parent in
> > that memory.  It does work as expected if I instead use
> > shmget(IPC_PRIVATE).

> This seems to be because such memory objects have no uvm_obj, which is
> needed by futex_get() to identify futexes.  Could they have one?  Or
> perhaps there is some other way to make a futex key in this case?

Thanks very much to kettenis@ for fixing this!

One other observation about this implementation (this may already be
on a to-do list somewhere, in which case please count this as +1
vote): instead of a single ftlock and ftlist_shared pair, you could
hash the futex key to select among N locked lists, to avoid contention
(like FreeBSD).



Re: futex(2) not working in inherited mmap'd anon memory

2021-11-04 Thread Thomas Munro
On Tue, Oct 26, 2021 at 11:29 PM Thomas Munro  wrote:
> When I do mmap(MAP_ANONYMOUS | MAP_SHARED) and then fork(), it seems
> that futex(2) wakeups are not delivered between child and parent in
> that memory.  It does work as expected if I instead use
> shmget(IPC_PRIVATE).

Hello,

This seems to be because such memory objects have no uvm_obj, which is
needed by futex_get() to identify futexes.  Could they have one?  Or
perhaps there is some other way to make a futex key in this case?



futex(2) not working in inherited mmap'd anon memory

2021-10-26 Thread Thomas Munro
Hello,

When I do mmap(MAP_ANONYMOUS | MAP_SHARED) and then fork(), it seems
that futex(2) wakeups are not delivered between child and parent in
that memory.  It does work as expected if I instead use
shmget(IPC_PRIVATE).

Below is a standalone test program.  I tested it with the four OSes
mentioned, and the two shmem types depending on that #if, and all
worked as expected except the OpenBSD/mmap case, which hangs.

Is it a bug?

$ uname -a
OpenBSD openbsd6.localdomain 6.9 GENERIC.MP#473 amd64

Thanks,

=== 8< ===

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 

#if defined(__linux__)
#include 
#include 
#elif defined(__OpenBSD__)
#include 
#include 
#elif defined(__FreeBSD__)
#include 
#include 
#elif defined(__APPLE__)
#define UL_COMPARE_AND_WAIT_SHARED 3
#define ULF_WAKE_ALL 0x0100
extern int __ulock_wait(uint32_t operation, void *addr, uint64_t
value, uint32_t timeout);
extern int __ulock_wake(uint32_t operation, void *addr, uint64_t wake_value);
#endif

static int
my_futex_wait_u32(void *fut, uint32_t value, struct timespec *timeout)
{
#if defined(__linux__)
if (syscall(SYS_futex, fut, FUTEX_WAIT, value, timeout, 0, 0) == 0)
return 0;
#elif defined(__OpenBSD__)
if ((errno = futex(fut, FUTEX_WAIT, (int) value, timeout, NULL)) == 0)
return 0;
if (errno == ECANCELED)
errno = EINTR;
#elif defined(__FreeBSD__)
if (_umtx_op(fut, UMTX_OP_WAIT_UINT, value, 0, timeout) == 0)
return 0;
#elif defined (__APPLE__)
if (__ulock_wait(UL_COMPARE_AND_WAIT_SHARED, (void *) fut,
value, timeout ? timeout->tv_sec * 100 + timeout->tv_nsec / 1000 :
0) >
= 0)
return 0;
#else
errno = ENOSYS;
#endif

return -1;
}

static int
my_futex_wake(void *fut, int nwaiters)
{
#if defined(__linux__)
if (syscall(SYS_futex, fut, FUTEX_WAKE, nwaiters, NULL, 0, 0) >= 0)
return 0;
#elif defined(__OpenBSD__)
if (futex(fut, FUTEX_WAKE, nwaiters, NULL, NULL) >= 0)
return 0;
#elif defined(__FreeBSD__)
if (_umtx_op(fut, UMTX_OP_WAKE, nwaiters, 0, 0) == 0)
return 0;
#elif defined (__APPLE__)
if (__ulock_wake(UL_COMPARE_AND_WAIT_SHARED | (nwaiters > 1 ?
ULF_WAKE_ALL : 0), (void *) fut, 0) >= 0)
return 0;
if (errno == ENOENT)
return 0;
#else
errno = ENOSYS;
#endif

return -1;
}

int
main(int argc, char *argv[])
{
pid_t pid;
uint32_t *memory;
int status;

#if 1
memory = mmap(NULL, sizeof(uint32_t), PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_SHARED, -1, 0);
if (memory == MAP_FAILED) {
perror("mmap");
return EXIT_FAILURE;
}
#else
int shm_id;

shm_id = shmget(IPC_PRIVATE, sizeof(uint32_t), IPC_CREAT | 0666);
if (shm_id < 0) {
perror("shmget");
return EXIT_FAILURE;
}
memory = shmat(shm_id, NULL, 0);
if ((intptr_t) memory == -1) {
perror("shmat");
return EXIT_FAILURE;
}
#endif

*memory = 42;

pid = fork();
if (pid == -1) {
perror("fork");
return EXIT_FAILURE;
} else if (pid > 0) {
printf("hello from parent, will wait for futex...\n");
if (my_futex_wait_u32(memory, 42, NULL) < 0) {
perror("futex_wait");
wait(&status);
return EXIT_FAILURE;
}
wait(&status);
return EXIT_SUCCESS;
} else {
printf("hello from child, will wake futex...\n");
sleep(1);
if (my_futex_wake(memory, INT_MAX) < 0) {
perror("futex_wake");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
}