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 __APPLE__ 48 sem_t* p = sem_open(name, O_CREAT, 0600, 0); 49 return p; 50 #else 51 sem_t* p = malloc(sizeof(*p)); 52 if (p) 53 sem_init(p, 0, 0); 54 return p; 55 #endif 56 } 57 58 static void destroy_semaphore(const char* const name, sem_t* p) 59 { 60 #ifdef __APPLE__ 61 sem_close(p); 62 sem_unlink(name); 63 #else 64 sem_destroy(p); 65 free(p); 66 #endif 67 } 68 69 static void* thread_func(void* mutex) 70 { 71 struct timeval now; 72 struct timespec deadline; 73 74 PTH_CALL(pthread_mutex_lock(mutex)); 75 sem_post(s_sem); 76 gettimeofday(&now, 0); 77 memset(&deadline, 0, sizeof(deadline)); 78 deadline.tv_sec = now.tv_sec + 2; 79 deadline.tv_nsec = now.tv_usec * 1000; 80 PTH_CALL(pthread_cond_timedwait(&s_cond, mutex, &deadline)); 81 PTH_CALL(pthread_mutex_unlock(mutex)); 82 return 0; 83 } 84 85 int main(int argc, char** argv) 86 { 87 char semaphore_name[32]; 88 int optchar; 89 pthread_t tid1; 90 pthread_t tid2; 91 92 while ((optchar = getopt(argc, argv, "q")) != EOF) 93 { 94 switch (optchar) 95 { 96 case 'q': s_quiet = 1; break; 97 default: 98 fprintf(stderr, "Error: unknown option '%c'.\n", optchar); 99 return 1; 100 } 101 } 102 103 /* Initialize synchronization objects. */ 104 snprintf(semaphore_name, sizeof(semaphore_name), "semaphore-%d", getpid()); 105 s_sem = create_semaphore(semaphore_name); 106 PTH_CALL(pthread_cond_init(&s_cond, 0)); 107 PTH_CALL(pthread_mutex_init(&s_mutex1, 0)); 108 PTH_CALL(pthread_mutex_init(&s_mutex2, 0)); 109 110 /* Create two threads. */ 111 PTH_CALL(pthread_create(&tid1, 0, &thread_func, &s_mutex1)); 112 PTH_CALL(pthread_create(&tid2, 0, &thread_func, &s_mutex2)); 113 114 /* Wait until both threads have called sem_post(). */ 115 sem_wait(s_sem); 116 sem_wait(s_sem); 117 destroy_semaphore(semaphore_name, s_sem); 118 s_sem = 0; 119 120 /* Wait until both threads are waiting inside pthread_cond_wait(). */ 121 PTH_CALL(pthread_mutex_lock(&s_mutex1)); 122 PTH_CALL(pthread_mutex_lock(&s_mutex2)); 123 PTH_CALL(pthread_mutex_unlock(&s_mutex2)); 124 PTH_CALL(pthread_mutex_unlock(&s_mutex1)); 125 126 /* Signal s_cond twice. */ 127 PTH_CALL(pthread_cond_signal(&s_cond)); 128 PTH_CALL(pthread_cond_signal(&s_cond)); 129 130 /* Join both threads. */ 131 PTH_CALL(pthread_join(tid1, 0)); 132 PTH_CALL(pthread_join(tid2, 0)); 133 134 return 0; 135 } 136