1/* Use a semaphore to implement mutual exclusion. */
2
3#include <assert.h>
4#include <fcntl.h>     /* O_CREAT */
5#include <pthread.h>
6#include <semaphore.h>
7#include <stdio.h>     /* printf() */
8#include <stdlib.h>    /* exit()  */
9#include <unistd.h>    /* sleep() */
10
11/* Local functions declarations. */
12
13static void* thread_func(void*);
14
15
16/* Local variables. */
17
18/* s_sem protects s_d3. */
19static sem_t* s_sem;
20
21static double s_d1; /* accessed before thread creation and in the created */
22                    /* thread (not a race). */
23static double s_d2; /* accessed in the created thread and after the join */
24                    /* (not a race). */
25static double s_d3; /* accessed simultaneously from both threads (race). */
26static int    s_debug     = 0;
27static int    s_do_printf = 0;
28static int    s_do_mutual_exclusion = 0;
29
30
31/* Function definitions. */
32
33int main(int argc, char** argv)
34{
35  int optchar;
36  pthread_t threadid;
37  char semaphore_name[32];
38
39  while ((optchar = getopt(argc, argv, "dmp")) != EOF)
40  {
41    switch (optchar)
42    {
43    case 'd':
44      s_debug = 1;
45      break;
46    case 'm':
47      s_do_mutual_exclusion = 1;
48      break;
49    case 'p':
50      s_do_printf = 1;
51      break;
52    default:
53      assert(0);
54    }
55  }
56
57  /*
58   * Use the ipcs and ipcrm commands to clean up named semaphores left by
59   * aborted instances of this process.
60   */
61  snprintf(semaphore_name, sizeof(semaphore_name), "/drd-sem-open-test-%d",
62	   getpid());
63  s_sem = sem_open(semaphore_name, O_CREAT | O_EXCL, 0600, 1);
64  if (s_sem == SEM_FAILED)
65  {
66    fprintf(stderr, "Failed to create a semaphore with name %s\n",
67            semaphore_name);
68    exit(1);
69  }
70
71  /*
72   * Switch to line-buffered mode, such that timing information can be
73   * obtained for each printf() call with strace.
74   */
75  setlinebuf(stdout);
76
77  if (s_debug)
78  {
79    printf("&s_d1 = %p; &s_d2 = %p; &s_d3 = %p\n", &s_d1, &s_d2, &s_d3);
80  }
81
82  s_d1 = 1;
83  s_d3 = 3;
84
85  pthread_create(&threadid, 0, thread_func, 0);
86
87  sleep(1); /* Wait until thread_func() finished. */
88
89  {
90    if (s_do_mutual_exclusion) sem_wait(s_sem);
91    s_d3++;
92    if (s_do_mutual_exclusion) sem_post(s_sem);
93  }
94
95  /* Wait until the thread finished. */
96  pthread_join(threadid, 0);
97  if (s_do_printf) printf("s_d2 = %g (should be 2)\n", s_d2);
98  if (s_do_printf) printf("s_d3 = %g (should be 5)\n", s_d3);
99
100  sem_close(s_sem);
101  sem_unlink(semaphore_name);
102
103  return 0;
104}
105
106static void* thread_func(void* thread_arg)
107{
108  if (s_do_printf)
109  {
110    printf("s_d1 = %g (should be 1)\n", s_d1);
111  }
112  s_d2 = 2;
113  {
114    if (s_do_mutual_exclusion) sem_wait(s_sem);
115    s_d3++;
116    if (s_do_mutual_exclusion) sem_post(s_sem);
117  }
118  return 0;
119}
120