1 /** Trigger two kinds of errors: once that condition variable s_cond is
2 * associated with two different mutexes (s_mutex1 and s_mutex2), and two
3 * times that pthread_cond_signal() is called without that the mutex
4 * associated with the condition variable is locked.
5 */
6
7
8 #include <errno.h> // ETIMEDOUT
9 #include <pthread.h>
10 #include <semaphore.h>
11 #include <stdio.h>
12 #include <stdlib.h> // malloc()
13 #include <string.h> // memset()
14 #include <sys/time.h> // gettimeofday()
15 #include <time.h> // struct timespec
16 #include <fcntl.h> // O_CREAT
17 #include <unistd.h>
18 #include "../../config.h"
19
20
21 #define PTH_CALL(expr) \
22 do \
23 { \
24 int err = (expr); \
25 if (! s_quiet && err) \
26 { \
27 fprintf(stderr, \
28 "%s:%d %s returned error code %d (%s)\n", \
29 __FILE__, \
30 __LINE__, \
31 #expr, \
32 err, \
33 strerror(err)); \
34 } \
35 } while (0)
36
37
38 static pthread_cond_t s_cond;
39 static pthread_mutex_t s_mutex1;
40 static pthread_mutex_t s_mutex2;
41 static sem_t* s_sem;
42 static int s_quiet;
43
44
create_semaphore(const char * const name)45 static sem_t* create_semaphore(const char* const name)
46 {
47 #ifdef VGO_darwin
48 char name_and_pid[32];
49 snprintf(name_and_pid, sizeof(name_and_pid), "%s-%d", name, getpid());
50 sem_t* p = sem_open(name_and_pid, O_CREAT | O_EXCL, 0600, 0);
51 if (p == SEM_FAILED) {
52 perror("sem_open");
53 return NULL;
54 }
55 return p;
56 #else
57 sem_t* p = malloc(sizeof(*p));
58 if (p)
59 sem_init(p, 0, 0);
60 return p;
61 #endif
62 }
63
destroy_semaphore(const char * const name,sem_t * p)64 static void destroy_semaphore(const char* const name, sem_t* p)
65 {
66 #ifdef VGO_darwin
67 sem_close(p);
68 sem_unlink(name);
69 #else
70 sem_destroy(p);
71 free(p);
72 #endif
73 }
74
thread_func(void * mutex)75 static void* thread_func(void* mutex)
76 {
77 struct timeval now;
78 struct timespec deadline;
79
80 PTH_CALL(pthread_mutex_lock(mutex));
81 sem_post(s_sem);
82 gettimeofday(&now, 0);
83 memset(&deadline, 0, sizeof(deadline));
84 deadline.tv_sec = now.tv_sec + 2;
85 deadline.tv_nsec = now.tv_usec * 1000;
86 PTH_CALL(pthread_cond_timedwait(&s_cond, mutex, &deadline));
87 PTH_CALL(pthread_mutex_unlock(mutex));
88 return 0;
89 }
90
main(int argc,char ** argv)91 int main(int argc, char** argv)
92 {
93 char semaphore_name[32];
94 int optchar;
95 pthread_t tid1;
96 pthread_t tid2;
97
98 while ((optchar = getopt(argc, argv, "q")) != EOF)
99 {
100 switch (optchar)
101 {
102 case 'q': s_quiet = 1; break;
103 default:
104 fprintf(stderr, "Error: unknown option '%c'.\n", optchar);
105 return 1;
106 }
107 }
108
109 /* Initialize synchronization objects. */
110 snprintf(semaphore_name, sizeof(semaphore_name), "semaphore-%ld",
111 (long) getpid());
112 s_sem = create_semaphore(semaphore_name);
113 PTH_CALL(pthread_cond_init(&s_cond, 0));
114 PTH_CALL(pthread_mutex_init(&s_mutex1, 0));
115 PTH_CALL(pthread_mutex_init(&s_mutex2, 0));
116
117 /* Create two threads. */
118 PTH_CALL(pthread_create(&tid1, 0, &thread_func, &s_mutex1));
119 PTH_CALL(pthread_create(&tid2, 0, &thread_func, &s_mutex2));
120
121 /* Wait until both threads have called sem_post(). */
122 sem_wait(s_sem);
123 sem_wait(s_sem);
124 destroy_semaphore(semaphore_name, s_sem);
125 s_sem = 0;
126
127 /* Wait until both threads are waiting inside pthread_cond_wait(). */
128 PTH_CALL(pthread_mutex_lock(&s_mutex1));
129 PTH_CALL(pthread_mutex_lock(&s_mutex2));
130 PTH_CALL(pthread_mutex_unlock(&s_mutex2));
131 PTH_CALL(pthread_mutex_unlock(&s_mutex1));
132
133 /* Signal s_cond twice. */
134 PTH_CALL(pthread_cond_signal(&s_cond));
135 PTH_CALL(pthread_cond_signal(&s_cond));
136
137 /* Join both threads. */
138 PTH_CALL(pthread_join(tid1, 0));
139 PTH_CALL(pthread_join(tid2, 0));
140
141 return 0;
142 }
143