tools/testing/selftests/bpf/test_progs.c

Source file repositories/reference/linux-study-clean/tools/testing/selftests/bpf/test_progs.c

File Facts

System
Linux kernel
Corpus path
tools/testing/selftests/bpf/test_progs.c
Extension
.c
Size
52402 bytes
Lines
2189
Domain
Support Tooling And Documentation
Bucket
tools
Inferred role
Support Tooling And Documentation: implementation source
Status
source implementation candidate

Why This File Exists

Repository support layer: documentation, build tooling, samples, user-space helper tools, generated initramfs support, licenses, and validation utilities.

Dependency Surface

Detected Declarations

Annotated Snippet

struct prog_test_def {
	const char *test_name;
	int test_num;
	void (*run_test)(void);
	void (*run_serial_test)(void);
	bool should_run;
	bool not_built;
	bool selected;
	bool need_cgroup_cleanup;
	bool should_tmon;
};

/* Override C runtime library's usleep() implementation to ensure nanosleep()
 * is always called. Usleep is frequently used in selftests as a way to
 * trigger kprobe and tracepoints.
 */
int usleep(useconds_t usec)
{
	struct timespec ts = {
		.tv_sec = usec / 1000000,
		.tv_nsec = (usec % 1000000) * 1000,
	};

	return syscall(__NR_nanosleep, &ts, NULL);
}

/* Watchdog timer is started by watchdog_start() and stopped by watchdog_stop().
 * If timer is active for longer than env.secs_till_notify,
 * it prints the name of the current test to the stderr.
 * If timer is active for longer than env.secs_till_kill,
 * it kills the thread executing the test by sending a SIGSEGV signal to it.
 */
static void watchdog_timer_func(union sigval sigval)
{
	struct itimerspec timeout = {};
	char test_name[256];
	int err;

	if (env.subtest_state)
		snprintf(test_name, sizeof(test_name), "%s/%s",
			 env.test->test_name, env.subtest_state->name);
	else
		snprintf(test_name, sizeof(test_name), "%s",
			 env.test->test_name);

	switch (env.watchdog_state) {
	case WD_NOTIFY:
		fprintf(env.stderr_saved, "WATCHDOG: test case %s executes for %d seconds...\n",
			test_name, env.secs_till_notify);
		timeout.it_value.tv_sec = env.secs_till_kill - env.secs_till_notify;
		env.watchdog_state = WD_KILL;
		err = timer_settime(env.watchdog, 0, &timeout, NULL);
		if (err)
			fprintf(env.stderr_saved, "Failed to arm watchdog timer\n");
		break;
	case WD_KILL:
		fprintf(env.stderr_saved,
			"WATCHDOG: test case %s executes for %d seconds, terminating with SIGSEGV\n",
			test_name, env.secs_till_kill);
		pthread_kill(env.main_thread, SIGSEGV);
		break;
	}
}

static void watchdog_start(void)
{
	struct itimerspec timeout = {};
	int err;

	if (env.secs_till_kill == 0)
		return;
	if (env.secs_till_notify > 0) {
		env.watchdog_state = WD_NOTIFY;
		timeout.it_value.tv_sec = env.secs_till_notify;
	} else {
		env.watchdog_state = WD_KILL;
		timeout.it_value.tv_sec = env.secs_till_kill;
	}
	err = timer_settime(env.watchdog, 0, &timeout, NULL);
	if (err)
		fprintf(env.stderr_saved, "Failed to start watchdog timer\n");
}

static void watchdog_stop(void)
{
	struct itimerspec timeout = {};
	int err;

	env.watchdog_state = WD_NOTIFY;
	err = timer_settime(env.watchdog, 0, &timeout, NULL);

Annotation

Implementation Notes