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