xref: /linux/lib/test_context-analysis.c (revision f16a802d402d735a55731f8c94952b3bbb5ddfe8)
19b00c160SMarco Elver // SPDX-License-Identifier: GPL-2.0-only
29b00c160SMarco Elver /*
39b00c160SMarco Elver  * Compile-only tests for common patterns that should not generate false
49b00c160SMarco Elver  * positive errors when compiled with Clang's context analysis.
59b00c160SMarco Elver  */
69b00c160SMarco Elver 
79b00c160SMarco Elver #include <linux/build_bug.h>
8*f16a802dSMarco Elver #include <linux/spinlock.h>
99b00c160SMarco Elver 
109b00c160SMarco Elver /*
119b00c160SMarco Elver  * Test that helper macros work as expected.
129b00c160SMarco Elver  */
139b00c160SMarco Elver static void __used test_common_helpers(void)
149b00c160SMarco Elver {
159b00c160SMarco Elver 	BUILD_BUG_ON(context_unsafe(3) != 3); /* plain expression */
169b00c160SMarco Elver 	BUILD_BUG_ON(context_unsafe((void)2; 3) != 3); /* does not swallow semi-colon */
179b00c160SMarco Elver 	BUILD_BUG_ON(context_unsafe((void)2, 3) != 3); /* does not swallow commas */
189b00c160SMarco Elver 	context_unsafe(do { } while (0)); /* works with void statements */
199b00c160SMarco Elver }
20*f16a802dSMarco Elver 
21*f16a802dSMarco Elver #define TEST_SPINLOCK_COMMON(class, type, type_init, type_lock, type_unlock, type_trylock, op)	\
22*f16a802dSMarco Elver 	struct test_##class##_data {								\
23*f16a802dSMarco Elver 		type lock;									\
24*f16a802dSMarco Elver 		int counter __guarded_by(&lock);						\
25*f16a802dSMarco Elver 		int *pointer __pt_guarded_by(&lock);						\
26*f16a802dSMarco Elver 	};											\
27*f16a802dSMarco Elver 	static void __used test_##class##_init(struct test_##class##_data *d)			\
28*f16a802dSMarco Elver 	{											\
29*f16a802dSMarco Elver 		type_init(&d->lock);								\
30*f16a802dSMarco Elver 		d->counter = 0;									\
31*f16a802dSMarco Elver 	}											\
32*f16a802dSMarco Elver 	static void __used test_##class(struct test_##class##_data *d)				\
33*f16a802dSMarco Elver 	{											\
34*f16a802dSMarco Elver 		unsigned long flags;								\
35*f16a802dSMarco Elver 		d->pointer++;									\
36*f16a802dSMarco Elver 		type_lock(&d->lock);								\
37*f16a802dSMarco Elver 		op(d->counter);									\
38*f16a802dSMarco Elver 		op(*d->pointer);								\
39*f16a802dSMarco Elver 		type_unlock(&d->lock);								\
40*f16a802dSMarco Elver 		type_lock##_irq(&d->lock);							\
41*f16a802dSMarco Elver 		op(d->counter);									\
42*f16a802dSMarco Elver 		op(*d->pointer);								\
43*f16a802dSMarco Elver 		type_unlock##_irq(&d->lock);							\
44*f16a802dSMarco Elver 		type_lock##_bh(&d->lock);							\
45*f16a802dSMarco Elver 		op(d->counter);									\
46*f16a802dSMarco Elver 		op(*d->pointer);								\
47*f16a802dSMarco Elver 		type_unlock##_bh(&d->lock);							\
48*f16a802dSMarco Elver 		type_lock##_irqsave(&d->lock, flags);						\
49*f16a802dSMarco Elver 		op(d->counter);									\
50*f16a802dSMarco Elver 		op(*d->pointer);								\
51*f16a802dSMarco Elver 		type_unlock##_irqrestore(&d->lock, flags);					\
52*f16a802dSMarco Elver 	}											\
53*f16a802dSMarco Elver 	static void __used test_##class##_trylock(struct test_##class##_data *d)		\
54*f16a802dSMarco Elver 	{											\
55*f16a802dSMarco Elver 		if (type_trylock(&d->lock)) {							\
56*f16a802dSMarco Elver 			op(d->counter);								\
57*f16a802dSMarco Elver 			type_unlock(&d->lock);							\
58*f16a802dSMarco Elver 		}										\
59*f16a802dSMarco Elver 	}											\
60*f16a802dSMarco Elver 	static void __used test_##class##_assert(struct test_##class##_data *d)			\
61*f16a802dSMarco Elver 	{											\
62*f16a802dSMarco Elver 		lockdep_assert_held(&d->lock);							\
63*f16a802dSMarco Elver 		op(d->counter);									\
64*f16a802dSMarco Elver 	}											\
65*f16a802dSMarco Elver 	static void __used test_##class##_guard(struct test_##class##_data *d)			\
66*f16a802dSMarco Elver 	{											\
67*f16a802dSMarco Elver 		{ guard(class)(&d->lock);		op(d->counter); }			\
68*f16a802dSMarco Elver 		{ guard(class##_irq)(&d->lock);		op(d->counter); }			\
69*f16a802dSMarco Elver 		{ guard(class##_irqsave)(&d->lock);	op(d->counter); }			\
70*f16a802dSMarco Elver 	}
71*f16a802dSMarco Elver 
72*f16a802dSMarco Elver #define TEST_OP_RW(x) (x)++
73*f16a802dSMarco Elver #define TEST_OP_RO(x) ((void)(x))
74*f16a802dSMarco Elver 
75*f16a802dSMarco Elver TEST_SPINLOCK_COMMON(raw_spinlock,
76*f16a802dSMarco Elver 		     raw_spinlock_t,
77*f16a802dSMarco Elver 		     raw_spin_lock_init,
78*f16a802dSMarco Elver 		     raw_spin_lock,
79*f16a802dSMarco Elver 		     raw_spin_unlock,
80*f16a802dSMarco Elver 		     raw_spin_trylock,
81*f16a802dSMarco Elver 		     TEST_OP_RW);
82*f16a802dSMarco Elver static void __used test_raw_spinlock_trylock_extra(struct test_raw_spinlock_data *d)
83*f16a802dSMarco Elver {
84*f16a802dSMarco Elver 	unsigned long flags;
85*f16a802dSMarco Elver 
86*f16a802dSMarco Elver 	if (raw_spin_trylock_irq(&d->lock)) {
87*f16a802dSMarco Elver 		d->counter++;
88*f16a802dSMarco Elver 		raw_spin_unlock_irq(&d->lock);
89*f16a802dSMarco Elver 	}
90*f16a802dSMarco Elver 	if (raw_spin_trylock_irqsave(&d->lock, flags)) {
91*f16a802dSMarco Elver 		d->counter++;
92*f16a802dSMarco Elver 		raw_spin_unlock_irqrestore(&d->lock, flags);
93*f16a802dSMarco Elver 	}
94*f16a802dSMarco Elver 	scoped_cond_guard(raw_spinlock_try, return, &d->lock) {
95*f16a802dSMarco Elver 		d->counter++;
96*f16a802dSMarco Elver 	}
97*f16a802dSMarco Elver }
98*f16a802dSMarco Elver 
99*f16a802dSMarco Elver TEST_SPINLOCK_COMMON(spinlock,
100*f16a802dSMarco Elver 		     spinlock_t,
101*f16a802dSMarco Elver 		     spin_lock_init,
102*f16a802dSMarco Elver 		     spin_lock,
103*f16a802dSMarco Elver 		     spin_unlock,
104*f16a802dSMarco Elver 		     spin_trylock,
105*f16a802dSMarco Elver 		     TEST_OP_RW);
106*f16a802dSMarco Elver static void __used test_spinlock_trylock_extra(struct test_spinlock_data *d)
107*f16a802dSMarco Elver {
108*f16a802dSMarco Elver 	unsigned long flags;
109*f16a802dSMarco Elver 
110*f16a802dSMarco Elver 	if (spin_trylock_irq(&d->lock)) {
111*f16a802dSMarco Elver 		d->counter++;
112*f16a802dSMarco Elver 		spin_unlock_irq(&d->lock);
113*f16a802dSMarco Elver 	}
114*f16a802dSMarco Elver 	if (spin_trylock_irqsave(&d->lock, flags)) {
115*f16a802dSMarco Elver 		d->counter++;
116*f16a802dSMarco Elver 		spin_unlock_irqrestore(&d->lock, flags);
117*f16a802dSMarco Elver 	}
118*f16a802dSMarco Elver 	scoped_cond_guard(spinlock_try, return, &d->lock) {
119*f16a802dSMarco Elver 		d->counter++;
120*f16a802dSMarco Elver 	}
121*f16a802dSMarco Elver }
122*f16a802dSMarco Elver 
123*f16a802dSMarco Elver TEST_SPINLOCK_COMMON(write_lock,
124*f16a802dSMarco Elver 		     rwlock_t,
125*f16a802dSMarco Elver 		     rwlock_init,
126*f16a802dSMarco Elver 		     write_lock,
127*f16a802dSMarco Elver 		     write_unlock,
128*f16a802dSMarco Elver 		     write_trylock,
129*f16a802dSMarco Elver 		     TEST_OP_RW);
130*f16a802dSMarco Elver static void __used test_write_trylock_extra(struct test_write_lock_data *d)
131*f16a802dSMarco Elver {
132*f16a802dSMarco Elver 	unsigned long flags;
133*f16a802dSMarco Elver 
134*f16a802dSMarco Elver 	if (write_trylock_irqsave(&d->lock, flags)) {
135*f16a802dSMarco Elver 		d->counter++;
136*f16a802dSMarco Elver 		write_unlock_irqrestore(&d->lock, flags);
137*f16a802dSMarco Elver 	}
138*f16a802dSMarco Elver }
139*f16a802dSMarco Elver 
140*f16a802dSMarco Elver TEST_SPINLOCK_COMMON(read_lock,
141*f16a802dSMarco Elver 		     rwlock_t,
142*f16a802dSMarco Elver 		     rwlock_init,
143*f16a802dSMarco Elver 		     read_lock,
144*f16a802dSMarco Elver 		     read_unlock,
145*f16a802dSMarco Elver 		     read_trylock,
146*f16a802dSMarco Elver 		     TEST_OP_RO);
147