xref: /linux/lib/test_context-analysis.c (revision 370f0a345a70fe36d0185abf87c7ee8e70572e06)
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*370f0a34SMarco Elver #include <linux/mutex.h>
9f16a802dSMarco Elver #include <linux/spinlock.h>
109b00c160SMarco Elver 
119b00c160SMarco Elver /*
129b00c160SMarco Elver  * Test that helper macros work as expected.
139b00c160SMarco Elver  */
149b00c160SMarco Elver static void __used test_common_helpers(void)
159b00c160SMarco Elver {
169b00c160SMarco Elver 	BUILD_BUG_ON(context_unsafe(3) != 3); /* plain expression */
179b00c160SMarco Elver 	BUILD_BUG_ON(context_unsafe((void)2; 3) != 3); /* does not swallow semi-colon */
189b00c160SMarco Elver 	BUILD_BUG_ON(context_unsafe((void)2, 3) != 3); /* does not swallow commas */
199b00c160SMarco Elver 	context_unsafe(do { } while (0)); /* works with void statements */
209b00c160SMarco Elver }
21f16a802dSMarco Elver 
22f16a802dSMarco Elver #define TEST_SPINLOCK_COMMON(class, type, type_init, type_lock, type_unlock, type_trylock, op)	\
23f16a802dSMarco Elver 	struct test_##class##_data {								\
24f16a802dSMarco Elver 		type lock;									\
25f16a802dSMarco Elver 		int counter __guarded_by(&lock);						\
26f16a802dSMarco Elver 		int *pointer __pt_guarded_by(&lock);						\
27f16a802dSMarco Elver 	};											\
28f16a802dSMarco Elver 	static void __used test_##class##_init(struct test_##class##_data *d)			\
29f16a802dSMarco Elver 	{											\
30f16a802dSMarco Elver 		type_init(&d->lock);								\
31f16a802dSMarco Elver 		d->counter = 0;									\
32f16a802dSMarco Elver 	}											\
33f16a802dSMarco Elver 	static void __used test_##class(struct test_##class##_data *d)				\
34f16a802dSMarco Elver 	{											\
35f16a802dSMarco Elver 		unsigned long flags;								\
36f16a802dSMarco Elver 		d->pointer++;									\
37f16a802dSMarco Elver 		type_lock(&d->lock);								\
38f16a802dSMarco Elver 		op(d->counter);									\
39f16a802dSMarco Elver 		op(*d->pointer);								\
40f16a802dSMarco Elver 		type_unlock(&d->lock);								\
41f16a802dSMarco Elver 		type_lock##_irq(&d->lock);							\
42f16a802dSMarco Elver 		op(d->counter);									\
43f16a802dSMarco Elver 		op(*d->pointer);								\
44f16a802dSMarco Elver 		type_unlock##_irq(&d->lock);							\
45f16a802dSMarco Elver 		type_lock##_bh(&d->lock);							\
46f16a802dSMarco Elver 		op(d->counter);									\
47f16a802dSMarco Elver 		op(*d->pointer);								\
48f16a802dSMarco Elver 		type_unlock##_bh(&d->lock);							\
49f16a802dSMarco Elver 		type_lock##_irqsave(&d->lock, flags);						\
50f16a802dSMarco Elver 		op(d->counter);									\
51f16a802dSMarco Elver 		op(*d->pointer);								\
52f16a802dSMarco Elver 		type_unlock##_irqrestore(&d->lock, flags);					\
53f16a802dSMarco Elver 	}											\
54f16a802dSMarco Elver 	static void __used test_##class##_trylock(struct test_##class##_data *d)		\
55f16a802dSMarco Elver 	{											\
56f16a802dSMarco Elver 		if (type_trylock(&d->lock)) {							\
57f16a802dSMarco Elver 			op(d->counter);								\
58f16a802dSMarco Elver 			type_unlock(&d->lock);							\
59f16a802dSMarco Elver 		}										\
60f16a802dSMarco Elver 	}											\
61f16a802dSMarco Elver 	static void __used test_##class##_assert(struct test_##class##_data *d)			\
62f16a802dSMarco Elver 	{											\
63f16a802dSMarco Elver 		lockdep_assert_held(&d->lock);							\
64f16a802dSMarco Elver 		op(d->counter);									\
65f16a802dSMarco Elver 	}											\
66f16a802dSMarco Elver 	static void __used test_##class##_guard(struct test_##class##_data *d)			\
67f16a802dSMarco Elver 	{											\
68f16a802dSMarco Elver 		{ guard(class)(&d->lock);		op(d->counter); }			\
69f16a802dSMarco Elver 		{ guard(class##_irq)(&d->lock);		op(d->counter); }			\
70f16a802dSMarco Elver 		{ guard(class##_irqsave)(&d->lock);	op(d->counter); }			\
71f16a802dSMarco Elver 	}
72f16a802dSMarco Elver 
73f16a802dSMarco Elver #define TEST_OP_RW(x) (x)++
74f16a802dSMarco Elver #define TEST_OP_RO(x) ((void)(x))
75f16a802dSMarco Elver 
76f16a802dSMarco Elver TEST_SPINLOCK_COMMON(raw_spinlock,
77f16a802dSMarco Elver 		     raw_spinlock_t,
78f16a802dSMarco Elver 		     raw_spin_lock_init,
79f16a802dSMarco Elver 		     raw_spin_lock,
80f16a802dSMarco Elver 		     raw_spin_unlock,
81f16a802dSMarco Elver 		     raw_spin_trylock,
82f16a802dSMarco Elver 		     TEST_OP_RW);
83f16a802dSMarco Elver static void __used test_raw_spinlock_trylock_extra(struct test_raw_spinlock_data *d)
84f16a802dSMarco Elver {
85f16a802dSMarco Elver 	unsigned long flags;
86f16a802dSMarco Elver 
87f16a802dSMarco Elver 	if (raw_spin_trylock_irq(&d->lock)) {
88f16a802dSMarco Elver 		d->counter++;
89f16a802dSMarco Elver 		raw_spin_unlock_irq(&d->lock);
90f16a802dSMarco Elver 	}
91f16a802dSMarco Elver 	if (raw_spin_trylock_irqsave(&d->lock, flags)) {
92f16a802dSMarco Elver 		d->counter++;
93f16a802dSMarco Elver 		raw_spin_unlock_irqrestore(&d->lock, flags);
94f16a802dSMarco Elver 	}
95f16a802dSMarco Elver 	scoped_cond_guard(raw_spinlock_try, return, &d->lock) {
96f16a802dSMarco Elver 		d->counter++;
97f16a802dSMarco Elver 	}
98f16a802dSMarco Elver }
99f16a802dSMarco Elver 
100f16a802dSMarco Elver TEST_SPINLOCK_COMMON(spinlock,
101f16a802dSMarco Elver 		     spinlock_t,
102f16a802dSMarco Elver 		     spin_lock_init,
103f16a802dSMarco Elver 		     spin_lock,
104f16a802dSMarco Elver 		     spin_unlock,
105f16a802dSMarco Elver 		     spin_trylock,
106f16a802dSMarco Elver 		     TEST_OP_RW);
107f16a802dSMarco Elver static void __used test_spinlock_trylock_extra(struct test_spinlock_data *d)
108f16a802dSMarco Elver {
109f16a802dSMarco Elver 	unsigned long flags;
110f16a802dSMarco Elver 
111f16a802dSMarco Elver 	if (spin_trylock_irq(&d->lock)) {
112f16a802dSMarco Elver 		d->counter++;
113f16a802dSMarco Elver 		spin_unlock_irq(&d->lock);
114f16a802dSMarco Elver 	}
115f16a802dSMarco Elver 	if (spin_trylock_irqsave(&d->lock, flags)) {
116f16a802dSMarco Elver 		d->counter++;
117f16a802dSMarco Elver 		spin_unlock_irqrestore(&d->lock, flags);
118f16a802dSMarco Elver 	}
119f16a802dSMarco Elver 	scoped_cond_guard(spinlock_try, return, &d->lock) {
120f16a802dSMarco Elver 		d->counter++;
121f16a802dSMarco Elver 	}
122f16a802dSMarco Elver }
123f16a802dSMarco Elver 
124f16a802dSMarco Elver TEST_SPINLOCK_COMMON(write_lock,
125f16a802dSMarco Elver 		     rwlock_t,
126f16a802dSMarco Elver 		     rwlock_init,
127f16a802dSMarco Elver 		     write_lock,
128f16a802dSMarco Elver 		     write_unlock,
129f16a802dSMarco Elver 		     write_trylock,
130f16a802dSMarco Elver 		     TEST_OP_RW);
131f16a802dSMarco Elver static void __used test_write_trylock_extra(struct test_write_lock_data *d)
132f16a802dSMarco Elver {
133f16a802dSMarco Elver 	unsigned long flags;
134f16a802dSMarco Elver 
135f16a802dSMarco Elver 	if (write_trylock_irqsave(&d->lock, flags)) {
136f16a802dSMarco Elver 		d->counter++;
137f16a802dSMarco Elver 		write_unlock_irqrestore(&d->lock, flags);
138f16a802dSMarco Elver 	}
139f16a802dSMarco Elver }
140f16a802dSMarco Elver 
141f16a802dSMarco Elver TEST_SPINLOCK_COMMON(read_lock,
142f16a802dSMarco Elver 		     rwlock_t,
143f16a802dSMarco Elver 		     rwlock_init,
144f16a802dSMarco Elver 		     read_lock,
145f16a802dSMarco Elver 		     read_unlock,
146f16a802dSMarco Elver 		     read_trylock,
147f16a802dSMarco Elver 		     TEST_OP_RO);
148*370f0a34SMarco Elver 
149*370f0a34SMarco Elver struct test_mutex_data {
150*370f0a34SMarco Elver 	struct mutex mtx;
151*370f0a34SMarco Elver 	int counter __guarded_by(&mtx);
152*370f0a34SMarco Elver };
153*370f0a34SMarco Elver 
154*370f0a34SMarco Elver static void __used test_mutex_init(struct test_mutex_data *d)
155*370f0a34SMarco Elver {
156*370f0a34SMarco Elver 	mutex_init(&d->mtx);
157*370f0a34SMarco Elver 	d->counter = 0;
158*370f0a34SMarco Elver }
159*370f0a34SMarco Elver 
160*370f0a34SMarco Elver static void __used test_mutex_lock(struct test_mutex_data *d)
161*370f0a34SMarco Elver {
162*370f0a34SMarco Elver 	mutex_lock(&d->mtx);
163*370f0a34SMarco Elver 	d->counter++;
164*370f0a34SMarco Elver 	mutex_unlock(&d->mtx);
165*370f0a34SMarco Elver 	mutex_lock_io(&d->mtx);
166*370f0a34SMarco Elver 	d->counter++;
167*370f0a34SMarco Elver 	mutex_unlock(&d->mtx);
168*370f0a34SMarco Elver }
169*370f0a34SMarco Elver 
170*370f0a34SMarco Elver static void __used test_mutex_trylock(struct test_mutex_data *d, atomic_t *a)
171*370f0a34SMarco Elver {
172*370f0a34SMarco Elver 	if (!mutex_lock_interruptible(&d->mtx)) {
173*370f0a34SMarco Elver 		d->counter++;
174*370f0a34SMarco Elver 		mutex_unlock(&d->mtx);
175*370f0a34SMarco Elver 	}
176*370f0a34SMarco Elver 	if (!mutex_lock_killable(&d->mtx)) {
177*370f0a34SMarco Elver 		d->counter++;
178*370f0a34SMarco Elver 		mutex_unlock(&d->mtx);
179*370f0a34SMarco Elver 	}
180*370f0a34SMarco Elver 	if (mutex_trylock(&d->mtx)) {
181*370f0a34SMarco Elver 		d->counter++;
182*370f0a34SMarco Elver 		mutex_unlock(&d->mtx);
183*370f0a34SMarco Elver 	}
184*370f0a34SMarco Elver 	if (atomic_dec_and_mutex_lock(a, &d->mtx)) {
185*370f0a34SMarco Elver 		d->counter++;
186*370f0a34SMarco Elver 		mutex_unlock(&d->mtx);
187*370f0a34SMarco Elver 	}
188*370f0a34SMarco Elver }
189*370f0a34SMarco Elver 
190*370f0a34SMarco Elver static void __used test_mutex_assert(struct test_mutex_data *d)
191*370f0a34SMarco Elver {
192*370f0a34SMarco Elver 	lockdep_assert_held(&d->mtx);
193*370f0a34SMarco Elver 	d->counter++;
194*370f0a34SMarco Elver }
195*370f0a34SMarco Elver 
196*370f0a34SMarco Elver static void __used test_mutex_guard(struct test_mutex_data *d)
197*370f0a34SMarco Elver {
198*370f0a34SMarco Elver 	guard(mutex)(&d->mtx);
199*370f0a34SMarco Elver 	d->counter++;
200*370f0a34SMarco Elver }
201*370f0a34SMarco Elver 
202*370f0a34SMarco Elver static void __used test_mutex_cond_guard(struct test_mutex_data *d)
203*370f0a34SMarco Elver {
204*370f0a34SMarco Elver 	scoped_cond_guard(mutex_try, return, &d->mtx) {
205*370f0a34SMarco Elver 		d->counter++;
206*370f0a34SMarco Elver 	}
207*370f0a34SMarco Elver 	scoped_cond_guard(mutex_intr, return, &d->mtx) {
208*370f0a34SMarco Elver 		d->counter++;
209*370f0a34SMarco Elver 	}
210*370f0a34SMarco Elver }
211