Home | History | Annotate | Download | only in tests
      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-%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