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
csema_ctr(struct csema * p)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
csema_dtr(struct csema * p)33 void csema_dtr(struct csema* p)
34 {
35 pthread_cond_destroy(&p->m_cond);
36 pthread_mutex_destroy(&p->m_mutex);
37 }
38
csema_p(struct csema * p,const int n)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
csema_v(struct csema * p)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
cthread_ctr(struct cthread * p)65 void cthread_ctr(struct cthread* p)
66 {
67 p->m_thread = 0;
68 p->m_sema = 0;
69 }
70
cthread_dtr(struct cthread * p)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
thread_func(struct cthread * thread_info)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
main(int argc,char ** argv)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