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 concurrent mutex having threads pending. 21 22 * The steps are: 23 * -> create some mutex attributes objects 24 * -> As long as nothing fails, do 25 * - create a thread. 26 * - this thread initializes a mutex with one of the mutex attributes 27 * - lock this mutex 28 * - create another thread which waits on the mutex (and hangs) then returns 29 * - wait for a condition 30 * - unlock the mutex. 31 * - join the thread 32 * -> When a create operation fails, broadcast the condition then join every threads. 33 * 34 * Additional note: 35 * This test will test only N/2 parallel mutex, where N is the max number of threads. 36 * It would be possible to create N parallel mutex with a slightly different algorithme: 37 * the main thread owns each mutex, then creates a thread which will block. 38 * This test could be written too. The current algorithm will give more stress to 39 * the mutex threads queues mechanism, as the threads are always different. 40 */ 41 42 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 43#define _POSIX_C_SOURCE 200112L 44 45 /* We enable the following line to have mutex attributes defined */ 46#ifndef WITHOUT_XOPEN 47#define _XOPEN_SOURCE 600 48#endif 49 50/********************************************************************************************/ 51/****************************** standard includes *****************************************/ 52/********************************************************************************************/ 53#include <pthread.h> 54#include <errno.h> 55#include <unistd.h> 56#include <stdio.h> 57#include <stdlib.h> 58#include <stdarg.h> 59 60/********************************************************************************************/ 61/****************************** Test framework *****************************************/ 62/********************************************************************************************/ 63#include "testfrmw.h" 64#include "testfrmw.c" 65 /* This header is responsible for defining the following macros: 66 * UNRESOLVED(ret, descr); 67 * where descr is a description of the error and ret is an int (error code for example) 68 * FAILED(descr); 69 * where descr is a short text saying why the test has failed. 70 * PASSED(); 71 * No parameter. 72 * 73 * Both three macros shall terminate the calling process. 74 * The testcase shall not terminate in any other maneer. 75 * 76 * The other file defines the functions 77 * void output_init() 78 * void output(char * string, ...) 79 * 80 * Those may be used to output information. 81 */ 82 83/********************************************************************************************/ 84/********************************** Configuration ******************************************/ 85/********************************************************************************************/ 86#ifndef SCALABILITY_FACTOR 87#define SCALABILITY_FACTOR 1 /* This is not used in this testcase */ 88#endif 89#ifndef VERBOSE 90#define VERBOSE 2 91#endif 92 93/********************************************************************************************/ 94/*********************************** Test case *****************************************/ 95/********************************************************************************************/ 96 97#ifndef WITHOUT_XOPEN 98int types[] = { 99 PTHREAD_MUTEX_NORMAL, 100 PTHREAD_MUTEX_ERRORCHECK, 101 PTHREAD_MUTEX_RECURSIVE, 102 PTHREAD_MUTEX_DEFAULT 103}; 104#endif 105 106/* The condition used to signal the main thread to go to the next step */ 107pthread_cond_t cnd; 108pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER; 109char do_it; 110unsigned long counter; 111 112/* Mutex attribute objects and pointers */ 113pthread_mutexattr_t *pma[6]; 114#ifdef WITHOUT_XOPEN 115pthread_mutexattr_t ma[1]; 116#else 117pthread_mutexattr_t ma[5]; 118#endif 119 120/* Test data type */ 121typedef struct _td { 122 pthread_t child; 123 int id; 124 pthread_mutex_t mtx; 125 int error; 126 struct _td *next; /* It is a chained list */ 127} testdata_t; 128 129/* Thread attribute object */ 130pthread_attr_t ta; 131 132/***** 133 * Level 2 - grandchild function 134 */ 135void *sub(void *arg) 136{ 137 testdata_t *td = (testdata_t *) arg; 138 td->error = pthread_mutex_lock(&(td->mtx)); 139 if (td->error != 0) { 140 /* Print out the error */ 141 output("PROBLEM: Unable to lock the mutex in thread %i\n", 142 td->id); 143 } else { 144 td->error = pthread_mutex_unlock(&(td->mtx)); 145 if (td->error != 0) { 146 UNRESOLVED(td->error, 147 "Mutex unlock failed. Mutex data was corrupted?"); 148 } 149 } 150 151 return NULL; 152} 153 154/***** 155 * Level 1 - child function 156 */ 157void *threaded(void *arg) 158{ 159 testdata_t *td = (testdata_t *) arg; 160 int ret; 161 int ret_create; 162 pthread_t ch; 163 164 ret = pthread_mutex_lock(&m); 165 if (ret != 0) { 166 UNRESOLVED(ret, "Unable to lock 'm' in child"); 167 } 168 /* Mark this thread as started */ 169 counter++; 170 171 /* Initialize the mutex with the mutex attribute */ 172 ret = pthread_mutex_init(&(td->mtx), pma[td->id % 6]); 173 if (ret != 0) { 174 UNRESOLVED(ret, "Unable to initialize a mutex"); 175 } 176 177 /* Lock the mutex */ 178 td->error = pthread_mutex_lock(&(td->mtx)); 179 if (td->error != 0) { 180 /* If the lock failed, we stop now */ 181 ret = pthread_mutex_unlock(&m); 182 if (ret != 0) { 183 UNRESOLVED(ret, "Unable to unlock 'm' in child"); 184 } 185 return NULL; 186 } 187 188 /* Create the child thread */ 189 ret_create = pthread_create(&ch, &ta, sub, arg); 190 191 /* Wait for the condition */ 192 while (do_it) { 193 ret = pthread_cond_wait(&cnd, &m); 194 if (ret != 0) { 195 UNRESOLVED(ret, "Unable to wait for condvar"); 196 } 197 } 198 ret = pthread_mutex_unlock(&m); 199 if (ret != 0) { 200 UNRESOLVED(ret, "Unable to unlock 'm' in child"); 201 } 202 203 /* Unlock the mutex and release the child */ 204 ret = pthread_mutex_unlock(&(td->mtx)); 205 if (ret != 0) { 206 UNRESOLVED(ret, 207 "Mutex unlock failed. Mutex data was corrupted?"); 208 } 209 210 /* If the child exists, join it now */ 211 if (ret_create == 0) { 212 ret = pthread_join(ch, NULL); 213 if (ret != 0) { 214 UNRESOLVED(ret, "Grandchild join failed"); 215 } 216 } 217 218 /* Destroy the test mutex */ 219 ret = pthread_mutex_destroy(&(td->mtx)); 220 if (ret != 0) { 221 UNRESOLVED(ret, "Test mutex destroy failed. Corrupted data?"); 222 } 223 224 /* We're done */ 225 return NULL; 226} 227 228/***** 229 * Level 0 - main function 230 */ 231int main(int argc, char *argv[]) 232{ 233 int ret; 234 int i; 235 int errors; 236 testdata_t sentinel; 237 testdata_t *cur, *tmp; 238 239 output_init(); 240 241#if VERBOSE > 1 242 output("Test starting, initializing data\n"); 243#endif 244 245 do_it = 1; 246 errors = 0; 247 counter = 0; 248 sentinel.next = NULL; 249 sentinel.id = 0; 250 cur = &sentinel; 251 252 /* Initialize the 6 pma objects */ 253 pma[0] = NULL; 254 pma[1] = &ma[0]; 255 ret = pthread_mutexattr_init(pma[1]); 256 if (ret != 0) { 257 UNRESOLVED(ret, "Mutex attribute init failed"); 258 } 259#ifdef WITHOUT_XOPEN 260 /* We only have default attributes objects */ 261 pma[2] = pma[0]; 262 pma[4] = pma[0]; 263 pma[3] = pma[1]; 264 pma[5] = pma[1]; 265#if VERBOSE > 1 266 output("Default mutex attribute object was initialized\n"); 267#endif 268#else 269 /* We can use the different mutex types */ 270 for (i = 0; i < 4; i++) { 271 pma[i + 2] = &ma[i + 1]; 272 ret = pthread_mutexattr_init(pma[i + 2]); 273 if (ret != 0) { 274 UNRESOLVED(ret, "Mutex attribute init failed"); 275 } 276 ret = pthread_mutexattr_settype(pma[i + 2], types[i]); 277 if (ret != 0) { 278 UNRESOLVED(ret, "Mutex attribute settype failed"); 279 } 280 } 281#if VERBOSE > 1 282 output("%d types of mutex attribute objects were initialized\n", 283 sizeof(types) / sizeof(types[0])); 284#endif 285#endif 286 287 /* Initialize the thread attribute object */ 288 ret = pthread_attr_init(&ta); 289 if (ret != 0) { 290 UNRESOLVED(ret, "Thread attribute init failed"); 291 } 292 ret = pthread_attr_setstacksize(&ta, sysconf(_SC_THREAD_STACK_MIN)); 293 if (ret != 0) { 294 UNRESOLVED(ret, "Unable to set stack size to minimum value"); 295 } 296 297 /* Lock m */ 298 ret = pthread_mutex_lock(&m); 299 if (ret != 0) { 300 UNRESOLVED(ret, "Unable to lock 'm' in main"); 301 } 302#if VERBOSE > 1 303 output("Ready to create the threads, processing...\n"); 304#endif 305 306 /* create the threads */ 307 while (1) { 308 tmp = malloc(sizeof(testdata_t)); 309 if (tmp == NULL) { 310 /* We cannot create anymore testdata */ 311 break; 312 } 313 314 /* We have a new test data structure */ 315 ret = pthread_create(&(tmp->child), &ta, threaded, tmp); 316 if (ret != 0) { 317 /* We cannot create more threads */ 318 free((void *)tmp); 319 break; 320 } 321 322 cur->next = tmp; 323 tmp->id = cur->id + 1; 324 tmp->error = 0; 325 cur = tmp; 326 327 /* The new thread was created, let's start it */ 328 do { 329 /* Unlock m so the thread can acquire it */ 330 ret = pthread_mutex_unlock(&m); 331 if (ret != 0) { 332 UNRESOLVED(ret, 333 "Unlock 'm' failed in main loop"); 334 } 335 /* Make sure the thread has a chance to run */ 336 sched_yield(); 337 /* Get m back */ 338 ret = pthread_mutex_lock(&m); 339 if (ret != 0) { 340 UNRESOLVED(ret, "Lock 'm' failed in main loop"); 341 } 342 /* If the counter has been incremented, this means this child is in the cond wait loop */ 343 } while (counter != cur->id); 344 } 345 346 /* Unable to create more threads, let's signal the cond and join the threads */ 347#if VERBOSE > 1 348 if (tmp == NULL) { 349 output("Cannot malloc more memory for the test data.\n"); 350 } else { 351 output("Cannot create another thread (error: %d).\n", ret); 352 } 353 output("The children will now be signaled.\n"); 354#endif 355 do_it = 0; 356 ret = pthread_cond_broadcast(&cnd); 357 if (ret != 0) { 358 UNRESOLVED(ret, "Cond broadcast failed"); 359 } 360 361 ret = pthread_mutex_unlock(&m); 362 if (ret != 0) { 363 UNRESOLVED(ret, "Unable to unlock m after broadcast"); 364 } 365#if VERBOSE > 1 366 output("The children are terminating. We will join them.\n"); 367#endif 368 369 /* All the threads are terminating, we can join the children and destroy the testdata */ 370 cur = &sentinel; 371 while (cur->next != NULL) { 372 /* Remove the first item from the list */ 373 tmp = cur->next; 374 cur->next = tmp->next; 375 376 /* Join the thread from the current item */ 377 ret = pthread_join(tmp->child, NULL); 378 if (ret != 0) { 379 UNRESOLVED(ret, "Unable to join a child"); 380 } 381 382 /* get the useful data */ 383 if (tmp->error != 0) 384 errors++; 385 386 /* Free the memory */ 387 free((void *)tmp); 388 } 389 390 /* We are done */ 391 392 /* Exit */ 393 if (errors == 0) { 394#if VERBOSE > 1 395 output("The test passed successfully.\n"); 396 output(" %i mutex were created and locked.\n", counter); 397 output(" No error was encountered\n"); 398#endif 399 PASSED; 400 } else { 401#if VERBOSE > 0 402 output("The test failed.\n"); 403 output(" %i mutex were created.\n", counter); 404 output(" %i lock operation failed.\n", errors); 405#endif 406 FAILED("There may be an issue in scalability"); 407 } 408} 409