1
2/* FIXME: this is basically a bad test as it is scheduling-
3   sensitive.  Sometimes the output is:
4
5   child: new value 6
6   child: new value 10
7   done, x = 10
8
9   and sometimes
10
11   child: new value 10
12   done, x = 10
13*/
14
15#include <pthread.h>
16#include <stdio.h>
17#include <stdlib.h>
18#include <unistd.h>
19
20/* Simple test program, no race.  Parent writes atomically to a counter
21   whilst child reads it.  When counter reaches a prearranged value,
22   child joins back to parent.  Parent (writer) uses hardware bus lock;
23   child is only reading and so does not need to use a bus lock. */
24
25#undef PLAT_x86_darwin
26#undef PLAT_amd64_darwin
27#undef PLAT_x86_linux
28#undef PLAT_amd64_linux
29#undef PLAT_ppc32_linux
30#undef PLAT_ppc64_linux
31#undef PLAT_arm_linux
32#undef PLAT_s390x_linux
33
34#if defined(__APPLE__) && defined(__i386__)
35#  define PLAT_x86_darwin 1
36#elif defined(__APPLE__) && defined(__x86_64__)
37#  define PLAT_amd64_darwin 1
38#elif defined(__linux__) && defined(__i386__)
39#  define PLAT_x86_linux 1
40#elif defined(__linux__) && defined(__x86_64__)
41#  define PLAT_amd64_linux 1
42#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
43#  define PLAT_ppc32_linux 1
44#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
45#  define PLAT_ppc64_linux 1
46#elif defined(__linux__) && defined(__arm__)
47#  define PLAT_arm_linux 1
48#elif defined(__linux__) && defined(__s390x__)
49#  define PLAT_s390x_linux 1
50#endif
51
52
53#if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \
54    || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin)
55#  define INC(_lval,_lqual)	     \
56      __asm__ __volatile__ ( \
57      "lock ; incl (%0)" : /*out*/ : /*in*/"r"(&(_lval)) : "memory", "cc" )
58#elif defined(PLAT_ppc32_linux) || defined(PLAT_ppc64_linux)
59#  define INC(_lval,_lqual)		  \
60   __asm__ __volatile__(                  \
61      "1:\n"                              \
62      "        lwarx 15,0,%0\n"           \
63      "        addi 15,15,1\n"            \
64      "        stwcx. 15,0,%0\n"          \
65      "        bne- 1b\n"                 \
66      : /*out*/ : /*in*/ "b"(&(_lval))    \
67      : /*trash*/ "r15", "cr0", "memory"  \
68   )
69#elif defined(PLAT_arm_linux)
70#  define INC(_lval,_lqual) \
71  __asm__ __volatile__( \
72      "1:\n"                                 \
73      "        ldrex r8, [%0, #0]\n"         \
74      "        add   r8, r8, #1\n"           \
75      "        strex r9, r8, [%0, #0]\n"     \
76      "        cmp   r9, #0\n"               \
77      "        bne   1b\n"                   \
78      : /*out*/ : /*in*/ "r"(&(_lval))       \
79      : /*trash*/ "r8", "r9", "cc", "memory" \
80  );
81#elif defined(PLAT_s390x_linux)
82#  define INC(_lval,_lqual) \
83   __asm__ __volatile__( \
84      "1: l     0,%0\n"                            \
85      "   lr    1,0\n"                             \
86      "   ahi   1,1\n"                             \
87      "   cs    0,1,%0\n"                          \
88      "   jl    1b\n"                              \
89      : "+m" (_lval) :: "cc", "0","1" \
90   )
91#else
92#  error "Fix Me for this platform"
93#endif
94
95
96
97#define LIMIT 10
98
99volatile int x = 0;
100
101void* child_fn ( void* arg )
102{
103   int q = 0;
104   int oldx = 0;
105   struct timespec ts = { 0, 1000 * 1000 };
106
107   while (1) {
108      q = (x >= LIMIT);
109      if (x != oldx) {
110         oldx = x;
111         printf("child: new value %d\n", oldx);
112         fflush(stdout);
113      }
114      if (q) break;
115      nanosleep(&ts, 0);
116   }
117   return NULL;
118}
119
120int main ( void )
121{
122   pthread_t child;
123   int i;
124
125   if (pthread_create(&child, NULL, child_fn, NULL)) {
126      perror("pthread_create");
127      exit(1);
128   }
129
130   for (i = 0; i < LIMIT; i++) {
131      INC(x, "main");
132      if (i == 5) sleep(1); /* make sure child doesn't starve */
133   }
134
135   if (pthread_join(child, NULL)) {
136      perror("pthread join");
137      exit(1);
138   }
139
140   printf("done, x = %d\n", x);
141
142   return 0;
143}
144