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 * This sample test aims to check the following assertion: 18 * 19 * The pthread_mutex_trylock() function locks the mutex object 20 * when it is unlocked. 21 22 * The steps are: 23 * 24 * -> For each kind of mutex, 25 * -> trylock the mutex. It shall suceed. 26 * -> trylock the mutex again. It shall fail (except in case of recursive mutex). 27 * -> create a new child (either thread or process) 28 * -> the new child trylock the mutex. It shall fail. 29 * -> undo everything. 30 */ 31 32 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 33 #define _POSIX_C_SOURCE 200112L 34 35 /* We need the XSI extention for the mutex attributes 36 and the mkstemp() routine */ 37 #ifndef WITHOUT_XOPEN 38 #define _XOPEN_SOURCE 600 39 #endif 40 /********************************************************************************************/ 41 /****************************** standard includes *****************************************/ 42 /********************************************************************************************/ 43 #include <pthread.h> 44 #include <stdarg.h> 45 #include <stdio.h> 46 #include <stdlib.h> 47 #include <unistd.h> 48 49 #include <errno.h> 50 #include <sys/wait.h> 51 #include <sys/mman.h> 52 #include <string.h> 53 54 /********************************************************************************************/ 55 /****************************** Test framework *****************************************/ 56 /********************************************************************************************/ 57 #include "../testfrmw/testfrmw.h" 58 #include "../testfrmw/testfrmw.c" 59 /* This header is responsible for defining the following macros: 60 * UNRESOLVED(ret, descr); 61 * where descr is a description of the error and ret is an int (error code for example) 62 * FAILED(descr); 63 * where descr is a short text saying why the test has failed. 64 * PASSED(); 65 * No parameter. 66 * 67 * Both three macros shall terminate the calling process. 68 * The testcase shall not terminate in any other maneer. 69 * 70 * The other file defines the functions 71 * void output_init() 72 * void output(char * string, ...) 73 * 74 * Those may be used to output information. 75 */ 76 77 /********************************************************************************************/ 78 /********************************** Configuration ******************************************/ 79 /********************************************************************************************/ 80 #ifndef VERBOSE 81 #define VERBOSE 1 82 #endif 83 84 /********************************************************************************************/ 85 /*********************************** Test case *****************************************/ 86 /********************************************************************************************/ 87 typedef struct { 88 pthread_mutex_t mtx; 89 int status; /* error code */ 90 } testdata_t; 91 92 struct _scenar { 93 int m_type; /* Mutex type to use */ 94 int m_pshared; /* 0: mutex is process-private (default) ~ !0: mutex is process-shared, if supported */ 95 int fork; /* 0: Test between threads. ~ !0: Test across processes, if supported (mmap) */ 96 char *descr; /* Case description */ 97 } scenarii[] = { 98 { 99 PTHREAD_MUTEX_DEFAULT, 0, 0, "Default mutex"} 100 #ifndef WITHOUT_XOPEN 101 , { 102 PTHREAD_MUTEX_NORMAL, 0, 0, "Normal mutex"} 103 , { 104 PTHREAD_MUTEX_ERRORCHECK, 0, 0, "Errorcheck mutex"} 105 , { 106 PTHREAD_MUTEX_RECURSIVE, 0, 0, "Recursive mutex"} 107 #endif 108 109 , { 110 PTHREAD_MUTEX_DEFAULT, 1, 0, "Pshared mutex"} 111 #ifndef WITHOUT_XOPEN 112 , { 113 PTHREAD_MUTEX_NORMAL, 1, 0, "Pshared Normal mutex"} 114 , { 115 PTHREAD_MUTEX_ERRORCHECK, 1, 0, "Pshared Errorcheck mutex"} 116 , { 117 PTHREAD_MUTEX_RECURSIVE, 1, 0, "Pshared Recursive mutex"} 118 #endif 119 120 , { 121 PTHREAD_MUTEX_DEFAULT, 1, 1, "Pshared mutex across processes"} 122 #ifndef WITHOUT_XOPEN 123 , { 124 PTHREAD_MUTEX_NORMAL, 1, 1, 125 "Pshared Normal mutex across processes"} 126 , { 127 PTHREAD_MUTEX_ERRORCHECK, 1, 1, 128 "Pshared Errorcheck mutex across processes"} 129 , { 130 PTHREAD_MUTEX_RECURSIVE, 1, 1, 131 "Pshared Recursive mutex across processes"} 132 #endif 133 }; 134 135 #define NSCENAR (sizeof(scenarii)/sizeof(scenarii[0])) 136 137 /* The test function will only perform a trylock operation then return. */ 138 void *tf(void *arg) 139 { 140 testdata_t *td = (testdata_t *) arg; 141 142 td->status = pthread_mutex_trylock(&(td->mtx)); 143 144 if (td->status == 0) { 145 int ret; 146 147 ret = pthread_mutex_unlock(&(td->mtx)); 148 if (ret != 0) { 149 UNRESOLVED(ret, "Failed to unlock a locked semaphore"); 150 } 151 } 152 153 return NULL; 154 } 155 156 /* Main entry point. */ 157 int main(void) 158 { 159 int ret; 160 int sc; 161 pthread_mutexattr_t ma; 162 163 testdata_t *td; 164 testdata_t alternativ; 165 166 int do_fork; 167 168 pid_t child_pr = 0, chkpid; 169 int status; 170 pthread_t child_th; 171 172 long pshared, mf; 173 174 /* Initialize output */ 175 output_init(); 176 177 /* Test system abilities */ 178 pshared = sysconf(_SC_THREAD_PROCESS_SHARED); 179 mf = sysconf(_SC_MAPPED_FILES); 180 181 #if VERBOSE > 0 182 output("Test starting\n"); 183 output("System abilities:\n"); 184 output(" TSH : %li\n", pshared); 185 output(" MF : %li\n", mf); 186 if ((mf < 0) || (pshared < 0)) 187 output("Process-shared attributes won't be tested\n"); 188 #endif 189 190 #ifdef WITHOUT_XOPEN 191 #if VERBOSE > 0 192 output 193 ("As XSI extension is disabled, we won't test the feature across process\n"); 194 #endif 195 mf = -1; 196 #endif 197 198 /********** 199 * Allocate space for the testdata structure 200 */ 201 if (mf < 0) { 202 /* Cannot mmap a file (or not interested in this), we use an alternative method */ 203 td = &alternativ; 204 pshared = -1; /* We won't do this testing anyway */ 205 #if VERBOSE > 0 206 output("Testdata allocated in the process memory.\n"); 207 #endif 208 } 209 #ifndef WITHOUT_XOPEN 210 else { 211 /* We will place the test data in a mmaped file */ 212 char filename[] = "/tmp/mutex_trylock_1-2-XXXXXX"; 213 size_t sz; 214 void *mmaped; 215 int fd; 216 char *tmp; 217 218 /* We now create the temp files */ 219 fd = mkstemp(filename); 220 if (fd == -1) { 221 UNRESOLVED(errno, 222 "Temporary file could not be created"); 223 } 224 225 /* and make sure the file will be deleted when closed */ 226 unlink(filename); 227 228 #if VERBOSE > 1 229 output("Temp file created (%s).\n", filename); 230 #endif 231 232 sz = (size_t) sysconf(_SC_PAGESIZE); 233 234 tmp = calloc(1, sz); 235 if (tmp == NULL) { 236 UNRESOLVED(errno, "Memory allocation failed"); 237 } 238 239 /* Write the data to the file. */ 240 if (write(fd, tmp, sz) != (ssize_t) sz) { 241 UNRESOLVED(sz, "Writting to the file failed"); 242 } 243 244 free(tmp); 245 246 /* Now we can map the file in memory */ 247 mmaped = 248 mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); 249 if (mmaped == MAP_FAILED) { 250 UNRESOLVED(errno, "mmap failed"); 251 } 252 253 td = (testdata_t *) mmaped; 254 255 /* Our datatest structure is now in shared memory */ 256 #if VERBOSE > 1 257 output("Testdata allocated in shared memory.\n"); 258 #endif 259 } 260 #endif 261 262 /********** 263 * For each test scenario, initialize the attributes and other variables. 264 * Do the whole thing for each time to test. 265 */ 266 for (sc = 0; sc < NSCENAR; sc++) { 267 #if VERBOSE > 1 268 output("[parent] Preparing attributes for: %s\n", 269 scenarii[sc].descr); 270 #endif 271 /* set / reset everything */ 272 do_fork = 0; 273 ret = pthread_mutexattr_init(&ma); 274 if (ret != 0) { 275 UNRESOLVED(ret, 276 "[parent] Unable to initialize the mutex attribute object"); 277 } 278 #ifndef WITHOUT_XOPEN 279 /* Set the mutex type */ 280 ret = pthread_mutexattr_settype(&ma, scenarii[sc].m_type); 281 if (ret != 0) { 282 UNRESOLVED(ret, "[parent] Unable to set mutex type"); 283 } 284 #if VERBOSE > 1 285 output("[parent] Mutex type : %i\n", scenarii[sc].m_type); 286 #endif 287 #endif 288 289 /* Set the pshared attributes, if supported */ 290 if ((pshared > 0) && (scenarii[sc].m_pshared != 0)) { 291 ret = 292 pthread_mutexattr_setpshared(&ma, 293 PTHREAD_PROCESS_SHARED); 294 if (ret != 0) { 295 UNRESOLVED(ret, 296 "[parent] Unable to set the mutex process-shared"); 297 } 298 #if VERBOSE > 1 299 output("[parent] Mutex is process-shared\n"); 300 #endif 301 } 302 #if VERBOSE > 1 303 else { 304 output("[parent] Mutex is process-private\n"); 305 } 306 #endif 307 308 /* Tell whether the test will be across processes */ 309 if ((pshared > 0) && (scenarii[sc].fork != 0)) { 310 do_fork = 1; 311 #if VERBOSE > 1 312 output("[parent] Child will be a new process\n"); 313 #endif 314 } 315 #if VERBOSE > 1 316 else { 317 output("[parent] Child will be a new thread\n"); 318 } 319 #endif 320 321 /********** 322 * Initialize the testdata_t structure with the previously defined attributes 323 */ 324 /* Initialize the mutex */ 325 ret = pthread_mutex_init(&(td->mtx), &ma); 326 if (ret != 0) { 327 UNRESOLVED(ret, "[parent] Mutex init failed"); 328 } 329 330 /* Initialize the other datas from the test structure */ 331 td->status = 0; 332 333 /********** 334 * Proceed to the actual testing 335 */ 336 /* Trylock the mutex twice before creating children */ 337 ret = pthread_mutex_trylock(&(td->mtx)); 338 if (ret != 0) { 339 UNRESOLVED(ret, "[parent] Unable to trylock the mutex"); 340 } 341 ret = pthread_mutex_trylock(&(td->mtx)); 342 #ifndef WITHOUT_XOPEN 343 if (scenarii[sc].m_type == PTHREAD_MUTEX_RECURSIVE) { 344 if (ret != 0) { 345 UNRESOLVED(ret, 346 "Failed to pthread_mutex_trylock() twice a recursive mutex"); 347 } 348 349 /* Unlock once so the count is "1" */ 350 ret = pthread_mutex_unlock(&(td->mtx)); 351 if (ret != 0) { 352 UNRESOLVED(ret, "Failed to unlock the mutex"); 353 } 354 } else 355 #endif 356 if (ret == 0) { 357 FAILED 358 ("Main was able to pthread_mutex_trylock() twice without error"); 359 } 360 361 /* Create the children */ 362 if (do_fork != 0) { 363 /* We are testing across processes */ 364 child_pr = fork(); 365 if (child_pr == -1) { 366 UNRESOLVED(errno, "[parent] Fork failed"); 367 } 368 369 if (child_pr == 0) { 370 #if VERBOSE > 3 371 output 372 ("[child] Child process is starting...\n"); 373 #endif 374 375 if (tf((void *)td) != NULL) { 376 UNRESOLVED(-1, 377 "[child] Got an unexpected return value from test function"); 378 } else { 379 /* We cannot use the PASSED macro here since it would terminate the output */ 380 exit(0); 381 } 382 } 383 /* Only the parent process goes further */ 384 } else { /* do_fork == 0 */ 385 386 /* We are testing across two threads */ 387 ret = pthread_create(&child_th, NULL, tf, td); 388 if (ret != 0) { 389 UNRESOLVED(ret, 390 "[parent] Unable to create the child thread."); 391 } 392 } 393 394 /* Wait for the child to terminate */ 395 if (do_fork != 0) { 396 /* We were testing across processes */ 397 ret = 0; 398 chkpid = waitpid(child_pr, &status, 0); 399 if (chkpid != child_pr) { 400 output("Expected pid: %i. Got %i\n", 401 (int)child_pr, (int)chkpid); 402 UNRESOLVED(errno, "Waitpid failed"); 403 } 404 if (WIFSIGNALED(status)) { 405 output("Child process killed with signal %d\n", 406 WTERMSIG(status)); 407 UNRESOLVED(-1, "Child process was killed"); 408 } 409 410 if (WIFEXITED(status)) { 411 ret = WEXITSTATUS(status); 412 } else { 413 UNRESOLVED(-1, 414 "Child process was neither killed nor exited"); 415 } 416 417 if (ret != 0) { 418 exit(ret); /* Output has already been closed in child */ 419 } 420 421 } else { /* child was a thread */ 422 423 ret = pthread_join(child_th, NULL); 424 if (ret != 0) { 425 UNRESOLVED(ret, 426 "[parent] Unable to join the thread"); 427 } 428 } 429 430 /* Check the child status */ 431 if (td->status != EBUSY) { 432 output("Unexpected return value: %d (%s)\n", td->status, 433 strerror(td->status)); 434 FAILED 435 ("pthread_mutex_trylock() did not return EBUSY in the child"); 436 } 437 438 /* Unlock the mutex */ 439 ret = pthread_mutex_unlock(&(td->mtx)); 440 if (ret != 0) { 441 UNRESOLVED(ret, "Failed to unlock the mutex"); 442 } 443 444 /********** 445 * Destroy the data 446 */ 447 ret = pthread_mutex_destroy(&(td->mtx)); 448 if (ret != 0) { 449 UNRESOLVED(ret, "Failed to destroy the mutex"); 450 } 451 452 ret = pthread_mutexattr_destroy(&ma); 453 if (ret != 0) { 454 UNRESOLVED(ret, 455 "Failed to destroy the mutex attribute object"); 456 } 457 458 } /* Proceed to the next scenario */ 459 460 #if VERBOSE > 0 461 output("Test passed\n"); 462 #endif 463 464 PASSED; 465 } 466