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 38static pthread_cond_t s_cond; 39static pthread_mutex_t s_mutex1; 40static pthread_mutex_t s_mutex2; 41static sem_t* s_sem; 42static int s_quiet; 43 44 45static 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 64static 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 75static 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 91int 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-%d", getpid()); 111 s_sem = create_semaphore(semaphore_name); 112 PTH_CALL(pthread_cond_init(&s_cond, 0)); 113 PTH_CALL(pthread_mutex_init(&s_mutex1, 0)); 114 PTH_CALL(pthread_mutex_init(&s_mutex2, 0)); 115 116 /* Create two threads. */ 117 PTH_CALL(pthread_create(&tid1, 0, &thread_func, &s_mutex1)); 118 PTH_CALL(pthread_create(&tid2, 0, &thread_func, &s_mutex2)); 119 120 /* Wait until both threads have called sem_post(). */ 121 sem_wait(s_sem); 122 sem_wait(s_sem); 123 destroy_semaphore(semaphore_name, s_sem); 124 s_sem = 0; 125 126 /* Wait until both threads are waiting inside pthread_cond_wait(). */ 127 PTH_CALL(pthread_mutex_lock(&s_mutex1)); 128 PTH_CALL(pthread_mutex_lock(&s_mutex2)); 129 PTH_CALL(pthread_mutex_unlock(&s_mutex2)); 130 PTH_CALL(pthread_mutex_unlock(&s_mutex1)); 131 132 /* Signal s_cond twice. */ 133 PTH_CALL(pthread_cond_signal(&s_cond)); 134 PTH_CALL(pthread_cond_signal(&s_cond)); 135 136 /* Join both threads. */ 137 PTH_CALL(pthread_join(tid1, 0)); 138 PTH_CALL(pthread_join(tid2, 0)); 139 140 return 0; 141} 142