xref: /linux/tools/testing/selftests/bpf/progs/free_timer.c (revision 6f7e6393d1ce636bb7ec77a7fe7b77458fddf701)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright (C) 2025. Huawei Technologies Co., Ltd */
3 #include <linux/bpf.h>
4 #include <time.h>
5 #include <bpf/bpf_tracing.h>
6 #include <bpf/bpf_helpers.h>
7 
8 #define MAX_ENTRIES 8
9 
10 /* clang considers 'sum += 1' as usage but 'sum++' as non-usage.  GCC
11  * is more consistent and considers both 'sum += 1' and 'sum++' as
12  * non-usage.  This triggers warnings in the functions below.
13  *
14  * Starting with GCC 16 -Wunused-but-set-variable=2 can be used to
15  * mimic clang's behavior.  */
16 #if !defined(__clang__) && __GNUC__ > 15
17 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
18 #endif
19 
20 struct map_value {
21 	struct bpf_timer timer;
22 };
23 
24 struct {
25 	__uint(type, BPF_MAP_TYPE_HASH);
26 	__type(key, int);
27 	__type(value, struct map_value);
28 	__uint(max_entries, MAX_ENTRIES);
29 } map SEC(".maps");
30 
31 static int timer_cb(void *map, void *key, struct map_value *value)
32 {
33 	volatile int sum = 0;
34 	int i;
35 
36 	bpf_for(i, 0, 1024 * 1024) sum += i;
37 
38 	return 0;
39 }
40 
41 static int start_cb(int key)
42 {
43 	struct map_value *value;
44 
45 	value = bpf_map_lookup_elem(&map, (void *)&key);
46 	if (!value)
47 		return 0;
48 
49 	bpf_timer_init(&value->timer, &map, CLOCK_MONOTONIC);
50 	bpf_timer_set_callback(&value->timer, timer_cb);
51 	/* Hope 100us will be enough to wake-up and run the overwrite thread */
52 	bpf_timer_start(&value->timer, 100000, BPF_F_TIMER_CPU_PIN);
53 
54 	return 0;
55 }
56 
57 static int overwrite_cb(int key)
58 {
59 	struct map_value zero = {};
60 
61 	/* Free the timer which may run on other CPU */
62 	bpf_map_update_elem(&map, (void *)&key, &zero, BPF_ANY);
63 
64 	return 0;
65 }
66 
67 SEC("syscall")
68 int BPF_PROG(start_timer)
69 {
70 	bpf_loop(MAX_ENTRIES, start_cb, NULL, 0);
71 	return 0;
72 }
73 
74 SEC("syscall")
75 int BPF_PROG(overwrite_timer)
76 {
77 	bpf_loop(MAX_ENTRIES, overwrite_cb, NULL, 0);
78 	return 0;
79 }
80 
81 char _license[] SEC("license") = "GPL";
82