[PATCH 5/5] syscalls/epoll_wait15: Add EPOLLEXCLUSIVE test
Cyril Hrubis <[email protected]>
| Newsgroups | gmane.linux.ltp |
|---|---|
| Message-ID | <[email protected]> |
Tests that with EPOLLEXCLUSIVE only single waiter is woken up. Signed-off-by: Cyril Hrubis <[email protected]> --- runtest/syscalls | 1 + .../kernel/syscalls/epoll_wait/.gitignore | 1 + .../kernel/syscalls/epoll_wait/epoll_wait16.c | 115 ++++++++++++++++++ 3 files changed, 117 insertions(+) create mode 100644 testcases/kernel/syscalls/epoll_wait/epoll_wait16.c diff --git a/runtest/syscalls b/runtest/syscalls index af04b430e..f50931f56 100644 --- a/runtest/syscalls +++ b/runtest/syscalls @@ -205,6 +205,7 @@ epoll_wait12 epoll_wait12 epoll_wait13 epoll_wait13 epoll_wait14 epoll_wait14 epoll_wait15 epoll_wait15 +epoll_wait16 epoll_wait16 epoll_pwait01 epoll_pwait01 epoll_pwait02 epoll_pwait02 diff --git a/testcases/kernel/syscalls/epoll_wait/.gitignore b/testcases/kernel/syscalls/epoll_wait/.gitignore index 5ba917bdb..1804efbce 100644 --- a/testcases/kernel/syscalls/epoll_wait/.gitignore +++ b/testcases/kernel/syscalls/epoll_wait/.gitignore @@ -13,3 +13,4 @@ epoll_wait12 epoll_wait13 epoll_wait14 epoll_wait15 +epoll_wait16 diff --git a/testcases/kernel/syscalls/epoll_wait/epoll_wait16.c b/testcases/kernel/syscalls/epoll_wait/epoll_wait16.c new file mode 100644 index 000000000..39d8ea259 --- /dev/null +++ b/testcases/kernel/syscalls/epoll_wait/epoll_wait16.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (c) 2026 Cyril Hrubis <[email protected]> + */ + +/*\ + * Verify the EPOLLEXCLUSIVE wakeup semantics of :manpage:`epoll_ctl(2)` and + * :manpage:`epoll_wait(2)`. + * + * When a single target file descriptor is added with EPOLLEXCLUSIVE into + * several epoll instances that each have a waiter blocked in + * :manpage:`epoll_wait(2)`, one event on the target must wake exactly one + * waiter. This is the thundering-herd avoidance introduced in Linux 4.5. + * + * The test writes into a pipe in a loop and checks that on each write exactly + * one child process waiting on the fd is woken up. + */ + +#include <sys/epoll.h> +#include <sys/mman.h> + +#include "tst_test.h" +#include "tst_epoll.h" +#include "tst_atomic.h" +#include "lapi/epoll.h" + +#define NWAITERS 8 + +static int fds[2] = {-1, -1}; +static pid_t pids[NWAITERS]; +static tst_atomic_t *woken; + +static void setup(void) +{ + woken = SAFE_MMAP(NULL, sizeof(*woken), PROT_READ | PROT_WRITE, + MAP_SHARED | MAP_ANONYMOUS, -1, 0); +} + +static void cleanup(void) +{ + if (fds[0] != -1) { + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); + } + + if (woken) + SAFE_MUNMAP(woken, sizeof(*woken)); +} + +static void child(void) +{ + int efd; + struct epoll_event ev = {.events = EPOLLIN | EPOLLET | EPOLLEXCLUSIVE}; + + efd = SAFE_EPOLL_CREATE1(0); + SAFE_EPOLL_CTL(efd, EPOLL_CTL_ADD, fds[0], &ev); + + if (epoll_wait(efd, &ev, 1, 2000) == 1) { + tst_atomic_add_return(1, woken); + TST_CHECKPOINT_WAKE(0); + } + + SAFE_CLOSE(efd); + exit(0); +} + +static void run(void) +{ + int i, round, nwoken; + char c; + + tst_atomic_store(0, woken); + + SAFE_PIPE(fds); + + for (i = 0; i < NWAITERS; i++) { + pids[i] = SAFE_FORK(); + if (!pids[i]) + child(); + } + + for (i = 0; i < NWAITERS; i++) + TST_PROCESS_STATE_WAIT(pids[i], 'S', 0); + + for (round = 0; round < NWAITERS; round++) { + SAFE_WRITE(SAFE_WRITE_ALL, fds[1], "x", 1); + + TST_CHECKPOINT_WAIT(0); + + nwoken = tst_atomic_load(woken); + if (nwoken != round+1) { + tst_res(TFAIL, + "event %d woke %d waiters in total, expected %d", + round, nwoken, round); + break; + } + + SAFE_READ(1, fds[0], &c, 1); + } + + if (round == NWAITERS) + tst_res(TPASS, "each event woke exactly one waiter"); + + SAFE_CLOSE(fds[0]); + SAFE_CLOSE(fds[1]); +} + +static struct tst_test test = { + .setup = setup, + .cleanup = cleanup, + .test_all = run, + .forks_child = 1, + .needs_checkpoints = 1, + .min_kver = "4.5", +}; -- 2.54.0 -- Mailing list info: https://lists.linux.it/listinfo/ltp