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