mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00
166 lines
3.4 KiB
C
166 lines
3.4 KiB
C
![]() |
// 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);
|
||
|
}
|