1b411202f9ff33a587558e2e836626bc7eb9db183sewardj
2b411202f9ff33a587558e2e836626bc7eb9db183sewardj/* FIXME: this is basically a bad test as it is scheduling-
3b411202f9ff33a587558e2e836626bc7eb9db183sewardj   sensitive.  Sometimes the output is:
4b411202f9ff33a587558e2e836626bc7eb9db183sewardj
5b411202f9ff33a587558e2e836626bc7eb9db183sewardj   child: new value 6
6b411202f9ff33a587558e2e836626bc7eb9db183sewardj   child: new value 10
7b411202f9ff33a587558e2e836626bc7eb9db183sewardj   done, x = 10
8b411202f9ff33a587558e2e836626bc7eb9db183sewardj
9b411202f9ff33a587558e2e836626bc7eb9db183sewardj   and sometimes
10b411202f9ff33a587558e2e836626bc7eb9db183sewardj
11b411202f9ff33a587558e2e836626bc7eb9db183sewardj   child: new value 10
12b411202f9ff33a587558e2e836626bc7eb9db183sewardj   done, x = 10
13b411202f9ff33a587558e2e836626bc7eb9db183sewardj*/
14b411202f9ff33a587558e2e836626bc7eb9db183sewardj
15b411202f9ff33a587558e2e836626bc7eb9db183sewardj#include <pthread.h>
16b411202f9ff33a587558e2e836626bc7eb9db183sewardj#include <stdio.h>
17b411202f9ff33a587558e2e836626bc7eb9db183sewardj#include <stdlib.h>
18b411202f9ff33a587558e2e836626bc7eb9db183sewardj#include <unistd.h>
19b411202f9ff33a587558e2e836626bc7eb9db183sewardj
20b411202f9ff33a587558e2e836626bc7eb9db183sewardj/* Simple test program, no race.  Parent writes atomically to a counter
21b411202f9ff33a587558e2e836626bc7eb9db183sewardj   whilst child reads it.  When counter reaches a prearranged value,
22b411202f9ff33a587558e2e836626bc7eb9db183sewardj   child joins back to parent.  Parent (writer) uses hardware bus lock;
23b411202f9ff33a587558e2e836626bc7eb9db183sewardj   child is only reading and so does not need to use a bus lock. */
24b411202f9ff33a587558e2e836626bc7eb9db183sewardj
258777f7308785b4eb67898670e29ecdde42dec9dfsewardj#undef PLAT_x86_darwin
268777f7308785b4eb67898670e29ecdde42dec9dfsewardj#undef PLAT_amd64_darwin
27b411202f9ff33a587558e2e836626bc7eb9db183sewardj#undef PLAT_x86_linux
28b411202f9ff33a587558e2e836626bc7eb9db183sewardj#undef PLAT_amd64_linux
29b411202f9ff33a587558e2e836626bc7eb9db183sewardj#undef PLAT_ppc32_linux
30b411202f9ff33a587558e2e836626bc7eb9db183sewardj#undef PLAT_ppc64_linux
318777f7308785b4eb67898670e29ecdde42dec9dfsewardj#undef PLAT_arm_linux
3223ed6302e96eb905ef25d6c39db600e17e5f341fsewardj#undef PLAT_arm64_linux
33b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj#undef PLAT_s390x_linux
345db15403e889d4db339b342bc2a824ef0bfaa654sewardj#undef PLAT_mips32_linux
35d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj#undef PLAT_mips64_linux
36112711afefcfcd43680c7c4aa8d38ef180e8811esewardj#undef PLAT_tilegx_linux
378eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#undef PLAT_x86_solaris
388eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#undef PLAT_amd64_solaris
39b411202f9ff33a587558e2e836626bc7eb9db183sewardj
406e9de463ef677f093e9f24f126e1b11c28cf59fdsewardj#if defined(__APPLE__) && defined(__i386__)
418777f7308785b4eb67898670e29ecdde42dec9dfsewardj#  define PLAT_x86_darwin 1
428777f7308785b4eb67898670e29ecdde42dec9dfsewardj#elif defined(__APPLE__) && defined(__x86_64__)
438777f7308785b4eb67898670e29ecdde42dec9dfsewardj#  define PLAT_amd64_darwin 1
448777f7308785b4eb67898670e29ecdde42dec9dfsewardj#elif defined(__linux__) && defined(__i386__)
45b411202f9ff33a587558e2e836626bc7eb9db183sewardj#  define PLAT_x86_linux 1
468777f7308785b4eb67898670e29ecdde42dec9dfsewardj#elif defined(__linux__) && defined(__x86_64__)
47b411202f9ff33a587558e2e836626bc7eb9db183sewardj#  define PLAT_amd64_linux 1
488777f7308785b4eb67898670e29ecdde42dec9dfsewardj#elif defined(__linux__) && defined(__powerpc__) && !defined(__powerpc64__)
49b411202f9ff33a587558e2e836626bc7eb9db183sewardj#  define PLAT_ppc32_linux 1
508777f7308785b4eb67898670e29ecdde42dec9dfsewardj#elif defined(__linux__) && defined(__powerpc__) && defined(__powerpc64__)
51b411202f9ff33a587558e2e836626bc7eb9db183sewardj#  define PLAT_ppc64_linux 1
5223ed6302e96eb905ef25d6c39db600e17e5f341fsewardj#elif defined(__linux__) && defined(__arm__) && !defined(__aarch64__)
538777f7308785b4eb67898670e29ecdde42dec9dfsewardj#  define PLAT_arm_linux 1
5423ed6302e96eb905ef25d6c39db600e17e5f341fsewardj#elif defined(__linux__) && defined(__aarch64__) && !defined(__arm__)
5523ed6302e96eb905ef25d6c39db600e17e5f341fsewardj#  define PLAT_arm64_linux 1
56b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj#elif defined(__linux__) && defined(__s390x__)
57b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj#  define PLAT_s390x_linux 1
585db15403e889d4db339b342bc2a824ef0bfaa654sewardj#elif defined(__linux__) && defined(__mips__)
59d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj#if (__mips==64)
60d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj#  define PLAT_mips64_linux 1
61d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj#else
625db15403e889d4db339b342bc2a824ef0bfaa654sewardj#  define PLAT_mips32_linux 1
63b411202f9ff33a587558e2e836626bc7eb9db183sewardj#endif
64112711afefcfcd43680c7c4aa8d38ef180e8811esewardj#elif defined(__linux__) && defined(__tilegx__)
65112711afefcfcd43680c7c4aa8d38ef180e8811esewardj#  define PLAT_tilegx_linux 1
668eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#elif defined(__sun__) && defined(__i386__)
678eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  define PLAT_x86_solaris 1
688eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#elif defined(__sun__) && defined(__x86_64__)
698eb8bab992e3998c33770b0cdb16059a8b918a06sewardj#  define PLAT_amd64_solaris 1
70d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj#endif
71b411202f9ff33a587558e2e836626bc7eb9db183sewardj
728777f7308785b4eb67898670e29ecdde42dec9dfsewardj
73f5b5f84a476b54c239a5179de49728b6fa8f3b85sewardj#if defined(PLAT_amd64_linux) || defined(PLAT_x86_linux) \
748eb8bab992e3998c33770b0cdb16059a8b918a06sewardj    || defined(PLAT_amd64_darwin) || defined(PLAT_x86_darwin) \
758eb8bab992e3998c33770b0cdb16059a8b918a06sewardj    || defined(PLAT_amd64_solaris) || defined(PLAT_x86_solaris)
762ee33955b80812a8f31ec06a0430103b50aeca8csewardj#  define INC(_lval,_lqual)	     \
77b411202f9ff33a587558e2e836626bc7eb9db183sewardj      __asm__ __volatile__ ( \
78b411202f9ff33a587558e2e836626bc7eb9db183sewardj      "lock ; incl (%0)" : /*out*/ : /*in*/"r"(&(_lval)) : "memory", "cc" )
796e9de463ef677f093e9f24f126e1b11c28cf59fdsewardj#elif defined(PLAT_ppc32_linux) || defined(PLAT_ppc64_linux)
802ee33955b80812a8f31ec06a0430103b50aeca8csewardj#  define INC(_lval,_lqual)		  \
81b411202f9ff33a587558e2e836626bc7eb9db183sewardj   __asm__ __volatile__(                  \
82d12c4a53875f9280323784227b0af727c7991966sewardj      "1:\n"                              \
83b411202f9ff33a587558e2e836626bc7eb9db183sewardj      "        lwarx 15,0,%0\n"           \
84b411202f9ff33a587558e2e836626bc7eb9db183sewardj      "        addi 15,15,1\n"            \
85b411202f9ff33a587558e2e836626bc7eb9db183sewardj      "        stwcx. 15,0,%0\n"          \
86d12c4a53875f9280323784227b0af727c7991966sewardj      "        bne- 1b\n"                 \
87b411202f9ff33a587558e2e836626bc7eb9db183sewardj      : /*out*/ : /*in*/ "b"(&(_lval))    \
88b411202f9ff33a587558e2e836626bc7eb9db183sewardj      : /*trash*/ "r15", "cr0", "memory"  \
89b411202f9ff33a587558e2e836626bc7eb9db183sewardj   )
908777f7308785b4eb67898670e29ecdde42dec9dfsewardj#elif defined(PLAT_arm_linux)
918777f7308785b4eb67898670e29ecdde42dec9dfsewardj#  define INC(_lval,_lqual) \
928777f7308785b4eb67898670e29ecdde42dec9dfsewardj  __asm__ __volatile__( \
93d12c4a53875f9280323784227b0af727c7991966sewardj      "1:\n"                                 \
948777f7308785b4eb67898670e29ecdde42dec9dfsewardj      "        ldrex r8, [%0, #0]\n"         \
958777f7308785b4eb67898670e29ecdde42dec9dfsewardj      "        add   r8, r8, #1\n"           \
968777f7308785b4eb67898670e29ecdde42dec9dfsewardj      "        strex r9, r8, [%0, #0]\n"     \
978777f7308785b4eb67898670e29ecdde42dec9dfsewardj      "        cmp   r9, #0\n"               \
98d12c4a53875f9280323784227b0af727c7991966sewardj      "        bne   1b\n"                   \
998777f7308785b4eb67898670e29ecdde42dec9dfsewardj      : /*out*/ : /*in*/ "r"(&(_lval))       \
1008777f7308785b4eb67898670e29ecdde42dec9dfsewardj      : /*trash*/ "r8", "r9", "cc", "memory" \
1018777f7308785b4eb67898670e29ecdde42dec9dfsewardj  );
10223ed6302e96eb905ef25d6c39db600e17e5f341fsewardj#elif defined(PLAT_arm64_linux)
10323ed6302e96eb905ef25d6c39db600e17e5f341fsewardj#  define INC(_lval,_lqual) \
10423ed6302e96eb905ef25d6c39db600e17e5f341fsewardj  __asm__ __volatile__( \
10523ed6302e96eb905ef25d6c39db600e17e5f341fsewardj      "1:\n"                                 \
10623ed6302e96eb905ef25d6c39db600e17e5f341fsewardj      "        ldxr  w8, [%0, #0]\n"         \
10723ed6302e96eb905ef25d6c39db600e17e5f341fsewardj      "        add   w8, w8, #1\n"           \
10823ed6302e96eb905ef25d6c39db600e17e5f341fsewardj      "        stxr  w9, w8, [%0, #0]\n"     \
10923ed6302e96eb905ef25d6c39db600e17e5f341fsewardj      "        cmp   w9, #0\n"               \
11023ed6302e96eb905ef25d6c39db600e17e5f341fsewardj      "        bne   1b\n"                   \
11123ed6302e96eb905ef25d6c39db600e17e5f341fsewardj      : /*out*/ : /*in*/ "r"(&(_lval))       \
11223ed6302e96eb905ef25d6c39db600e17e5f341fsewardj      : /*trash*/ "x8", "x9", "cc", "memory" \
11323ed6302e96eb905ef25d6c39db600e17e5f341fsewardj  );
114b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj#elif defined(PLAT_s390x_linux)
115b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj#  define INC(_lval,_lqual) \
116b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj   __asm__ __volatile__( \
117b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj      "1: l     0,%0\n"                            \
118b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj      "   lr    1,0\n"                             \
119b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj      "   ahi   1,1\n"                             \
120b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj      "   cs    0,1,%0\n"                          \
121b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj      "   jl    1b\n"                              \
122b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj      : "+m" (_lval) :: "cc", "0","1" \
123b5b87408c0c99f9f6938d8cd921e2a5f420577c4sewardj   )
124d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj#elif defined(PLAT_mips32_linux) || defined(PLAT_mips64_linux)
1255db15403e889d4db339b342bc2a824ef0bfaa654sewardj#  define INC(_lval,_lqual)                         \
1265db15403e889d4db339b342bc2a824ef0bfaa654sewardj     __asm__ __volatile__ (                         \
1275db15403e889d4db339b342bc2a824ef0bfaa654sewardj      "L1xyzzy1" _lqual":\n"                        \
128d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj      "        move $t0, %0\n"                      \
129d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj      "        ll   $t1, 0($t0)\n"                  \
130d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj      "        addi $t1, $t1, 1\n"                  \
131d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj      "        sc   $t1, 0($t0)\n"                  \
132d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj      "        beqz $t1, L1xyzzy1" _lqual           \
1335db15403e889d4db339b342bc2a824ef0bfaa654sewardj      : /*out*/ : /*in*/ "r"(&(_lval))              \
134d5f0d1e2ae84afae0ef5c1db0fa1089280f0e3c9petarj      : /*trash*/ "t0", "t1", "memory"              \
1355db15403e889d4db339b342bc2a824ef0bfaa654sewardj        )
136112711afefcfcd43680c7c4aa8d38ef180e8811esewardj#elif defined(PLAT_tilegx_linux)
137112711afefcfcd43680c7c4aa8d38ef180e8811esewardj#  define INC(_lval,_lqual)                     \
138112711afefcfcd43680c7c4aa8d38ef180e8811esewardj  if (sizeof(_lval) == 4)                       \
139112711afefcfcd43680c7c4aa8d38ef180e8811esewardj    __insn_fetchadd(&(_lval), 1);               \
140112711afefcfcd43680c7c4aa8d38ef180e8811esewardj  else if(sizeof(_lval) == 8)                   \
141112711afefcfcd43680c7c4aa8d38ef180e8811esewardj    __insn_fetchadd(&(_lval), 1)
142b411202f9ff33a587558e2e836626bc7eb9db183sewardj#else
143b411202f9ff33a587558e2e836626bc7eb9db183sewardj#  error "Fix Me for this platform"
144b411202f9ff33a587558e2e836626bc7eb9db183sewardj#endif
145b411202f9ff33a587558e2e836626bc7eb9db183sewardj
146b411202f9ff33a587558e2e836626bc7eb9db183sewardj
147b411202f9ff33a587558e2e836626bc7eb9db183sewardj
148b411202f9ff33a587558e2e836626bc7eb9db183sewardj#define LIMIT 10
149b411202f9ff33a587558e2e836626bc7eb9db183sewardj
150b411202f9ff33a587558e2e836626bc7eb9db183sewardjvolatile int x = 0;
151b411202f9ff33a587558e2e836626bc7eb9db183sewardj
152b411202f9ff33a587558e2e836626bc7eb9db183sewardjvoid* child_fn ( void* arg )
153b411202f9ff33a587558e2e836626bc7eb9db183sewardj{
154b411202f9ff33a587558e2e836626bc7eb9db183sewardj   int q = 0;
155b411202f9ff33a587558e2e836626bc7eb9db183sewardj   int oldx = 0;
156f91fd73d264a38f0c742bd2eeb9895daa880aa5abart   struct timespec ts = { 0, 1000 * 1000 };
157f91fd73d264a38f0c742bd2eeb9895daa880aa5abart
158b411202f9ff33a587558e2e836626bc7eb9db183sewardj   while (1) {
159b411202f9ff33a587558e2e836626bc7eb9db183sewardj      q = (x >= LIMIT);
160b411202f9ff33a587558e2e836626bc7eb9db183sewardj      if (x != oldx) {
161b411202f9ff33a587558e2e836626bc7eb9db183sewardj         oldx = x;
162b411202f9ff33a587558e2e836626bc7eb9db183sewardj         printf("child: new value %d\n", oldx);
163b411202f9ff33a587558e2e836626bc7eb9db183sewardj         fflush(stdout);
164b411202f9ff33a587558e2e836626bc7eb9db183sewardj      }
165b411202f9ff33a587558e2e836626bc7eb9db183sewardj      if (q) break;
166f91fd73d264a38f0c742bd2eeb9895daa880aa5abart      nanosleep(&ts, 0);
167b411202f9ff33a587558e2e836626bc7eb9db183sewardj   }
168b411202f9ff33a587558e2e836626bc7eb9db183sewardj   return NULL;
169b411202f9ff33a587558e2e836626bc7eb9db183sewardj}
170b411202f9ff33a587558e2e836626bc7eb9db183sewardj
171b411202f9ff33a587558e2e836626bc7eb9db183sewardjint main ( void )
172b411202f9ff33a587558e2e836626bc7eb9db183sewardj{
173b411202f9ff33a587558e2e836626bc7eb9db183sewardj   pthread_t child;
174b411202f9ff33a587558e2e836626bc7eb9db183sewardj   int i;
175b411202f9ff33a587558e2e836626bc7eb9db183sewardj
176b411202f9ff33a587558e2e836626bc7eb9db183sewardj   if (pthread_create(&child, NULL, child_fn, NULL)) {
177b411202f9ff33a587558e2e836626bc7eb9db183sewardj      perror("pthread_create");
178b411202f9ff33a587558e2e836626bc7eb9db183sewardj      exit(1);
179b411202f9ff33a587558e2e836626bc7eb9db183sewardj   }
180b411202f9ff33a587558e2e836626bc7eb9db183sewardj
181b411202f9ff33a587558e2e836626bc7eb9db183sewardj   for (i = 0; i < LIMIT; i++) {
1822ee33955b80812a8f31ec06a0430103b50aeca8csewardj      INC(x, "main");
183b411202f9ff33a587558e2e836626bc7eb9db183sewardj      if (i == 5) sleep(1); /* make sure child doesn't starve */
184b411202f9ff33a587558e2e836626bc7eb9db183sewardj   }
185b411202f9ff33a587558e2e836626bc7eb9db183sewardj
186b411202f9ff33a587558e2e836626bc7eb9db183sewardj   if (pthread_join(child, NULL)) {
187b411202f9ff33a587558e2e836626bc7eb9db183sewardj      perror("pthread join");
188b411202f9ff33a587558e2e836626bc7eb9db183sewardj      exit(1);
189b411202f9ff33a587558e2e836626bc7eb9db183sewardj   }
190b411202f9ff33a587558e2e836626bc7eb9db183sewardj
191b411202f9ff33a587558e2e836626bc7eb9db183sewardj   printf("done, x = %d\n", x);
192b411202f9ff33a587558e2e836626bc7eb9db183sewardj
193b411202f9ff33a587558e2e836626bc7eb9db183sewardj   return 0;
194b411202f9ff33a587558e2e836626bc7eb9db183sewardj}
195