1ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Test data race detection between floating point variables. */
2ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
3ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
4ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <assert.h>
5ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <stdio.h>     /* printf() */
6ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <pthread.h>
7ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown#include <unistd.h>    /* sleep() */
8ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
9ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
10ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Local functions declarations. */
11ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
12ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* thread_func(void*);
13ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
14ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
15ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Local variables. */
16ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
17ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* s_mutex protects s_d3. */
18ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic pthread_mutex_t s_mutex;
19ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
20ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic double s_d1; /* accessed before thread creation and in the created */
21ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    /* thread (not a race). */
22ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic double s_d2; /* accessed in the created thread and after the join */
23ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown                    /* (not a race). */
24ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic double s_d3; /* accessed simultaneously from both threads (race). */
25ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int    s_debug     = 0;
26ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int    s_do_printf = 0;
27ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic int    s_use_mutex = 0;
28ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
29ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
30ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown/* Function definitions. */
31ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
32ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownint main(int argc, char** argv)
33ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
34ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  int optchar;
35ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_t threadid;
36ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
37ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  while ((optchar = getopt(argc, argv, "dmp")) != EOF)
38ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
39ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    switch (optchar)
40ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    {
41ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case 'd':
42ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s_debug = 1;
43ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
44ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case 'm':
45ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s_use_mutex = 1;
46ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
47ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    case 'p':
48ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      s_do_printf = 1;
49ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      break;
50ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    default:
51ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown      assert(0);
52ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    }
53ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
54ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
55ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_mutex_init(&s_mutex, 0);
56ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
57ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /*
58ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * Switch to line-buffered mode, such that timing information can be
59ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   * obtained for each printf() call with strace.
60ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown   */
61ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  setlinebuf(stdout);
62ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
63ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (s_debug)
64ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
65ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    printf("&s_d1 = %p; &s_d2 = %p; &s_d3 = %p\n", &s_d1, &s_d2, &s_d3);
66ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
67ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
68ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_d1 = 1;
69ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_d3 = 3;
70ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
71ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_create(&threadid, 0, thread_func, 0);
72ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
73ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  sleep(1); /* Wait until thread_func() finished. */
74ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
75ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
76ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (s_use_mutex) pthread_mutex_lock(&s_mutex);
77ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    s_d3++;
78ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (s_use_mutex) pthread_mutex_unlock(&s_mutex);
79ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
80ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
81ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  /* Wait until the thread finished. */
82ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_join(threadid, 0);
83ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (s_do_printf) printf("s_d2 = %g (should be 2)\n", s_d2);
84ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (s_do_printf) printf("s_d3 = %g (should be 5)\n", s_d3);
85ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
86ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  pthread_mutex_destroy(&s_mutex);
87ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
88ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
89ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
90ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown
91ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brownstatic void* thread_func(void* thread_arg)
92ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown{
93ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  if (s_do_printf)
94ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
95ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    printf("s_d1 = %g (should be 1)\n", s_d1);
96ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
97ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  s_d2 = 2;
98ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  {
99ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (s_use_mutex) pthread_mutex_lock(&s_mutex);
100ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    s_d3++;
101ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown    if (s_use_mutex) pthread_mutex_unlock(&s_mutex);
102ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  }
103ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown  return 0;
104ed07e00d438c74b7a23c01bfffde77e3968305e4Jeff Brown}
105