1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/**
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * This test program triggers a single race condition on variable s_y.
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Although another variable (s_x) is also modified by both threads, no race
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * condition must be reported on this variable since it is only accessed via
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * atomic instructions.
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown *
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * Note: for the i386 and x86_64 memory models, thread 2 must print y = 1.
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * On PPC however, both y = 0 and y = 1 are legal results. This is because
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * the PPC memory model allows different CPU's to observe stores to variables
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown * in different cache lines in a different order.
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown */
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#define _GNU_SOURCE
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h>
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>   /* fprintf() */
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdlib.h>  /* atoi() */
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include "../../config.h"
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Atomic builtins are only supported by gcc 4.1.0 and later. */
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#ifndef HAVE_BUILTIN_ATOMIC
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#error Sorry, but this test program can only be compiled by a compiler that\
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownhas built-in functions for atomic memory access.
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#endif
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic __inline__
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint sync_add_and_fetch(int* p, int i)
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return __sync_add_and_fetch(p, i);
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int s_x = 0;
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* g_dummy[] ensures that s_x and s_y are not in the same cache line. */
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownchar g_dummy[512];
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int s_y = 0;
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* thread_func_1(void* arg)
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_y = 1;
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  (void) sync_add_and_fetch(&s_x, 1);
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* thread_func_2(void* arg)
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  while (sync_add_and_fetch(&s_x, 0) == 0)
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    ;
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  fprintf(stderr, "y = %d\n", s_y);
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(int argc, char** argv)
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int i;
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  const int n_threads = 2;
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_t tid[n_threads];
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  fprintf(stderr, "Start of test.\n");
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_create(&tid[0], 0, thread_func_1, 0);
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_create(&tid[1], 0, thread_func_2, 0);
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  for (i = 0; i < n_threads; i++)
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    pthread_join(tid[i], 0);
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  fprintf(stderr, "Test finished.\n");
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
67