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