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 * This function is a cancelation point: when cancelability 21 * is PTHREAD_CANCEL_DEFERRED and a cancel request arrives, the thread 22 * must relock the mutex before the first (if any) clean up handler is called. 23 24 * The steps are: 25 * -> Create a thread 26 * -> this thread locks a mutex then waits for a condition 27 * -> cancel the thread 28 * -> the cancelation handler will test if the thread owns the mutex. 29 */ 30 31 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 32 #define _POSIX_C_SOURCE 200112L 33 34 /* We need the XSI extention for the mutex attributes */ 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 <time.h> 49 #include <semaphore.h> 50 51/********************************************************************************************/ 52/****************************** Test framework *****************************************/ 53/********************************************************************************************/ 54 #include "testfrmw.h" 55 #include "testfrmw.c" 56 /* This header is responsible for defining the following macros: 57 * UNRESOLVED(ret, descr); 58 * where descr is a description of the error and ret is an int (error code for example) 59 * FAILED(descr); 60 * where descr is a short text saying why the test has failed. 61 * PASSED(); 62 * No parameter. 63 * 64 * Both three macros shall terminate the calling process. 65 * The testcase shall not terminate in any other maneer. 66 * 67 * The other file defines the functions 68 * void output_init() 69 * void output(char * string, ...) 70 * 71 * Those may be used to output information. 72 */ 73 74/********************************************************************************************/ 75/********************************** Configuration ******************************************/ 76/********************************************************************************************/ 77#ifndef VERBOSE 78#define VERBOSE 1 79#endif 80 81#ifndef WITHOUT_ALTCLK 82#define USE_ALTCLK /* make tests with MONOTONIC CLOCK if supported */ 83#endif 84 85/********************************************************************************************/ 86/*********************************** Test case *****************************************/ 87/********************************************************************************************/ 88 89struct 90{ 91 pthread_mutex_t mtx; 92 pthread_cond_t cnd; 93 int type; 94 sem_t semA; 95 sem_t semB; 96 int bool; 97} data; 98 99 100/**** First handler that will be poped 101 * This one works only with recursive mutexes 102 */ 103void clnp1 (void * arg) 104{ 105 int ret; 106 if (data.type == PTHREAD_MUTEX_RECURSIVE) 107 { 108 ret = pthread_mutex_trylock(&(data.mtx)); 109 if (ret != 0) { FAILED("Unable to double-lock a recursive mutex in clean-up handler 1"); } 110 ret = pthread_mutex_unlock(&(data.mtx)); 111 if (ret != 0) { UNRESOLVED(ret, "Unable to unlock double-locked recursive mutex in clean-up handler 1"); } 112 } 113 return; 114} 115 116/**** Second handler 117 * This one will trigger an action in main thread, while we are owning the mutex 118 */ 119void clnp2 (void * arg) 120{ 121 int ret; 122 do { 123 ret = sem_post(&(data.semA)); 124 } while ((ret != 0) && (errno == EINTR)); 125 if (ret != 0) { UNRESOLVED(errno, "Sem post failed in cleanup handler 2"); } 126 127 do { 128 ret = sem_wait(&(data.semB)); 129 } while ((ret != 0) && (errno == EINTR)); 130 if (ret != 0) { UNRESOLVED(errno, "Sem wait failed in cleanup handler 2"); } 131 132 return; 133} 134 135/**** Third handler 136 * Will actually unlock the mutex, then try to unlock second time to check an error is returned 137 */ 138void clnp3 (void * arg) 139{ 140 int ret; 141 142 ret = pthread_mutex_unlock(&(data.mtx)); 143 if (ret != 0) { UNRESOLVED(ret, "Unable to unlock mutex in clean-up handler 3"); } 144 145 if ((data.type == PTHREAD_MUTEX_ERRORCHECK) || (data.type == PTHREAD_MUTEX_RECURSIVE)) 146 { 147 ret = pthread_mutex_unlock(&(data.mtx)); 148 if (ret == 0) { UNRESOLVED(ret, "Was able to unlock unlocked mutex in clean-up handler 3"); } 149 } 150 151 return; 152} 153 154 155/**** Thread function 156 * This function will lock the mutex, then install the cleanup handlers 157 * and wait for the cond. At this point it will be canceled. 158 */ 159void * threaded (void * arg) 160{ 161 int ret; 162 163 ret= pthread_mutex_lock(&(data.mtx)); 164 if (ret != 0) { UNRESOLVED(ret, "Failed to lock the mutex in thread"); } 165 166 /* Tell the main thread we got the lock */ 167 do { 168 ret = sem_post(&(data.semA)); 169 } while ((ret != 0) && (errno == EINTR)); 170 if (ret != 0) { UNRESOLVED(errno, "Sem post failed in cleanup handler 2"); } 171 172 pthread_cleanup_push ( clnp3, NULL); 173 pthread_cleanup_push ( clnp2, NULL); 174 pthread_cleanup_push ( clnp1, NULL); 175 176 do { 177 ret = pthread_cond_wait(&(data.cnd), &(data.mtx)); 178 } while ((ret == 0) && (data.bool == 0)); 179 180 if (ret != 0) { UNRESOLVED(ret , "Wait failed"); } /* We will exit even if the error is timedwait */ 181 182 /* If we are here, the thread was not canceled */ 183 FAILED("The thread has not been canceled"); 184 185 pthread_cleanup_pop(0); 186 pthread_cleanup_pop(0); 187 pthread_cleanup_pop(1); 188 189 return NULL; 190} 191 192int main(int argc, char * argv[]) 193{ 194 int ret, i; 195 void * rc; 196 197 pthread_mutexattr_t ma; 198 pthread_condattr_t ca; 199 pthread_t th; 200 201 long altclk_ok, pshared_ok; 202 203 struct 204 { 205 char altclk; /* Want to use alternative clock */ 206 char pshared; /* Want to use process-shared primitives */ 207 int type; /* mutex type */ 208 char * descr; /* Description of the case */ 209 210 } scenar[] = 211 { {0, 0, PTHREAD_MUTEX_NORMAL, "Normal mutex" } 212#ifdef USE_ALTCLK 213 ,{1, 0, PTHREAD_MUTEX_NORMAL, "Normal mutex + altclock cond" } 214 ,{1, 1, PTHREAD_MUTEX_NORMAL, "PShared mutex + altclock cond" } 215#endif 216 ,{0, 1, PTHREAD_MUTEX_NORMAL, "Pshared mutex" } 217#ifndef WITHOUT_XOPEN 218 ,{0, 0, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck mutex" } 219 ,{0, 0, PTHREAD_MUTEX_RECURSIVE , "Recursive mutex" } 220#ifdef USE_ALTCLK 221 ,{1, 0, PTHREAD_MUTEX_RECURSIVE , "Recursive mutex + altclock cond" } 222 ,{1, 0, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck mutex + altclock cond" } 223 ,{1, 1, PTHREAD_MUTEX_RECURSIVE , "Recursive pshared mutex + altclock cond" } 224 ,{1, 1, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck pshared mutex + altclock cond" } 225#endif 226 ,{0, 1, PTHREAD_MUTEX_RECURSIVE , "Recursive pshared mutex" } 227 ,{0, 1, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck pshared mutex" } 228#endif 229 }; 230 231 output_init(); 232 233 /* Initialize the constants */ 234 altclk_ok = sysconf(_SC_CLOCK_SELECTION); 235 if (altclk_ok > 0) 236 altclk_ok = sysconf(_SC_MONOTONIC_CLOCK); 237#ifndef USE_ALTCLK 238 if (altclk_ok > 0) 239 output("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n"); 240#endif 241 242 pshared_ok = sysconf(_SC_THREAD_PROCESS_SHARED); 243 244 #if VERBOSE > 0 245 output("Test starting\n"); 246 output(" Process-shared primitive %s be tested\n", (pshared_ok>0)?"will":"won't"); 247 output(" Alternative clock for cond %s be tested\n", (altclk_ok>0)?"will":"won't"); 248 #endif 249 250 ret = sem_init(&(data.semA), 0, 0); 251 if (ret != 0) { UNRESOLVED(errno, "Unable to init sem A"); } 252 253 ret = sem_init(&(data.semB), 0, 0); 254 if (ret != 0) { UNRESOLVED(errno, "Unable to init sem B"); } 255 256 for (i=0; i< (sizeof(scenar) / sizeof(scenar[0])); i++) 257 { 258 #if VERBOSE > 1 259 output("Starting test for %s\n", scenar[i].descr); 260 #endif 261 262 /* Initialize the data structure */ 263 ret = pthread_mutexattr_init(&ma); 264 if (ret != 0) { UNRESOLVED(ret, "Mutex attribute object init failed"); } 265 266 ret = pthread_mutexattr_settype(&ma, scenar[i].type); 267 if (ret != 0) { UNRESOLVED(ret, "Unable to set mutex type"); } 268 269 if ((pshared_ok > 0) && (scenar[i].pshared != 0)) 270 { 271 ret = pthread_mutexattr_setpshared(&ma, PTHREAD_PROCESS_SHARED); 272 if (ret != 0) { UNRESOLVED(ret, "Unable to set mutex process-shared"); } 273 } 274 275 ret = pthread_condattr_init(&ca); 276 if (ret != 0) { UNRESOLVED(ret, "Cond attribute object init failed"); } 277 278 if ((pshared_ok > 0) && (scenar[i].pshared != 0)) 279 { 280 ret = pthread_condattr_setpshared(&ca, PTHREAD_PROCESS_SHARED); 281 if (ret != 0) { UNRESOLVED(ret, "Unable to set cond process-shared"); } 282 } 283 284 #ifdef USE_ALTCLK 285 if ((altclk_ok > 0) && (scenar[i].altclk != 0)) 286 { 287 ret = pthread_condattr_setclock(&ca, CLOCK_MONOTONIC); 288 if (ret != 0) { UNRESOLVED(ret, "Unable to set alternative (monotonic) clock for cond"); } 289 } 290 #endif 291 292 ret = pthread_mutex_init(&(data.mtx), &ma); 293 if (ret != 0) { UNRESOLVED(ret, "Unable to init mutex"); } 294 295 ret = pthread_cond_init(&(data.cnd), &ca); 296 if (ret != 0) { UNRESOLVED(ret, "Unable to initialize condvar"); } 297 298 ret = pthread_mutexattr_gettype(&ma, &(data.type)); 299 if (ret != 0) { UNRESOLVED(ret, "Unable to get type from mutex attr"); } 300 301 data.bool = 0; 302 303 /** Data is ready, create the thread */ 304 #if VERBOSE > 1 305 output("Initialization OK, starting thread\n"); 306 #endif 307 308 ret = pthread_create(&th, NULL, threaded, NULL); 309 if (ret != 0) { UNRESOLVED(ret, "Thread creation failed"); } 310 311 /** Wait for the thread to be waiting */ 312 do { 313 ret = sem_wait(&(data.semA)); 314 } while ((ret != 0) && (errno == EINTR)); 315 if (ret != 0) { UNRESOLVED(errno, "Sem wait failed in main"); } 316 317 ret = pthread_mutex_lock(&(data.mtx)); 318 if (ret != 0) { UNRESOLVED(ret, "Unable to lock mutex in main"); } 319 320 data.bool = 1; 321 322 /** Cancel the thread */ 323 ret = pthread_cancel(th); 324 if (ret != 0) { UNRESOLVED(ret, "Thread cancelation failed"); } 325 326 sched_yield(); 327 #ifndef WITHOUT_XOPEN 328 usleep(100); 329 #endif 330 331 ret = pthread_mutex_unlock(&(data.mtx)); 332 if (ret != 0) { UNRESOLVED(ret, "Unable to unlock mutex in main"); } 333 334 /** Wait for the thread to be executing second cleanup handler */ 335 do { 336 ret = sem_wait(&(data.semA)); 337 } while ((ret != 0) && (errno == EINTR)); 338 if (ret != 0) { UNRESOLVED(errno, "Sem wait failed in main"); } 339 340 /** Here the child should own the mutex, we check this */ 341 ret = pthread_mutex_trylock(&(data.mtx)); 342 if (ret == 0) { FAILED("The child did not own the mutex inside the cleanup handler"); } 343 344 /** Let the cleanups go on */ 345 do { 346 ret = sem_post(&(data.semB)); 347 } while ((ret != 0) && (errno == EINTR)); 348 if (ret != 0) { UNRESOLVED(errno, "Sem post failed in main"); } 349 350 /** Join the thread */ 351 ret = pthread_join(th, &rc); 352 if (ret != 0) { UNRESOLVED(ret, "Unable to join the thread"); } 353 if (rc != PTHREAD_CANCELED) { FAILED("thread was not canceled"); } 354 355 #if VERBOSE > 1 356 output("Test passed for %s\n\n", scenar[i].descr); 357 #endif 358 359 /* Destroy datas */ 360 ret = pthread_cond_destroy(&(data.cnd)); 361 if (ret != 0) { UNRESOLVED(ret, "Cond destroy failed"); } 362 363 ret = pthread_mutex_destroy(&(data.mtx)); 364 if (ret != 0) { UNRESOLVED(ret, "Mutex destroy failed"); } 365 366 ret = pthread_condattr_destroy(&ca); 367 if (ret != 0) { UNRESOLVED(ret, "Cond attribute destroy failed"); } 368 369 ret = pthread_mutexattr_destroy(&ma); 370 if (ret != 0) { UNRESOLVED(ret, "Mutex attr destroy failed"); } 371 } /* Proceed to next case */ 372 373 ret = sem_destroy(&(data.semA)); 374 if (ret != 0) { UNRESOLVED(errno, "Sem destroy failed"); } 375 376 ret = sem_destroy(&(data.semB)); 377 if (ret != 0) { UNRESOLVED(errno, "Sem destroy failed"); } 378 379 PASSED; 380} 381 382