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