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