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