148529bc234eb7497175c99bb727e9bd3c6a229d4bart/**
248529bc234eb7497175c99bb727e9bd3c6a229d4bart * This test program triggers a single race condition on variable s_y.
348529bc234eb7497175c99bb727e9bd3c6a229d4bart * Although another variable (s_x) is also modified by both threads, no race
448529bc234eb7497175c99bb727e9bd3c6a229d4bart * condition must be reported on this variable since it is only accessed via
548529bc234eb7497175c99bb727e9bd3c6a229d4bart * atomic instructions.
648529bc234eb7497175c99bb727e9bd3c6a229d4bart *
748529bc234eb7497175c99bb727e9bd3c6a229d4bart * Note: for the i386 and x86_64 memory models, thread 2 must print y = 1.
848529bc234eb7497175c99bb727e9bd3c6a229d4bart * On PPC however, both y = 0 and y = 1 are legal results. This is because
948529bc234eb7497175c99bb727e9bd3c6a229d4bart * the PPC memory model allows different CPU's to observe stores to variables
1048529bc234eb7497175c99bb727e9bd3c6a229d4bart * in different cache lines in a different order.
11cca440bcba031f0f37b39ad82e840ba693dd6b9dbart */
12cca440bcba031f0f37b39ad82e840ba693dd6b9dbart
13cca440bcba031f0f37b39ad82e840ba693dd6b9dbart#define _GNU_SOURCE
14cca440bcba031f0f37b39ad82e840ba693dd6b9dbart
15cca440bcba031f0f37b39ad82e840ba693dd6b9dbart#include <pthread.h>
16cca440bcba031f0f37b39ad82e840ba693dd6b9dbart#include <stdio.h>   /* fprintf() */
17cca440bcba031f0f37b39ad82e840ba693dd6b9dbart#include <stdlib.h>  /* atoi() */
18d22e8b216f2dcde66d77dcecfc3a6b03a40db2a7bart#include "../../config.h"
19cca440bcba031f0f37b39ad82e840ba693dd6b9dbart
2048529bc234eb7497175c99bb727e9bd3c6a229d4bart/* Atomic builtins are only supported by gcc 4.1.0 and later. */
21d45d99553c15a361bb797d21ec6afb9bad22d2d4bart#ifndef HAVE_BUILTIN_ATOMIC
22d45d99553c15a361bb797d21ec6afb9bad22d2d4bart#error Sorry, but this test program can only be compiled by a compiler that\
23d45d99553c15a361bb797d21ec6afb9bad22d2d4barthas built-in functions for atomic memory access.
24d45d99553c15a361bb797d21ec6afb9bad22d2d4bart#endif
2548529bc234eb7497175c99bb727e9bd3c6a229d4bart
26cca440bcba031f0f37b39ad82e840ba693dd6b9dbartstatic __inline__
27143eec7c7f7e00e7d60def53097eb18559a1a2fbbartint sync_add_and_fetch(int* p, int i)
28143eec7c7f7e00e7d60def53097eb18559a1a2fbbart{
29143eec7c7f7e00e7d60def53097eb18559a1a2fbbart  return __sync_add_and_fetch(p, i);
30143eec7c7f7e00e7d60def53097eb18559a1a2fbbart}
31cca440bcba031f0f37b39ad82e840ba693dd6b9dbart
32cca440bcba031f0f37b39ad82e840ba693dd6b9dbartstatic int s_x = 0;
3348529bc234eb7497175c99bb727e9bd3c6a229d4bart/* g_dummy[] ensures that s_x and s_y are not in the same cache line. */
3448529bc234eb7497175c99bb727e9bd3c6a229d4bartchar g_dummy[512];
35cca440bcba031f0f37b39ad82e840ba693dd6b9dbartstatic int s_y = 0;
36cca440bcba031f0f37b39ad82e840ba693dd6b9dbart
37cca440bcba031f0f37b39ad82e840ba693dd6b9dbartstatic void* thread_func_1(void* arg)
38cca440bcba031f0f37b39ad82e840ba693dd6b9dbart{
39cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  s_y = 1;
40143eec7c7f7e00e7d60def53097eb18559a1a2fbbart  (void) sync_add_and_fetch(&s_x, 1);
41cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  return 0;
42cca440bcba031f0f37b39ad82e840ba693dd6b9dbart}
43cca440bcba031f0f37b39ad82e840ba693dd6b9dbart
44cca440bcba031f0f37b39ad82e840ba693dd6b9dbartstatic void* thread_func_2(void* arg)
45cca440bcba031f0f37b39ad82e840ba693dd6b9dbart{
46143eec7c7f7e00e7d60def53097eb18559a1a2fbbart  while (sync_add_and_fetch(&s_x, 0) == 0)
47cca440bcba031f0f37b39ad82e840ba693dd6b9dbart    ;
48cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  fprintf(stderr, "y = %d\n", s_y);
49cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  return 0;
50cca440bcba031f0f37b39ad82e840ba693dd6b9dbart}
51cca440bcba031f0f37b39ad82e840ba693dd6b9dbart
52cca440bcba031f0f37b39ad82e840ba693dd6b9dbartint main(int argc, char** argv)
53cca440bcba031f0f37b39ad82e840ba693dd6b9dbart{
54cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  int i;
55cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  const int n_threads = 2;
56cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  pthread_t tid[n_threads];
57cca440bcba031f0f37b39ad82e840ba693dd6b9dbart
58cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  fprintf(stderr, "Start of test.\n");
59cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  pthread_create(&tid[0], 0, thread_func_1, 0);
60cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  pthread_create(&tid[1], 0, thread_func_2, 0);
61cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  for (i = 0; i < n_threads; i++)
62cca440bcba031f0f37b39ad82e840ba693dd6b9dbart    pthread_join(tid[i], 0);
63cca440bcba031f0f37b39ad82e840ba693dd6b9dbart  fprintf(stderr, "Test finished.\n");
640d84eabef5806ae924bfb05aaf70445135f6e2d5bart
6548529bc234eb7497175c99bb727e9bd3c6a229d4bart  return 0;
6648529bc234eb7497175c99bb727e9bd3c6a229d4bart}
67