xref: /linux/tools/testing/selftests/bpf/prog_tests/free_timer.c (revision d0d106a2bd21499901299160744e5fe9f4c83ddb)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2025. Huawei Technologies Co., Ltd */
3 #define _GNU_SOURCE
4 #include <unistd.h>
5 #include <sys/syscall.h>
6 #include <test_progs.h>
7 
8 #include "free_timer.skel.h"
9 
10 struct run_ctx {
11 	struct bpf_program *start_prog;
12 	struct bpf_program *overwrite_prog;
13 	pthread_barrier_t notify;
14 	int loop;
15 	bool start;
16 	bool stop;
17 };
18 
start_threads(struct run_ctx * ctx)19 static void start_threads(struct run_ctx *ctx)
20 {
21 	ctx->start = true;
22 }
23 
stop_threads(struct run_ctx * ctx)24 static void stop_threads(struct run_ctx *ctx)
25 {
26 	ctx->stop = true;
27 	/* Guarantee the order between ->stop and ->start */
28 	__atomic_store_n(&ctx->start, true, __ATOMIC_RELEASE);
29 }
30 
wait_for_start(struct run_ctx * ctx)31 static int wait_for_start(struct run_ctx *ctx)
32 {
33 	while (!__atomic_load_n(&ctx->start, __ATOMIC_ACQUIRE))
34 		usleep(10);
35 
36 	return ctx->stop;
37 }
38 
overwrite_timer_fn(void * arg)39 static void *overwrite_timer_fn(void *arg)
40 {
41 	struct run_ctx *ctx = arg;
42 	int loop, fd, err;
43 	cpu_set_t cpuset;
44 	long ret = 0;
45 
46 	/* Pin on CPU 0 */
47 	CPU_ZERO(&cpuset);
48 	CPU_SET(0, &cpuset);
49 	pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
50 
51 	/* Is the thread being stopped ? */
52 	err = wait_for_start(ctx);
53 	if (err)
54 		return NULL;
55 
56 	fd = bpf_program__fd(ctx->overwrite_prog);
57 	loop = ctx->loop;
58 	while (loop-- > 0) {
59 		LIBBPF_OPTS(bpf_test_run_opts, opts);
60 
61 		/* Wait for start thread to complete */
62 		pthread_barrier_wait(&ctx->notify);
63 
64 		/* Overwrite timers */
65 		err = bpf_prog_test_run_opts(fd, &opts);
66 		if (err)
67 			ret |= 1;
68 		else if (opts.retval)
69 			ret |= 2;
70 
71 		/* Notify start thread to start timers */
72 		pthread_barrier_wait(&ctx->notify);
73 	}
74 
75 	return (void *)ret;
76 }
77 
start_timer_fn(void * arg)78 static void *start_timer_fn(void *arg)
79 {
80 	struct run_ctx *ctx = arg;
81 	int loop, fd, err;
82 	cpu_set_t cpuset;
83 	long ret = 0;
84 
85 	/* Pin on CPU 1 */
86 	CPU_ZERO(&cpuset);
87 	CPU_SET(1, &cpuset);
88 	pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
89 
90 	/* Is the thread being stopped ? */
91 	err = wait_for_start(ctx);
92 	if (err)
93 		return NULL;
94 
95 	fd = bpf_program__fd(ctx->start_prog);
96 	loop = ctx->loop;
97 	while (loop-- > 0) {
98 		LIBBPF_OPTS(bpf_test_run_opts, opts);
99 
100 		/* Run the prog to start timer */
101 		err = bpf_prog_test_run_opts(fd, &opts);
102 		if (err)
103 			ret |= 4;
104 		else if (opts.retval)
105 			ret |= 8;
106 
107 		/* Notify overwrite thread to do overwrite */
108 		pthread_barrier_wait(&ctx->notify);
109 
110 		/* Wait for overwrite thread to complete */
111 		pthread_barrier_wait(&ctx->notify);
112 	}
113 
114 	return (void *)ret;
115 }
116 
test_free_timer(void)117 void test_free_timer(void)
118 {
119 	struct free_timer *skel;
120 	struct bpf_program *prog;
121 	struct run_ctx ctx;
122 	pthread_t tid[2];
123 	void *ret;
124 	int err;
125 
126 	skel = free_timer__open_and_load();
127 	if (!ASSERT_OK_PTR(skel, "open_load"))
128 		return;
129 
130 	memset(&ctx, 0, sizeof(ctx));
131 
132 	prog = bpf_object__find_program_by_name(skel->obj, "start_timer");
133 	if (!ASSERT_OK_PTR(prog, "find start prog"))
134 		goto out;
135 	ctx.start_prog = prog;
136 
137 	prog = bpf_object__find_program_by_name(skel->obj, "overwrite_timer");
138 	if (!ASSERT_OK_PTR(prog, "find overwrite prog"))
139 		goto out;
140 	ctx.overwrite_prog = prog;
141 
142 	pthread_barrier_init(&ctx.notify, NULL, 2);
143 	ctx.loop = 10;
144 
145 	err = pthread_create(&tid[0], NULL, start_timer_fn, &ctx);
146 	if (!ASSERT_OK(err, "create start_timer"))
147 		goto out;
148 
149 	err = pthread_create(&tid[1], NULL, overwrite_timer_fn, &ctx);
150 	if (!ASSERT_OK(err, "create overwrite_timer")) {
151 		stop_threads(&ctx);
152 		goto out;
153 	}
154 
155 	start_threads(&ctx);
156 
157 	ret = NULL;
158 	err = pthread_join(tid[0], &ret);
159 	ASSERT_EQ(err | (long)ret, 0, "start_timer");
160 	ret = NULL;
161 	err = pthread_join(tid[1], &ret);
162 	ASSERT_EQ(err | (long)ret, 0, "overwrite_timer");
163 out:
164 	free_timer__destroy(skel);
165 }
166