File: pth_inconsistent_cond_wait.c

package info (click to toggle)
valgrind 1%3A3.12.0~svn20160714-1
  • links: PTS, VCS
  • area: main
  • in suites: stretch
  • size: 120,428 kB
  • ctags: 70,855
  • sloc: ansic: 674,645; exp: 26,134; xml: 21,574; asm: 7,570; cpp: 7,567; makefile: 7,380; sh: 6,188; perl: 5,855; haskell: 195
file content (142 lines) | stat: -rw-r--r-- 4,002 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/** Trigger two kinds of errors: once that condition variable s_cond is
 *  associated with two different mutexes (s_mutex1 and s_mutex2), and two
 *  times that pthread_cond_signal() is called without that the mutex
 *  associated with the condition variable is locked.
 */


#include <errno.h>     // ETIMEDOUT
#include <pthread.h>
#include <semaphore.h>
#include <stdio.h>
#include <stdlib.h>    // malloc()
#include <string.h>    // memset()
#include <sys/time.h>  // gettimeofday()
#include <time.h>      // struct timespec
#include <fcntl.h>     // O_CREAT
#include <unistd.h>
#include "../../config.h"


#define PTH_CALL(expr)                                  \
  do                                                    \
  {                                                     \
    int err = (expr);                                   \
    if (! s_quiet && err)				\
    {                                                   \
      fprintf(stderr,                                   \
              "%s:%d %s returned error code %d (%s)\n", \
              __FILE__,                                 \
              __LINE__,                                 \
              #expr,                                    \
              err,                                      \
              strerror(err));                           \
    }                                                   \
  } while (0)


static pthread_cond_t  s_cond;
static pthread_mutex_t s_mutex1;
static pthread_mutex_t s_mutex2;
static sem_t*          s_sem;
static int             s_quiet;


static sem_t* create_semaphore(const char* const name)
{
#ifdef VGO_darwin
  char name_and_pid[32];
  snprintf(name_and_pid, sizeof(name_and_pid), "%s-%d", name, getpid());
  sem_t* p = sem_open(name_and_pid, O_CREAT | O_EXCL, 0600, 0);
  if (p == SEM_FAILED) {
    perror("sem_open");
    return NULL;
  }
  return p;
#else
  sem_t* p = malloc(sizeof(*p));
  if (p)
    sem_init(p, 0, 0);
  return p;
#endif
}

static void destroy_semaphore(const char* const name, sem_t* p)
{
#ifdef VGO_darwin
  sem_close(p);
  sem_unlink(name);
#else
  sem_destroy(p);
  free(p);
#endif
}

static void* thread_func(void* mutex)
{
  struct timeval now;
  struct timespec deadline;

  PTH_CALL(pthread_mutex_lock(mutex));
  sem_post(s_sem);
  gettimeofday(&now, 0);
  memset(&deadline, 0, sizeof(deadline));
  deadline.tv_sec  = now.tv_sec + 2;
  deadline.tv_nsec = now.tv_usec * 1000;
  PTH_CALL(pthread_cond_timedwait(&s_cond, mutex, &deadline));
  PTH_CALL(pthread_mutex_unlock(mutex));
  return 0;
}

int main(int argc, char** argv)
{
  char semaphore_name[32];
  int optchar;
  pthread_t tid1;
  pthread_t tid2;

  while ((optchar = getopt(argc, argv, "q")) != EOF)
  {
    switch (optchar)
    {
    case 'q': s_quiet = 1; break;
    default:
      fprintf(stderr, "Error: unknown option '%c'.\n", optchar);
      return 1;
    }
  }

  /* Initialize synchronization objects. */
  snprintf(semaphore_name, sizeof(semaphore_name), "semaphore-%ld",
           (long) getpid());
  s_sem = create_semaphore(semaphore_name);
  PTH_CALL(pthread_cond_init(&s_cond, 0));
  PTH_CALL(pthread_mutex_init(&s_mutex1, 0));
  PTH_CALL(pthread_mutex_init(&s_mutex2, 0));

  /* Create two threads. */
  PTH_CALL(pthread_create(&tid1, 0, &thread_func, &s_mutex1));
  PTH_CALL(pthread_create(&tid2, 0, &thread_func, &s_mutex2));

  /* Wait until both threads have called sem_post(). */
  sem_wait(s_sem);
  sem_wait(s_sem);
  destroy_semaphore(semaphore_name, s_sem);
  s_sem = 0;

  /* Wait until both threads are waiting inside pthread_cond_wait(). */
  PTH_CALL(pthread_mutex_lock(&s_mutex1));
  PTH_CALL(pthread_mutex_lock(&s_mutex2));
  PTH_CALL(pthread_mutex_unlock(&s_mutex2));
  PTH_CALL(pthread_mutex_unlock(&s_mutex1));

  /* Signal s_cond twice. */
  PTH_CALL(pthread_cond_signal(&s_cond));
  PTH_CALL(pthread_cond_signal(&s_cond));

  /* Join both threads. */
  PTH_CALL(pthread_join(tid1, 0));
  PTH_CALL(pthread_join(tid2, 0));

  return 0;
}