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