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 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 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 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 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-%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