1 /*
2 * Copyright (c) 2004, Bull S.A.. All rights reserved.
3 * Created by: Sebastien Decugis
4
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 *
17
18 * This file is a scalability test for the pthread_mutex_lock function.
19 * The goal is to test if there is a limit on the number
20 * of threads waiting on the same mutex.
21
22 * The steps are:
23 * -> Create 5 mutex with different attributes.
24 * -> lock the 5 mutex in the main thread
25 * -> Create the maximum amount of threads allowed on the system.
26 * -> each thread, for each mutex:
27 * - locks the mutex
28 * - increments a counter
29 * - unlocks the mutex
30 * - if the counter equals the amount of threads,
31 */
32
33 /********************************************************************************************/
34 /****************************** standard includes *****************************************/
35 /********************************************************************************************/
36 #include <pthread.h>
37 #include <errno.h>
38 #include <unistd.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <stdarg.h>
42
43 /********************************************************************************************/
44 /****************************** Test framework *****************************************/
45 /********************************************************************************************/
46 #include "testfrmw.h"
47 #include "testfrmw.c"
48 /* This header is responsible for defining the following macros:
49 * UNRESOLVED(ret, descr);
50 * where descr is a description of the error and ret is an int (error code for example)
51 * FAILED(descr);
52 * where descr is a short text saying why the test has failed.
53 * PASSED();
54 * No parameter.
55 *
56 * Both three macros shall terminate the calling process.
57 * The testcase shall not terminate in any other maneer.
58 *
59 * The other file defines the functions
60 * void output_init()
61 * void output(char * string, ...)
62 *
63 * Those may be used to output information.
64 */
65
66 /********************************************************************************************/
67 /********************************** Configuration ******************************************/
68 /********************************************************************************************/
69 #ifndef SCALABILITY_FACTOR
70 #define SCALABILITY_FACTOR 1 /* This is not used in this testcase */
71 #endif
72 #ifndef VERBOSE
73 #define VERBOSE 2
74 #endif
75
76 /********************************************************************************************/
77 /*********************************** Test case *****************************************/
78 /********************************************************************************************/
79
80 #ifndef WITHOUT_XOPEN
81 int types[] = {
82 PTHREAD_MUTEX_NORMAL,
83 PTHREAD_MUTEX_ERRORCHECK,
84 PTHREAD_MUTEX_RECURSIVE,
85 PTHREAD_MUTEX_DEFAULT
86 };
87 #endif
88
89 /* The mutex the threads will block on */
90 pthread_mutex_t mtx[5];
91
92 /* The condition used to signal the main thread to go to the next step */
93 pthread_cond_t cnd;
94 pthread_mutex_t m;
95
96 /* The shared data used to control the results of the test */
97 unsigned long nbthOK[5];
98 unsigned long nbthNOK[5];
99 unsigned long nbthTOT;
100
101 /*****
102 *
103 */
threaded(void * arg)104 void *threaded(void *arg)
105 {
106 int ret;
107 int i;
108 int bool;
109
110 for (i = 0; i < 5; i++) {
111 ret = pthread_mutex_lock(&mtx[i]);
112 if (ret == 0) { /* The thread was blocked successfuly */
113 /* We increment nbth[i] */
114 ret = pthread_mutex_lock(&m);
115 if (ret != 0) {
116 UNRESOLVED(ret, "Unable to lock 'm'");
117 }
118 nbthOK[i]++;
119 bool = ((nbthOK[i] + nbthNOK[i]) >= nbthTOT);
120 ret = pthread_mutex_unlock(&m);
121 if (ret != 0) {
122 UNRESOLVED(ret, "Unable to unlock 'm'");
123 }
124
125 /* We can unlock the test mutex */
126 ret = pthread_mutex_unlock(&mtx[i]);
127 if (ret != 0) {
128 FAILED("Unlocking a test mutex failed");
129 }
130 } else { /* Locking the test mutex failed */
131
132 /* We increment nbth[i] */
133 ret = pthread_mutex_lock(&m);
134 if (ret != 0) {
135 UNRESOLVED(ret, "Unable to lock 'm'");
136 }
137 nbthNOK[i]++;
138 bool = ((nbthOK[i] + nbthNOK[i]) >= nbthTOT);
139 ret = pthread_mutex_unlock(&m);
140 if (ret != 0) {
141 UNRESOLVED(ret, "Unable to unlock 'm'");
142 }
143 }
144
145 /* When every thread has passed the lock call, bool is true.
146 we signal the main thread to release the next mutex. */
147
148 if (bool) {
149 ret = pthread_cond_signal(&cnd);
150 if (ret != 0) {
151 UNRESOLVED(ret,
152 "Signaling the condition failed");
153 }
154 }
155 }
156
157 /* The test is terminated, the thread can die */
158 ret = pthread_detach(pthread_self());
159 if (ret != 0) {
160 UNRESOLVED(ret, "Thread detach failed");
161 }
162
163 return NULL;
164 }
165
main(int argc,char * argv[])166 int main(int argc, char *argv[])
167 {
168 pthread_t th;
169 pthread_attr_t tha;
170 pthread_mutexattr_t ma;
171 int ret;
172 int i;
173
174 output_init();
175
176 #if VERBOSE > 1
177 output("Test starting, initializing data\n");
178 #endif
179
180 /* Init the shared data */
181 for (i = 0; i < 4; i++) {
182 nbthOK[i] = 0;
183 nbthNOK[i] = 0;
184 }
185 nbthTOT = 0;
186
187 /* Init the cnd */
188 ret = pthread_mutex_init(&m, NULL);
189 if (ret != 0) {
190 UNRESOLVED(ret, "Unable to initialize 'm'");
191 }
192 ret = pthread_cond_init(&cnd, NULL);
193 if (ret != 0) {
194 UNRESOLVED(ret, "Unable to initialize 'cnd'");
195 }
196
197 /* Init the 5 mutexes */
198 ret = pthread_mutexattr_init(&ma);
199 if (ret != 0) {
200 UNRESOLVED(ret, "Unable to initialize 'ma'");
201 }
202
203 for (i = 0; i < 5; i++) {
204 #ifndef WITHOUT_XOPEN
205 if (i > 0) {
206 ret = pthread_mutexattr_settype(&ma, types[i - 1]);
207 if (ret != 0) {
208 UNRESOLVED(ret,
209 "Unable to set mutex attribute type");
210 }
211 }
212 #endif
213 ret = pthread_mutex_init(&mtx[i], &ma);
214 if (ret != 0) {
215 UNRESOLVED(ret, "A mutex init failed");
216 }
217 }
218
219 ret = pthread_mutexattr_destroy(&ma);
220 if (ret != 0) {
221 UNRESOLVED(ret, "Unable to destroy the mutex attribute object");
222 }
223
224 /* Lock the mutexes */
225 for (i = 0; i < 5; i++) {
226 ret = pthread_mutex_lock(&mtx[i]);
227 if (ret != 0) {
228 UNRESOLVED(ret,
229 "Unable to lock a mutex for the first time");
230 }
231 }
232
233 /* Init the threads attribute */
234 ret = pthread_attr_init(&tha);
235 if (ret != 0) {
236 UNRESOLVED(ret, "Thread attribute init failed");
237 }
238
239 ret = pthread_attr_setstacksize(&tha, sysconf(_SC_THREAD_STACK_MIN));
240 if (ret != 0) {
241 UNRESOLVED(ret, "Unable to set stack size to minimum value");
242 }
243
244 /* Create as many threads as possible */
245 #if VERBOSE > 1
246 output("Creating threads...\n");
247 #endif
248 do {
249 ret = pthread_create(&th, &tha, threaded, NULL);
250 if (ret == 0)
251 nbthTOT++;
252 } while (ret == 0);
253
254 #if VERBOSE > 1
255 output("Created %d threads.\n", nbthTOT);
256 #endif
257
258 /* lock m */
259 ret = pthread_mutex_lock(&m);
260 if (ret != 0) {
261 UNRESOLVED(ret, "Unable to lock 'm' in main thread");
262 }
263
264 /* For each mutex */
265 for (i = 0; i < 5; i++) {
266 /* Yield to let other threads enter the lock function */
267 sched_yield();
268
269 /* unlock the test mutex */
270 ret = pthread_mutex_unlock(&mtx[i]);
271 if (ret != 0) {
272 UNRESOLVED(ret,
273 "Unable to unlock a test mutex in main thread");
274 }
275
276 /* wait for cnd */
277 do {
278 ret = pthread_cond_wait(&cnd, &m);
279 }
280 while ((ret == 0) && ((nbthOK[i] + nbthNOK[i]) < nbthTOT));
281 if (ret != 0) {
282 UNRESOLVED(ret, "Unable to wait for 'cnd'");
283 }
284 }
285
286 /* unlock m */
287 ret = pthread_mutex_unlock(&m);
288 if (ret != 0) {
289 UNRESOLVED(ret, "Final 'm' unlock failed");
290 }
291
292 /* Destroy everything */
293 ret = pthread_attr_destroy(&tha);
294 if (ret != 0) {
295 UNRESOLVED(ret, "Final thread attribute destroy failed");
296 }
297
298 for (i = 0; i < 5; i++) {
299 ret = pthread_mutex_destroy(&mtx[i]);
300 if (ret != 0) {
301 UNRESOLVED(ret, "Unable to destroy a test mutex");
302 }
303 }
304
305 ret = pthread_cond_destroy(&cnd);
306 if (ret != 0) {
307 UNRESOLVED(ret, "Final cond destroy failed");
308 }
309
310 ret = pthread_mutex_destroy(&m);
311 if (ret != 0) {
312 UNRESOLVED(ret, "Final mutex destroy failed");
313 }
314
315 /* Output the results */
316 output("Sample results:\n");
317 output(" %lu threads were created\n", nbthTOT);
318 for (i = 0; i < 5; i++) {
319 output(" %lu threads have waited on mutex %i\n", nbthOK[i],
320 i + 1);
321 output(" (and %lu threads could not wait)\n", nbthNOK[i]);
322 ret += nbthNOK[i];
323 }
324
325 /* Exit */
326 if (ret == 0) {
327 PASSED;
328 } else {
329 FAILED("There may be an issue in scalability");
330 }
331 }
332