Home | History | Annotate | Download | only in tests
      1 /** Broadcast a (POSIX threads) signal to all running threads, where the
      2  *  number of threads can be specified on the command line. This test program
      3  *  is intended not only to test the correctness of drd but also to test
      4  *  whether performance does not degrade too much when the number of threads
      5  *  increases.
      6  */
      7 
      8 
      9 #include <assert.h>
     10 #include <pthread.h>
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <unistd.h>
     15 
     16 
     17 // Counting semaphore.
     18 
     19 struct csema
     20 {
     21   pthread_mutex_t  m_mutex;
     22   pthread_cond_t   m_cond;
     23   int              m_count;
     24 };
     25 
     26 void csema_ctr(struct csema* p)
     27 {
     28   memset(p, 0, sizeof(*p));
     29   pthread_mutex_init(&p->m_mutex, 0);
     30   pthread_cond_init(&p->m_cond, 0);
     31 }
     32 
     33 void csema_dtr(struct csema* p)
     34 {
     35   pthread_cond_destroy(&p->m_cond);
     36   pthread_mutex_destroy(&p->m_mutex);
     37 }
     38 
     39 void csema_p(struct csema* p, const int n)
     40 {
     41   pthread_mutex_lock(&p->m_mutex);
     42   while (p->m_count < n)
     43     pthread_cond_wait(&p->m_cond, &p->m_mutex);
     44   p->m_count -= n;
     45   pthread_cond_signal(&p->m_cond);
     46   pthread_mutex_unlock(&p->m_mutex);
     47 }
     48 
     49 void csema_v(struct csema* p)
     50 {
     51   pthread_mutex_lock(&p->m_mutex);
     52   p->m_count++;
     53   pthread_cond_signal(&p->m_cond);
     54   pthread_mutex_unlock(&p->m_mutex);
     55 }
     56 
     57 
     58 struct cthread
     59 {
     60   pthread_t     m_thread;
     61   int           m_threadnum;
     62   struct csema* m_sema;
     63 };
     64 
     65 void cthread_ctr(struct cthread* p)
     66 {
     67   p->m_thread = 0;
     68   p->m_sema   = 0;
     69 }
     70 
     71 void cthread_dtr(struct cthread* p)
     72 { }
     73 
     74 
     75 // Local variables.
     76 
     77 static int s_debug = 0;
     78 static int s_trace = 0;
     79 static int s_signal_count;
     80 static pthread_mutex_t s_mutex;
     81 static pthread_cond_t  s_cond;
     82 
     83 
     84 // Function definitions.
     85 
     86 static void thread_func(struct cthread* thread_info)
     87 {
     88   int i;
     89 
     90   pthread_mutex_lock(&s_mutex);
     91 
     92   for (i = 0; i < s_signal_count; i++)
     93   {
     94     if (s_trace)
     95     {
     96       printf("thread %d [%d] (1)\n", thread_info->m_threadnum, i);
     97     }
     98     csema_v(thread_info->m_sema);
     99 
    100     // Wait until the main thread signals us via pthread_cond_broadcast().
    101     pthread_cond_wait(&s_cond, &s_mutex);
    102     if (s_trace)
    103     {
    104       printf("thread %d [%d] (2)\n", thread_info->m_threadnum, i);
    105     }
    106   }
    107 
    108   pthread_mutex_unlock(&s_mutex);
    109 }
    110 
    111 int main(int argc, char** argv)
    112 {
    113   int optchar;
    114   int thread_count;
    115 
    116   while ((optchar = getopt(argc, argv, "d")) != EOF)
    117   {
    118     switch (optchar)
    119     {
    120     case 'd':
    121       s_debug = 1;
    122       break;
    123     default:
    124       assert(0);
    125       break;
    126     }
    127   }
    128 
    129   /* This test should complete in 15s or less. If the test does not complete */
    130   /* within that time, abort the test via the signal SIGALRM.                */
    131   alarm(100);
    132 
    133   s_signal_count = argc > optind ? atoi(argv[optind]) : 10;
    134   thread_count = argc > optind + 1 ? atoi(argv[optind + 1]) : 10;
    135 
    136   if (s_debug)
    137     printf("&s_cond = %p\n", &s_cond);
    138 
    139   pthread_mutex_init(&s_mutex, 0);
    140   pthread_cond_init(&s_cond, 0);
    141   {
    142     int i;
    143     struct csema sema;
    144     struct cthread* p;
    145     struct cthread* thread_vec;
    146 
    147     csema_ctr(&sema);
    148     thread_vec = malloc(sizeof(struct cthread) * thread_count);
    149     for (p = thread_vec; p != thread_vec + thread_count; p++)
    150     {
    151       cthread_ctr(p);
    152       p->m_threadnum = p - thread_vec;
    153       p->m_sema = &sema;
    154       pthread_create(&p->m_thread, 0,
    155                      (void*(*)(void*))thread_func, &*p);
    156     }
    157     for (i = 0; i < s_signal_count; i++)
    158     {
    159       if (s_trace)
    160         printf("main [%d] (1)\n", i);
    161       csema_p(&sema, thread_count);
    162       if (s_trace)
    163         printf("main [%d] (2)\n", i);
    164       pthread_mutex_lock(&s_mutex);
    165       pthread_cond_broadcast(&s_cond);
    166       pthread_mutex_unlock(&s_mutex);
    167       if (s_trace)
    168         printf("main [%d] (3)\n", i);
    169     }
    170     for (i = 0; i < thread_count; i++)
    171     {
    172       pthread_join(thread_vec[i].m_thread, 0);
    173       cthread_dtr(&thread_vec[i]);
    174     }
    175     free(thread_vec);
    176     csema_dtr(&sema);
    177   }
    178   pthread_cond_destroy(&s_cond);
    179   pthread_mutex_destroy(&s_mutex);
    180 
    181   fprintf(stderr, "Done.\n");
    182 
    183   return 0;
    184 }
    185