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 * This function is a cancelation point: when cancelability 20 * is PTHREAD_CANCEL_DEFERRED and a cancel request falls, the thread 21 * must relock the mutex before the first (if any) clean up handler is called. 22 23 * The steps are: 24 * -> Create a thread 25 * -> this thread locks a mutex then waits for a condition 26 * -> cancel the thread 27 * -> the cancelation handler will test if the thread owns the mutex. 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 #ifndef WITHOUT_XOPEN 35 #define _XOPEN_SOURCE 600 36 #endif 37 38 #include <pthread.h> 39 #include <stdarg.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <unistd.h> 43 44 #include <errno.h> 45 #include <time.h> 46 #include <semaphore.h> 47 48 #include "../testfrmw/testfrmw.h" 49 #include "../testfrmw/testfrmw.c" 50 51 #ifndef VERBOSE 52 #define VERBOSE 1 53 #endif 54 55 #ifndef WITHOUT_ALTCLK 56 #define USE_ALTCLK /* make tests with MONOTONIC CLOCK if supported */ 57 #endif 58 59 struct { 60 pthread_mutex_t mtx; 61 pthread_cond_t cnd; 62 int type; 63 clockid_t cid; 64 sem_t semA; 65 sem_t semB; 66 int bool; 67 } data; 68 69 /**** First handler that will be poped 70 * This one works only with recursive mutexes 71 */ 72 void clnp1(void *arg) 73 { 74 int ret; 75 76 (void) arg; 77 78 if (data.type == PTHREAD_MUTEX_RECURSIVE) { 79 ret = pthread_mutex_trylock(&(data.mtx)); 80 if (ret != 0) { 81 FAILED 82 ("Unable to double-lock a recursive mutex in clean-up handler 1"); 83 } 84 ret = pthread_mutex_unlock(&(data.mtx)); 85 if (ret != 0) { 86 UNRESOLVED(ret, 87 "Unable to unlock double-locked recursive mutex in clean-up handler 1"); 88 } 89 } 90 return; 91 } 92 93 /**** Second handler 94 * This one will trigger an action in main thread, while we are owning the mutex 95 */ 96 void clnp2(void *arg) 97 { 98 int ret; 99 100 (void) arg; 101 102 do { 103 ret = sem_post(&(data.semA)); 104 } while ((ret != 0) && (errno == EINTR)); 105 if (ret != 0) { 106 UNRESOLVED(errno, "Sem post failed in cleanup handler 2"); 107 } 108 109 do { 110 ret = sem_wait(&(data.semB)); 111 } while ((ret != 0) && (errno == EINTR)); 112 if (ret != 0) { 113 UNRESOLVED(errno, "Sem wait failed in cleanup handler 2"); 114 } 115 116 return; 117 } 118 119 /**** Third handler 120 * Will actually unlock the mutex, then try to unlock second time to check an error is returned 121 */ 122 void clnp3(void *arg) 123 { 124 int ret; 125 126 (void) arg; 127 128 ret = pthread_mutex_unlock(&(data.mtx)); 129 if (ret != 0) { 130 UNRESOLVED(ret, "Unable to unlock mutex in clean-up handler 3"); 131 } 132 133 if ((data.type == PTHREAD_MUTEX_ERRORCHECK) 134 || (data.type == PTHREAD_MUTEX_RECURSIVE)) { 135 ret = pthread_mutex_unlock(&(data.mtx)); 136 if (ret == 0) { 137 UNRESOLVED(ret, 138 "Was able to unlock unlocked mutex in clean-up handler 3"); 139 } 140 } 141 142 return; 143 } 144 145 /**** Thread function 146 * This function will lock the mutex, then install the cleanup handlers 147 * and wait for the cond. At this point it will be canceled. 148 */ 149 void *threaded(void *arg) 150 { 151 int ret; 152 153 (void) arg; 154 155 struct timespec ts; 156 157 ret = clock_gettime(data.cid, &ts); 158 if (ret != 0) { 159 UNRESOLVED(ret, "Unable to get time from clock"); 160 } 161 162 ts.tv_sec += 30; 163 164 ret = pthread_mutex_lock(&(data.mtx)); 165 if (ret != 0) { 166 UNRESOLVED(ret, "Failed to lock the mutex in thread"); 167 } 168 169 do { 170 ret = sem_post(&(data.semA)); 171 } while ((ret != 0) && (errno == EINTR)); 172 if (ret != 0) { 173 UNRESOLVED(errno, "Sem post failed in thread"); 174 } 175 176 pthread_cleanup_push(clnp3, NULL); 177 pthread_cleanup_push(clnp2, NULL); 178 pthread_cleanup_push(clnp1, NULL); 179 180 do { 181 ret = pthread_cond_timedwait(&(data.cnd), &(data.mtx), &ts); 182 } while ((ret == 0) && (data.bool == 0)); 183 184 if (ret != 0) { 185 UNRESOLVED(ret, "Timedwait failed"); 186 } 187 188 /* We will exit even if the error is timedwait */ 189 /* If we are here, the thread was not canceled */ 190 FAILED("The thread has not been canceled"); 191 192 pthread_cleanup_pop(0); 193 pthread_cleanup_pop(0); 194 pthread_cleanup_pop(1); 195 196 return NULL; 197 } 198 199 int main(void) 200 { 201 int ret; 202 unsigned int i; 203 void *rc; 204 205 pthread_mutexattr_t ma; 206 pthread_condattr_t ca; 207 pthread_t th; 208 209 long altclk_ok, pshared_ok; 210 211 struct { 212 char altclk; /* Want to use alternative clock */ 213 char pshared; /* Want to use process-shared primitives */ 214 int type; /* mutex type */ 215 char *descr; /* Description of the case */ 216 217 } scenar[] = { { 218 0, 0, PTHREAD_MUTEX_NORMAL, "Normal mutex"} 219 #ifdef USE_ALTCLK 220 , { 221 1, 0, PTHREAD_MUTEX_NORMAL, "Normal mutex + altclock cond"} 222 , { 223 1, 1, PTHREAD_MUTEX_NORMAL, "PShared mutex + altclock cond"} 224 #endif 225 , { 226 0, 1, PTHREAD_MUTEX_NORMAL, "Pshared mutex"} 227 #ifndef WITHOUT_XOPEN 228 , { 229 0, 0, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck mutex"} 230 , { 231 0, 0, PTHREAD_MUTEX_RECURSIVE, "Recursive mutex"} 232 #ifdef USE_ALTCLK 233 , { 234 1, 0, PTHREAD_MUTEX_RECURSIVE, "Recursive mutex + altclock cond"} 235 , { 236 1, 0, PTHREAD_MUTEX_ERRORCHECK, 237 "Errorcheck mutex + altclock cond"} 238 , { 239 1, 1, PTHREAD_MUTEX_RECURSIVE, 240 "Recursive pshared mutex + altclock cond"} 241 , { 242 1, 1, PTHREAD_MUTEX_ERRORCHECK, 243 "Errorcheck pshared mutex + altclock cond"} 244 #endif 245 , { 246 0, 1, PTHREAD_MUTEX_RECURSIVE, "Recursive pshared mutex"} 247 , { 248 0, 1, PTHREAD_MUTEX_ERRORCHECK, "Errorcheck pshared mutex"} 249 #endif 250 }; 251 252 output_init(); 253 254 /* Initialize the constants */ 255 altclk_ok = sysconf(_SC_CLOCK_SELECTION); 256 if (altclk_ok > 0) 257 altclk_ok = sysconf(_SC_MONOTONIC_CLOCK); 258 #ifndef USE_ALTCLK 259 if (altclk_ok > 0) 260 output 261 ("Implementation supports the MONOTONIC CLOCK but option is disabled in test.\n"); 262 #endif 263 264 pshared_ok = sysconf(_SC_THREAD_PROCESS_SHARED); 265 266 #if VERBOSE > 0 267 output("Test starting\n"); 268 output(" Process-shared primitive %s be tested\n", 269 (pshared_ok > 0) ? "will" : "won't"); 270 output(" Alternative clock for cond %s be tested\n", 271 (altclk_ok > 0) ? "will" : "won't"); 272 #endif 273 274 ret = sem_init(&(data.semA), 0, 0); 275 if (ret != 0) { 276 UNRESOLVED(errno, "Unable to init sem A"); 277 } 278 279 ret = sem_init(&(data.semB), 0, 0); 280 if (ret != 0) { 281 UNRESOLVED(errno, "Unable to init sem B"); 282 } 283 284 for (i = 0; i < (sizeof(scenar) / sizeof(scenar[0])); i++) { 285 #if VERBOSE > 1 286 output("Starting test for %s\n", scenar[i].descr); 287 #endif 288 289 /* Initialize the data structure */ 290 ret = pthread_mutexattr_init(&ma); 291 if (ret != 0) { 292 UNRESOLVED(ret, "Mutex attribute object init failed"); 293 } 294 295 ret = pthread_mutexattr_settype(&ma, scenar[i].type); 296 if (ret != 0) { 297 UNRESOLVED(ret, "Unable to set mutex type"); 298 } 299 300 if ((pshared_ok > 0) && (scenar[i].pshared != 0)) { 301 ret = 302 pthread_mutexattr_setpshared(&ma, 303 PTHREAD_PROCESS_SHARED); 304 if (ret != 0) { 305 UNRESOLVED(ret, 306 "Unable to set mutex process-shared"); 307 } 308 } 309 310 ret = pthread_condattr_init(&ca); 311 if (ret != 0) { 312 UNRESOLVED(ret, "Cond attribute object init failed"); 313 } 314 315 if ((pshared_ok > 0) && (scenar[i].pshared != 0)) { 316 ret = 317 pthread_condattr_setpshared(&ca, 318 PTHREAD_PROCESS_SHARED); 319 if (ret != 0) { 320 UNRESOLVED(ret, 321 "Unable to set cond process-shared"); 322 } 323 } 324 #ifdef USE_ALTCLK 325 if ((altclk_ok > 0) && (scenar[i].altclk != 0)) { 326 ret = pthread_condattr_setclock(&ca, CLOCK_MONOTONIC); 327 if (ret != 0) { 328 UNRESOLVED(ret, 329 "Unable to set alternative (monotonic) clock for cond"); 330 } 331 } 332 #endif 333 334 ret = pthread_mutex_init(&(data.mtx), &ma); 335 if (ret != 0) { 336 UNRESOLVED(ret, "Unable to init mutex"); 337 } 338 339 ret = pthread_cond_init(&(data.cnd), &ca); 340 if (ret != 0) { 341 UNRESOLVED(ret, "Unable to initialize condvar"); 342 } 343 344 ret = pthread_mutexattr_gettype(&ma, &(data.type)); 345 if (ret != 0) { 346 UNRESOLVED(ret, "Unable to get type from mutex attr"); 347 } 348 #ifdef USE_ALTCLK 349 ret = pthread_condattr_getclock(&ca, &(data.cid)); 350 if (ret != 0) { 351 UNRESOLVED(ret, 352 "Unable to get clock ID from cond attr"); 353 } 354 #else 355 data.cid = CLOCK_REALTIME; 356 #endif 357 358 data.bool = 0; 359 360 /** Data is ready, create the thread */ 361 #if VERBOSE > 1 362 output("Initialization OK, starting thread\n"); 363 #endif 364 365 ret = pthread_create(&th, NULL, threaded, NULL); 366 if (ret != 0) { 367 UNRESOLVED(ret, "Thread creation failed"); 368 } 369 370 /** Wait for the thread to be waiting */ 371 do { 372 ret = sem_wait(&(data.semA)); 373 } while ((ret != 0) && (errno == EINTR)); 374 if (ret != 0) { 375 UNRESOLVED(errno, "Sem wait failed in main"); 376 } 377 378 ret = pthread_mutex_lock(&(data.mtx)); 379 if (ret != 0) { 380 UNRESOLVED(ret, "Unable to lock mutex in main"); 381 } 382 383 data.bool = 1; 384 385 /** Cancel the thread */ 386 ret = pthread_cancel(th); 387 if (ret != 0) { 388 UNRESOLVED(ret, "Thread cancelation failed"); 389 } 390 391 sched_yield(); 392 #ifndef WITHOUT_XOPEN 393 usleep(100); 394 #endif 395 396 ret = pthread_mutex_unlock(&(data.mtx)); 397 if (ret != 0) { 398 UNRESOLVED(ret, "Unable to unlock mutex in main"); 399 } 400 401 /** Wait for the thread to be executing second cleanup handler */ 402 do { 403 ret = sem_wait(&(data.semA)); 404 } while ((ret != 0) && (errno == EINTR)); 405 if (ret != 0) { 406 UNRESOLVED(errno, "Sem wait failed in main"); 407 } 408 409 /** Here the child should own the mutex, we check this */ 410 ret = pthread_mutex_trylock(&(data.mtx)); 411 if (ret == 0) { 412 FAILED 413 ("The child did not own the mutex inside the cleanup handler"); 414 } 415 416 /** Let the cleanups go on */ 417 do { 418 ret = sem_post(&(data.semB)); 419 } while ((ret != 0) && (errno == EINTR)); 420 if (ret != 0) { 421 UNRESOLVED(errno, "Sem post failed in main"); 422 } 423 424 /** Join the thread */ 425 ret = pthread_join(th, &rc); 426 if (ret != 0) { 427 UNRESOLVED(ret, "Unable to join the thread"); 428 } 429 if (rc != PTHREAD_CANCELED) { 430 FAILED("thread was not canceled"); 431 } 432 #if VERBOSE > 1 433 output("Test passed for %s\n", scenar[i].descr); 434 #endif 435 436 /* Destroy datas */ 437 ret = pthread_cond_destroy(&(data.cnd)); 438 if (ret != 0) { 439 UNRESOLVED(ret, "Cond destroy failed"); 440 } 441 442 ret = pthread_mutex_destroy(&(data.mtx)); 443 if (ret != 0) { 444 UNRESOLVED(ret, "Mutex destroy failed"); 445 } 446 447 ret = pthread_condattr_destroy(&ca); 448 if (ret != 0) { 449 UNRESOLVED(ret, "Cond attribute destroy failed"); 450 } 451 452 ret = pthread_mutexattr_destroy(&ma); 453 if (ret != 0) { 454 UNRESOLVED(ret, "Mutex attr destroy failed"); 455 } 456 } /* Proceed to next case */ 457 458 ret = sem_destroy(&(data.semA)); 459 if (ret != 0) { 460 UNRESOLVED(errno, "Sem destroy failed"); 461 } 462 463 ret = sem_destroy(&(data.semB)); 464 if (ret != 0) { 465 UNRESOLVED(errno, "Sem destroy failed"); 466 } 467 468 PASSED; 469 } 470