#define _GNU_SOURCE
#include <sched.h>
#include <pthread.h>
#include <test_progs.h>
#include "timer_start_delete_race.skel.h"
#define ITERATIONS 1000
struct ctx {
struct timer_start_delete_race *skel;
volatile bool start;
volatile bool stop;
int errors;
};
static void *start_timer_thread(void *arg)
{
struct ctx *ctx = arg;
cpu_set_t cpuset;
int fd, i;
CPU_ZERO(&cpuset);
CPU_SET(0, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
while (!ctx->start && !ctx->stop)
usleep(1);
if (ctx->stop)
return NULL;
fd = bpf_program__fd(ctx->skel->progs.start_timer);
for (i = 0; i < ITERATIONS && !ctx->stop; i++) {
LIBBPF_OPTS(bpf_test_run_opts, opts);
int err;
err = bpf_prog_test_run_opts(fd, &opts);
if (err || opts.retval) {
ctx->errors++;
break;
}
}
return NULL;
}
static void *delete_elem_thread(void *arg)
{
struct ctx *ctx = arg;
cpu_set_t cpuset;
int fd, i;
CPU_ZERO(&cpuset);
CPU_SET(1, &cpuset);
pthread_setaffinity_np(pthread_self(), sizeof(cpuset), &cpuset);
while (!ctx->start && !ctx->stop)
usleep(1);
if (ctx->stop)
return NULL;
fd = bpf_program__fd(ctx->skel->progs.delete_elem);
for (i = 0; i < ITERATIONS && !ctx->stop; i++) {
LIBBPF_OPTS(bpf_test_run_opts, opts);
int err;
err = bpf_prog_test_run_opts(fd, &opts);
if (err || opts.retval) {
ctx->errors++;
break;
}
}
return NULL;
}
void test_timer_start_delete_race(void)
{
struct timer_start_delete_race *skel;
pthread_t threads[2];
struct ctx ctx = {};
int err;
skel = timer_start_delete_race__open_and_load();
if (!ASSERT_OK_PTR(skel, "skel_open_and_load"))
return;
ctx.skel = skel;
err = pthread_create(&threads[0], NULL, start_timer_thread, &ctx);
if (!ASSERT_OK(err, "create start_timer_thread")) {
ctx.stop = true;
goto cleanup;
}
err = pthread_create(&threads[1], NULL, delete_elem_thread, &ctx);
if (!ASSERT_OK(err, "create delete_elem_thread")) {
ctx.stop = true;
pthread_join(threads[0], NULL);
goto cleanup;
}
ctx.start = true;
pthread_join(threads[0], NULL);
pthread_join(threads[1], NULL);
ASSERT_EQ(ctx.errors, 0, "thread_errors");
cleanup:
timer_start_delete_race__destroy(skel);
}