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 19 static void start_threads(struct run_ctx *ctx) 20 { 21 ctx->start = true; 22 } 23 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 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 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 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 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