xref: /linux/tools/testing/selftests/bpf/prog_tests/timer_lockup.c (revision fcc79e1714e8c2b8e216dc3149812edd37884eef)
1 // SPDX-License-Identifier: GPL-2.0
2 
3 #define _GNU_SOURCE
4 #include <sched.h>
5 #include <test_progs.h>
6 #include <pthread.h>
7 #include <network_helpers.h>
8 #include <sys/sysinfo.h>
9 
10 #include "timer_lockup.skel.h"
11 
12 static long cpu;
13 static int *timer1_err;
14 static int *timer2_err;
15 static bool skip;
16 
17 volatile int k = 0;
18 
19 static void *timer_lockup_thread(void *arg)
20 {
21 	LIBBPF_OPTS(bpf_test_run_opts, opts,
22 		.data_in	= &pkt_v4,
23 		.data_size_in	= sizeof(pkt_v4),
24 		.repeat		= 1000,
25 	);
26 	int i, prog_fd = *(int *)arg;
27 	cpu_set_t cpuset;
28 
29 	CPU_ZERO(&cpuset);
30 	CPU_SET(__sync_fetch_and_add(&cpu, 1), &cpuset);
31 	ASSERT_OK(pthread_setaffinity_np(pthread_self(), sizeof(cpuset),
32 				         &cpuset),
33 		  "cpu affinity");
34 
35 	for (i = 0; !READ_ONCE(*timer1_err) && !READ_ONCE(*timer2_err); i++) {
36 		bpf_prog_test_run_opts(prog_fd, &opts);
37 		/* Skip the test if we can't reproduce the race in a reasonable
38 		 * amount of time.
39 		 */
40 		if (i > 50) {
41 			WRITE_ONCE(skip, true);
42 			break;
43 		}
44 	}
45 
46 	return NULL;
47 }
48 
49 void test_timer_lockup(void)
50 {
51 	int timer1_prog, timer2_prog;
52 	struct timer_lockup *skel;
53 	pthread_t thrds[2];
54 	void *ret;
55 
56 	if (get_nprocs() < 2) {
57 		test__skip();
58 		return;
59 	}
60 
61 	skel = timer_lockup__open_and_load();
62 	if (!ASSERT_OK_PTR(skel, "timer_lockup__open_and_load"))
63 		return;
64 
65 	timer1_prog = bpf_program__fd(skel->progs.timer1_prog);
66 	timer2_prog = bpf_program__fd(skel->progs.timer2_prog);
67 
68 	timer1_err = &skel->bss->timer1_err;
69 	timer2_err = &skel->bss->timer2_err;
70 
71 	if (!ASSERT_OK(pthread_create(&thrds[0], NULL, timer_lockup_thread,
72 				      &timer1_prog),
73 		       "pthread_create thread1"))
74 		goto out;
75 	if (!ASSERT_OK(pthread_create(&thrds[1], NULL, timer_lockup_thread,
76 				      &timer2_prog),
77 		       "pthread_create thread2")) {
78 		pthread_exit(&thrds[0]);
79 		goto out;
80 	}
81 
82 	pthread_join(thrds[1], &ret);
83 	pthread_join(thrds[0], &ret);
84 
85 	if (skip) {
86 		test__skip();
87 		goto out;
88 	}
89 
90 	if (*timer1_err != -EDEADLK && *timer1_err != 0)
91 		ASSERT_FAIL("timer1_err bad value");
92 	if (*timer2_err != -EDEADLK && *timer2_err != 0)
93 		ASSERT_FAIL("timer2_err bad value");
94 out:
95 	timer_lockup__destroy(skel);
96 	return;
97 }
98