/** Broadcast a (POSIX threads) signal to all running threads, where the * number of threads can be specified on the command line. This test program * is intended not only to test the correctness of drd but also to test * whether performance does not degrade too much when the number of threads * increases. */ #include <assert.h> #include <pthread.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> // Counting semaphore. struct csema { pthread_mutex_t m_mutex; pthread_cond_t m_cond; int m_count; }; void csema_ctr(struct csema* p) { memset(p, 0, sizeof(*p)); pthread_mutex_init(&p->m_mutex, 0); pthread_cond_init(&p->m_cond, 0); } void csema_dtr(struct csema* p) { pthread_cond_destroy(&p->m_cond); pthread_mutex_destroy(&p->m_mutex); } void csema_p(struct csema* p, const int n) { pthread_mutex_lock(&p->m_mutex); while (p->m_count < n) pthread_cond_wait(&p->m_cond, &p->m_mutex); p->m_count -= n; pthread_cond_signal(&p->m_cond); pthread_mutex_unlock(&p->m_mutex); } void csema_v(struct csema* p) { pthread_mutex_lock(&p->m_mutex); p->m_count++; pthread_cond_signal(&p->m_cond); pthread_mutex_unlock(&p->m_mutex); } struct cthread { pthread_t m_thread; int m_threadnum; struct csema* m_sema; }; void cthread_ctr(struct cthread* p) { p->m_thread = 0; p->m_sema = 0; } void cthread_dtr(struct cthread* p) { } // Local variables. static int s_debug = 0; static int s_trace = 0; static int s_signal_count; static pthread_mutex_t s_mutex; static pthread_cond_t s_cond; // Function definitions. static void thread_func(struct cthread* thread_info) { int i; pthread_mutex_lock(&s_mutex); for (i = 0; i < s_signal_count; i++) { if (s_trace) { printf("thread %d [%d] (1)\n", thread_info->m_threadnum, i); } csema_v(thread_info->m_sema); // Wait until the main thread signals us via pthread_cond_broadcast(). pthread_cond_wait(&s_cond, &s_mutex); if (s_trace) { printf("thread %d [%d] (2)\n", thread_info->m_threadnum, i); } } pthread_mutex_unlock(&s_mutex); } int main(int argc, char** argv) { int optchar; int thread_count; while ((optchar = getopt(argc, argv, "d")) != EOF) { switch (optchar) { case 'd': s_debug = 1; break; default: assert(0); break; } } /* This test should complete in 15s or less. If the test does not complete */ /* within that time, abort the test via the signal SIGALRM. */ alarm(100); s_signal_count = argc > optind ? atoi(argv[optind]) : 10; thread_count = argc > optind + 1 ? atoi(argv[optind + 1]) : 10; if (s_debug) printf("&s_cond = %p\n", &s_cond); pthread_mutex_init(&s_mutex, 0); pthread_cond_init(&s_cond, 0); { int i; struct csema sema; struct cthread* p; struct cthread* thread_vec; csema_ctr(&sema); thread_vec = malloc(sizeof(struct cthread) * thread_count); for (p = thread_vec; p != thread_vec + thread_count; p++) { cthread_ctr(p); p->m_threadnum = p - thread_vec; p->m_sema = &sema; pthread_create(&p->m_thread, 0, (void*(*)(void*))thread_func, &*p); } for (i = 0; i < s_signal_count; i++) { if (s_trace) printf("main [%d] (1)\n", i); csema_p(&sema, thread_count); if (s_trace) printf("main [%d] (2)\n", i); pthread_mutex_lock(&s_mutex); pthread_cond_broadcast(&s_cond); pthread_mutex_unlock(&s_mutex); if (s_trace) printf("main [%d] (3)\n", i); } for (i = 0; i < thread_count; i++) { pthread_join(thread_vec[i].m_thread, 0); cthread_dtr(&thread_vec[i]); } free(thread_vec); csema_dtr(&sema); } pthread_cond_destroy(&s_cond); pthread_mutex_destroy(&s_mutex); fprintf(stderr, "Done.\n"); return 0; }