| /** 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; |
| } |