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