xref: /aosp_15_r20/external/ltp/lib/newlib_tests/test15.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
1*49cdfc7eSAndroid Build Coastguard Worker // SPDX-License-Identifier: GPL-2.0-or-later
2*49cdfc7eSAndroid Build Coastguard Worker /*
3*49cdfc7eSAndroid Build Coastguard Worker  * Copyright (c) 2017 Richard Palethorpe <[email protected]>
4*49cdfc7eSAndroid Build Coastguard Worker  */
5*49cdfc7eSAndroid Build Coastguard Worker 
6*49cdfc7eSAndroid Build Coastguard Worker /*
7*49cdfc7eSAndroid Build Coastguard Worker  * A basic regression test for tst_atomic_{load,store}. Also provides a
8*49cdfc7eSAndroid Build Coastguard Worker  * limited check that atomic stores and loads order non-atomic memory
9*49cdfc7eSAndroid Build Coastguard Worker  * accesses. That is, we are checking that they implement memory fences or
10*49cdfc7eSAndroid Build Coastguard Worker  * barriers.
11*49cdfc7eSAndroid Build Coastguard Worker  *
12*49cdfc7eSAndroid Build Coastguard Worker  * Many architectures/machines will still pass the test even if you remove the
13*49cdfc7eSAndroid Build Coastguard Worker  * atomic functions. X86 in particular has strong memory ordering by default
14*49cdfc7eSAndroid Build Coastguard Worker  * so that should always pass (if you use volatile). However Aarch64
15*49cdfc7eSAndroid Build Coastguard Worker  * (Raspberry Pi 3 Model B) has been observed to fail without the atomic
16*49cdfc7eSAndroid Build Coastguard Worker  * functions.
17*49cdfc7eSAndroid Build Coastguard Worker  *
18*49cdfc7eSAndroid Build Coastguard Worker  * A failure can occur if an update to seq_n is not made globally visible by
19*49cdfc7eSAndroid Build Coastguard Worker  * the time the next thread needs to use it.
20*49cdfc7eSAndroid Build Coastguard Worker  */
21*49cdfc7eSAndroid Build Coastguard Worker 
22*49cdfc7eSAndroid Build Coastguard Worker #include <stdint.h>
23*49cdfc7eSAndroid Build Coastguard Worker #include <pthread.h>
24*49cdfc7eSAndroid Build Coastguard Worker #include "tst_test.h"
25*49cdfc7eSAndroid Build Coastguard Worker #include "tst_atomic.h"
26*49cdfc7eSAndroid Build Coastguard Worker 
27*49cdfc7eSAndroid Build Coastguard Worker #define THREADS 64
28*49cdfc7eSAndroid Build Coastguard Worker #define FILLER (1 << 20)
29*49cdfc7eSAndroid Build Coastguard Worker 
30*49cdfc7eSAndroid Build Coastguard Worker /* Uncomment these to see what happens without atomics. To prevent the compiler
31*49cdfc7eSAndroid Build Coastguard Worker  * from removing/reording atomic and seq_n, mark them as volatile.
32*49cdfc7eSAndroid Build Coastguard Worker  */
33*49cdfc7eSAndroid Build Coastguard Worker /* #define tst_atomic_load(v) (*(v)) */
34*49cdfc7eSAndroid Build Coastguard Worker /* #define tst_atomic_store(i, v) *(v) = (i) */
35*49cdfc7eSAndroid Build Coastguard Worker 
36*49cdfc7eSAndroid Build Coastguard Worker struct block {
37*49cdfc7eSAndroid Build Coastguard Worker 	int seq_n;
38*49cdfc7eSAndroid Build Coastguard Worker 	intptr_t id;
39*49cdfc7eSAndroid Build Coastguard Worker 	intptr_t filler[FILLER];
40*49cdfc7eSAndroid Build Coastguard Worker };
41*49cdfc7eSAndroid Build Coastguard Worker 
42*49cdfc7eSAndroid Build Coastguard Worker static int atomic;
43*49cdfc7eSAndroid Build Coastguard Worker /* Instead of storing seq_n on the stack (probably next to the atomic variable
44*49cdfc7eSAndroid Build Coastguard Worker  * above), we store it in the middle of some anonymous mapped memory and keep
45*49cdfc7eSAndroid Build Coastguard Worker  * a pointer to it. This should decrease the probability that the value of
46*49cdfc7eSAndroid Build Coastguard Worker  * seq_n will be synchronised between processors as a byproduct of the atomic
47*49cdfc7eSAndroid Build Coastguard Worker  * variable being updated.
48*49cdfc7eSAndroid Build Coastguard Worker  */
49*49cdfc7eSAndroid Build Coastguard Worker static int *seq_n;
50*49cdfc7eSAndroid Build Coastguard Worker static struct block *m;
51*49cdfc7eSAndroid Build Coastguard Worker 
worker_load_store(void * aid)52*49cdfc7eSAndroid Build Coastguard Worker static void *worker_load_store(void *aid)
53*49cdfc7eSAndroid Build Coastguard Worker {
54*49cdfc7eSAndroid Build Coastguard Worker 	int id = (intptr_t)aid, i;
55*49cdfc7eSAndroid Build Coastguard Worker 
56*49cdfc7eSAndroid Build Coastguard Worker 	for (i = tst_atomic_load(&atomic);
57*49cdfc7eSAndroid Build Coastguard Worker 	     i != id;
58*49cdfc7eSAndroid Build Coastguard Worker 	     i = tst_atomic_load(&atomic))
59*49cdfc7eSAndroid Build Coastguard Worker 		;
60*49cdfc7eSAndroid Build Coastguard Worker 
61*49cdfc7eSAndroid Build Coastguard Worker 	(m + (*seq_n))->id = id;
62*49cdfc7eSAndroid Build Coastguard Worker 	*seq_n += 1;
63*49cdfc7eSAndroid Build Coastguard Worker 	tst_atomic_store(i + 1, &atomic);
64*49cdfc7eSAndroid Build Coastguard Worker 
65*49cdfc7eSAndroid Build Coastguard Worker 	return NULL;
66*49cdfc7eSAndroid Build Coastguard Worker }
67*49cdfc7eSAndroid Build Coastguard Worker 
68*49cdfc7eSAndroid Build Coastguard Worker /* Attempt to stress the memory transport so that memory operations are
69*49cdfc7eSAndroid Build Coastguard Worker  * contended and less predictable. This should increase the likelyhood of a
70*49cdfc7eSAndroid Build Coastguard Worker  * failure if a memory fence is missing.
71*49cdfc7eSAndroid Build Coastguard Worker  */
mem_spam(void * vp LTP_ATTRIBUTE_UNUSED)72*49cdfc7eSAndroid Build Coastguard Worker static void *mem_spam(void *vp LTP_ATTRIBUTE_UNUSED)
73*49cdfc7eSAndroid Build Coastguard Worker {
74*49cdfc7eSAndroid Build Coastguard Worker 	intptr_t i = 0, j;
75*49cdfc7eSAndroid Build Coastguard Worker 	struct block *cur = m;
76*49cdfc7eSAndroid Build Coastguard Worker 
77*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Memory spammer started");
78*49cdfc7eSAndroid Build Coastguard Worker 	while (tst_atomic_load(&atomic) > 0) {
79*49cdfc7eSAndroid Build Coastguard Worker 		for (j = 0; j < FILLER; j++)
80*49cdfc7eSAndroid Build Coastguard Worker 			cur->filler[j] = j;
81*49cdfc7eSAndroid Build Coastguard Worker 
82*49cdfc7eSAndroid Build Coastguard Worker 		if (i < THREADS - 1) {
83*49cdfc7eSAndroid Build Coastguard Worker 			cur = m + (++i);
84*49cdfc7eSAndroid Build Coastguard Worker 		} else {
85*49cdfc7eSAndroid Build Coastguard Worker 			i = 0;
86*49cdfc7eSAndroid Build Coastguard Worker 			cur = m;
87*49cdfc7eSAndroid Build Coastguard Worker 		}
88*49cdfc7eSAndroid Build Coastguard Worker 	}
89*49cdfc7eSAndroid Build Coastguard Worker 
90*49cdfc7eSAndroid Build Coastguard Worker 	return NULL;
91*49cdfc7eSAndroid Build Coastguard Worker }
92*49cdfc7eSAndroid Build Coastguard Worker 
do_test(void)93*49cdfc7eSAndroid Build Coastguard Worker static void do_test(void)
94*49cdfc7eSAndroid Build Coastguard Worker {
95*49cdfc7eSAndroid Build Coastguard Worker 	intptr_t i, id;
96*49cdfc7eSAndroid Build Coastguard Worker 	pthread_t threads[THREADS + 1];
97*49cdfc7eSAndroid Build Coastguard Worker 
98*49cdfc7eSAndroid Build Coastguard Worker 	atomic = 0;
99*49cdfc7eSAndroid Build Coastguard Worker 	m = SAFE_MMAP(NULL, sizeof(*m) * THREADS,
100*49cdfc7eSAndroid Build Coastguard Worker 		      PROT_READ | PROT_WRITE,
101*49cdfc7eSAndroid Build Coastguard Worker 		      MAP_PRIVATE | MAP_ANONYMOUS,
102*49cdfc7eSAndroid Build Coastguard Worker 		      -1, 0);
103*49cdfc7eSAndroid Build Coastguard Worker 	seq_n = &((m + THREADS / 2)->seq_n);
104*49cdfc7eSAndroid Build Coastguard Worker 
105*49cdfc7eSAndroid Build Coastguard Worker 	pthread_create(&threads[THREADS], NULL, mem_spam, NULL);
106*49cdfc7eSAndroid Build Coastguard Worker 	for (i = THREADS - 1; i >= 0; i--)
107*49cdfc7eSAndroid Build Coastguard Worker 		pthread_create(&threads[i], NULL, worker_load_store, (void *)i);
108*49cdfc7eSAndroid Build Coastguard Worker 
109*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < THREADS; i++) {
110*49cdfc7eSAndroid Build Coastguard Worker 		tst_res(TINFO, "Joining thread %li", i);
111*49cdfc7eSAndroid Build Coastguard Worker 		pthread_join(threads[i], NULL);
112*49cdfc7eSAndroid Build Coastguard Worker 	}
113*49cdfc7eSAndroid Build Coastguard Worker 	tst_atomic_store(-1, &atomic);
114*49cdfc7eSAndroid Build Coastguard Worker 	pthread_join(threads[THREADS], NULL);
115*49cdfc7eSAndroid Build Coastguard Worker 
116*49cdfc7eSAndroid Build Coastguard Worker 	tst_res(TINFO, "Expected\tFound");
117*49cdfc7eSAndroid Build Coastguard Worker 	for (i = 0; i < THREADS; i++) {
118*49cdfc7eSAndroid Build Coastguard Worker 		id = (m + i)->id;
119*49cdfc7eSAndroid Build Coastguard Worker 		if (id != i)
120*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TFAIL, "%d\t\t%d", (int)i, (int)id);
121*49cdfc7eSAndroid Build Coastguard Worker 		else
122*49cdfc7eSAndroid Build Coastguard Worker 			tst_res(TPASS, "%d\t\t%d", (int)i, (int)id);
123*49cdfc7eSAndroid Build Coastguard Worker 	}
124*49cdfc7eSAndroid Build Coastguard Worker 
125*49cdfc7eSAndroid Build Coastguard Worker 	SAFE_MUNMAP(m, sizeof(*m) * THREADS);
126*49cdfc7eSAndroid Build Coastguard Worker }
127*49cdfc7eSAndroid Build Coastguard Worker 
128*49cdfc7eSAndroid Build Coastguard Worker static struct tst_test test = {
129*49cdfc7eSAndroid Build Coastguard Worker 	.test_all = do_test,
130*49cdfc7eSAndroid Build Coastguard Worker };
131