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