1f08c3bdfSopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
2f08c3bdfSopenharmony_ci/*
3f08c3bdfSopenharmony_ci * Copyright (C) 2021 SUSE LLC Andrea Cervesato <andrea.cervesato@suse.com>
4f08c3bdfSopenharmony_ci */
5f08c3bdfSopenharmony_ci
6f08c3bdfSopenharmony_ci/*\
7f08c3bdfSopenharmony_ci * [Description]
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * This test verifies futex_waitv syscall using shared data.
10f08c3bdfSopenharmony_ci */
11f08c3bdfSopenharmony_ci
12f08c3bdfSopenharmony_ci#define _GNU_SOURCE
13f08c3bdfSopenharmony_ci#include <unistd.h>
14f08c3bdfSopenharmony_ci#include <time.h>
15f08c3bdfSopenharmony_ci#include <sys/shm.h>
16f08c3bdfSopenharmony_ci#include "tst_test.h"
17f08c3bdfSopenharmony_ci#include "lapi/futex.h"
18f08c3bdfSopenharmony_ci#include "lapi/syscalls.h"
19f08c3bdfSopenharmony_ci#include "futex2test.h"
20f08c3bdfSopenharmony_ci#include "futex_utils.h"
21f08c3bdfSopenharmony_ci#include "tst_safe_pthread.h"
22f08c3bdfSopenharmony_ci#include "tst_safe_clocks.h"
23f08c3bdfSopenharmony_ci#include "tst_safe_sysv_ipc.h"
24f08c3bdfSopenharmony_ci
25f08c3bdfSopenharmony_cistatic char *str_numfutex;
26f08c3bdfSopenharmony_cistatic int numfutex = 30;
27f08c3bdfSopenharmony_ci
28f08c3bdfSopenharmony_cistatic struct futex_waitv *waitv;
29f08c3bdfSopenharmony_cistatic unsigned int waitv_allocated;
30f08c3bdfSopenharmony_cistatic int *shmids;
31f08c3bdfSopenharmony_ci
32f08c3bdfSopenharmony_cistatic void setup(void)
33f08c3bdfSopenharmony_ci{
34f08c3bdfSopenharmony_ci	struct futex_test_variants tv = futex_variant();
35f08c3bdfSopenharmony_ci	int i;
36f08c3bdfSopenharmony_ci
37f08c3bdfSopenharmony_ci	tst_res(TINFO, "Testing variant: %s", tv.desc);
38f08c3bdfSopenharmony_ci	futex_supported_by_kernel(tv.fntype);
39f08c3bdfSopenharmony_ci
40f08c3bdfSopenharmony_ci	if (tst_parse_int(str_numfutex, &numfutex, 1, FUTEX_WAITV_MAX))
41f08c3bdfSopenharmony_ci		tst_brk(TBROK, "Invalid number of futexes '%s'", str_numfutex);
42f08c3bdfSopenharmony_ci
43f08c3bdfSopenharmony_ci	waitv = tst_alloc(sizeof(struct futex_waitv) * numfutex);
44f08c3bdfSopenharmony_ci	memset(waitv, 0, sizeof(struct futex_waitv) * numfutex);
45f08c3bdfSopenharmony_ci	shmids = tst_alloc(sizeof(int*) * numfutex);
46f08c3bdfSopenharmony_ci	memset(shmids, 0, sizeof(int*) * numfutex);
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_ci	for (i = 0; i < numfutex; i++) {
49f08c3bdfSopenharmony_ci		shmids[i] = SAFE_SHMGET(IPC_PRIVATE, 4096, IPC_CREAT | 0666);
50f08c3bdfSopenharmony_ci		waitv[i].uaddr = (uintptr_t)SAFE_SHMAT(shmids[i], NULL, 0);
51f08c3bdfSopenharmony_ci		waitv[i].flags = FUTEX_32;
52f08c3bdfSopenharmony_ci		waitv[i].val = 0;
53f08c3bdfSopenharmony_ci	}
54f08c3bdfSopenharmony_ci	waitv_allocated = tst_variant + 1;
55f08c3bdfSopenharmony_ci}
56f08c3bdfSopenharmony_ci
57f08c3bdfSopenharmony_cistatic void cleanup(void)
58f08c3bdfSopenharmony_ci{
59f08c3bdfSopenharmony_ci	int i;
60f08c3bdfSopenharmony_ci
61f08c3bdfSopenharmony_ci	if (waitv_allocated != (tst_variant + 1))
62f08c3bdfSopenharmony_ci		return;
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci	for (i = 0; i < numfutex; i++) {
65f08c3bdfSopenharmony_ci		if (!waitv[i].uaddr)
66f08c3bdfSopenharmony_ci			continue;
67f08c3bdfSopenharmony_ci
68f08c3bdfSopenharmony_ci		SAFE_SHMDT((void *)(uintptr_t)waitv[i].uaddr);
69f08c3bdfSopenharmony_ci		SAFE_SHMCTL(shmids[i], IPC_RMID, NULL);
70f08c3bdfSopenharmony_ci	}
71f08c3bdfSopenharmony_ci}
72f08c3bdfSopenharmony_ci
73f08c3bdfSopenharmony_cistatic void *threaded(LTP_ATTRIBUTE_UNUSED void *arg)
74f08c3bdfSopenharmony_ci{
75f08c3bdfSopenharmony_ci	struct futex_test_variants tv = futex_variant();
76f08c3bdfSopenharmony_ci
77f08c3bdfSopenharmony_ci	TST_RETRY_FUNC(futex_wake(tv.fntype,
78f08c3bdfSopenharmony_ci		(void *)(uintptr_t)waitv[numfutex - 1].uaddr,
79f08c3bdfSopenharmony_ci		1, 0), futex_waked_someone);
80f08c3bdfSopenharmony_ci
81f08c3bdfSopenharmony_ci	return NULL;
82f08c3bdfSopenharmony_ci}
83f08c3bdfSopenharmony_ci
84f08c3bdfSopenharmony_cistatic void run(void)
85f08c3bdfSopenharmony_ci{
86f08c3bdfSopenharmony_ci	struct timespec to;
87f08c3bdfSopenharmony_ci	pthread_t t;
88f08c3bdfSopenharmony_ci
89f08c3bdfSopenharmony_ci	SAFE_PTHREAD_CREATE(&t, NULL, threaded, NULL);
90f08c3bdfSopenharmony_ci
91f08c3bdfSopenharmony_ci	/* setting absolute timeout for futex2 */
92f08c3bdfSopenharmony_ci	SAFE_CLOCK_GETTIME(CLOCK_MONOTONIC, &to);
93f08c3bdfSopenharmony_ci	to.tv_sec += 5;
94f08c3bdfSopenharmony_ci
95f08c3bdfSopenharmony_ci	TEST(futex_waitv(waitv, numfutex, 0, &to, CLOCK_MONOTONIC));
96f08c3bdfSopenharmony_ci	if (TST_RET < 0) {
97f08c3bdfSopenharmony_ci		tst_brk(TBROK | TTERRNO, "futex_waitv returned: %ld", TST_RET);
98f08c3bdfSopenharmony_ci	} else if (TST_RET != numfutex - 1) {
99f08c3bdfSopenharmony_ci		tst_res(TFAIL, "futex_waitv returned: %ld, expecting %d",
100f08c3bdfSopenharmony_ci			TST_RET, numfutex - 1);
101f08c3bdfSopenharmony_ci	}
102f08c3bdfSopenharmony_ci
103f08c3bdfSopenharmony_ci	SAFE_PTHREAD_JOIN(t, NULL);
104f08c3bdfSopenharmony_ci	tst_res(TPASS, "futex_waitv returned correctly");
105f08c3bdfSopenharmony_ci}
106f08c3bdfSopenharmony_ci
107f08c3bdfSopenharmony_cistatic struct tst_test test = {
108f08c3bdfSopenharmony_ci	.test_all = run,
109f08c3bdfSopenharmony_ci	.setup = setup,
110f08c3bdfSopenharmony_ci	.cleanup = cleanup,
111f08c3bdfSopenharmony_ci	.min_kver = "5.16",
112f08c3bdfSopenharmony_ci	.test_variants = FUTEX_VARIANTS,
113f08c3bdfSopenharmony_ci	.options =
114f08c3bdfSopenharmony_ci		(struct tst_option[]){
115f08c3bdfSopenharmony_ci			{ "n:", &str_numfutex, "Number of futex (default 30)" },
116f08c3bdfSopenharmony_ci			{},
117f08c3bdfSopenharmony_ci		},
118f08c3bdfSopenharmony_ci};
119