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 attribute pointer passed to pthread_mutex_init is NULL, 20 * the effects on the mutex are the same as if a default mutex attribute object had been passed. 21 * 22 * The steps are: 23 * * create two mutexes. One is initialized with NULL attribute, the other with a default attribute object. 24 * * Compare the following features between the two mutexes: 25 * -> Can it cause / detect a deadlock? (attempt to lock a mutex the thread already owns). 26 * If detected, do both mutexes cause the same error code? 27 * -> Is an error returned when unlocking the mutex in unlocked state? 28 * When unlocking the mutex owned by another thread? 29 * 30 * The test will pass if the results of each feature are the same for the two mutexes 31 * (making no assumption on what is the default behavior). 32 * The test will be unresolved if any initialization fails. 33 * The test will fail if a feature differs between the two mutex objects. 34 */ 35 36 /* 37 * - adam.li (at) intel.com 2004-05-09 38 * Add to PTS. Please refer to http://nptl.bullopensource.org/phpBB/ 39 * for general information 40 */ 41 42 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 43 #define _POSIX_C_SOURCE 200112L 44 /********************************************************************************************/ 45 /****************************** standard includes *****************************************/ 46 /********************************************************************************************/ 47 #include <pthread.h> 48 #include <semaphore.h> 49 #include <errno.h> 50 #include <stdio.h> 51 #include <unistd.h> 52 #include <stdarg.h> 53 #include <stdlib.h> 54 55 /********************************************************************************************/ 56 /****************************** Test framework *****************************************/ 57 /********************************************************************************************/ 58 #include "../testfrmw/testfrmw.h" 59 #include "../testfrmw/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 /********************************************************************************************/ 88 89 /**** global variables ****/ 90 pthread_mutex_t *p_mtx; 91 int retval = 0; 92 int returned = 0; 93 int canceled = 0; 94 sem_t semA, semB; 95 96 /***** Cancelation handlers *****/ 97 void cleanup_deadlk(void *arg) 98 { 99 canceled = 1; 100 pthread_mutex_unlock(p_mtx); 101 } 102 103 /***** Threads functions *****/ 104 void *deadlk_issue(void *arg) 105 { 106 int ret, tmp; 107 108 if ((ret = pthread_mutex_lock(p_mtx))) { 109 UNRESOLVED(ret, "First mutex lock in deadlk_issue"); 110 } 111 pthread_cleanup_push(cleanup_deadlk, NULL); 112 if ((ret = pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, &tmp))) { 113 UNRESOLVED(ret, "Set cancel type in deadlk_issue"); 114 } 115 if ((ret = pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &tmp))) { 116 UNRESOLVED(ret, "Set cancel state in deadlk_issue"); 117 } 118 #if VERBOSE >1 119 output("Thread releases the semaphore...\n"); 120 #endif 121 if ((ret = sem_post(&semA))) { 122 UNRESOLVED(errno, "Sem_post in deadlk_issue"); 123 } 124 125 returned = 0; 126 retval = pthread_mutex_lock(p_mtx); 127 returned = 1; 128 129 if ((ret = pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &tmp))) { 130 UNRESOLVED(ret, "Set cancel state in deadlk_issue"); 131 } 132 pthread_cleanup_pop(0); 133 return NULL; 134 } 135 136 void *unlock_issue(void *arg) 137 { 138 int ret; 139 140 #if VERBOSE >1 141 output("Locking in child...\n"); 142 #endif 143 if ((ret = pthread_mutex_lock(p_mtx))) { 144 UNRESOLVED(ret, "First mutex lock in unlock_issue"); 145 } 146 147 if ((ret = sem_post(&semA))) { 148 UNRESOLVED(errno, "Sem_post in unlock_issue"); 149 } 150 151 if ((ret = sem_wait(&semB))) { 152 UNRESOLVED(errno, "Sem_wait in unlock_issue"); 153 } 154 155 if (retval != 0) { /* parent thread failed to unlock the mutex) */ 156 #if VERBOSE >1 157 output("Unlocking in child...\n"); 158 #endif 159 if ((ret = pthread_mutex_unlock(p_mtx))) { 160 FAILED 161 ("Mutex unlock returned an error but mutex is unlocked."); 162 } 163 } 164 165 return NULL; 166 } 167 168 /***** main program *****/ 169 int main(void) 170 { 171 pthread_mutex_t mtx_null, mtx_def; 172 pthread_mutexattr_t mattr; 173 pthread_t thr; 174 175 pthread_mutex_t *tab_mutex[2] = { &mtx_null, &mtx_def }; 176 int tab_res[2][3] = { {0, 0, 0}, {0, 0, 0} }; 177 178 int ret; 179 void *th_ret; 180 181 int i; 182 183 output_init(); 184 185 #if VERBOSE >1 186 output("Test starting...\n"); 187 #endif 188 189 /* We first initialize the two mutexes. */ 190 if ((ret = pthread_mutex_init(&mtx_null, NULL))) { 191 UNRESOLVED(ret, "NULL mutex init"); 192 } 193 194 if ((ret = pthread_mutexattr_init(&mattr))) { 195 UNRESOLVED(ret, "Mutex attribute init"); 196 } 197 if ((ret = pthread_mutex_init(&mtx_def, &mattr))) { 198 UNRESOLVED(ret, "Default attribute mutex init"); 199 } 200 201 if ((ret = pthread_mutexattr_destroy(&mattr))) { 202 UNRESOLVED(ret, "Mutex attribute destroy"); 203 } 204 205 if ((ret = sem_init(&semA, 0, 0))) { 206 UNRESOLVED(errno, "Sem A init"); 207 } 208 if ((ret = sem_init(&semB, 0, 0))) { 209 UNRESOLVED(errno, "Sem B init"); 210 } 211 #if VERBOSE >1 212 output("Data initialized...\n"); 213 #endif 214 215 /* OK let's go for the first part of the test : abnormals unlocking */ 216 217 /* We first check if unlocking an unlocked mutex returns an error. */ 218 retval = pthread_mutex_unlock(tab_mutex[0]); 219 ret = pthread_mutex_unlock(tab_mutex[1]); 220 #if VERBOSE >0 221 output 222 ("Results for unlock issue #1:\n mutex 1 unlocking returned %i\n mutex 2 unlocking returned %i\n", 223 retval, ret); 224 #endif 225 if (ret != retval) { 226 FAILED("Unlocking an unlocked mutex behaves differently."); 227 } 228 229 /* Now we focus on unlocking a mutex lock by another thread */ 230 for (i = 0; i < 2; i++) { 231 p_mtx = tab_mutex[i]; 232 tab_res[i][0] = 0; 233 tab_res[i][1] = 0; 234 tab_res[i][2] = 0; 235 236 #if VERBOSE >1 237 output("Creating thread (unlock)...\n"); 238 #endif 239 240 if ((ret = pthread_create(&thr, NULL, unlock_issue, NULL))) { 241 UNRESOLVED(ret, "Unlock issue thread create"); 242 } 243 244 if ((ret = sem_wait(&semA))) { 245 UNRESOLVED(errno, 246 "Sem A wait failed for unlock issue."); 247 } 248 #if VERBOSE >1 249 output("Unlocking in parent...\n"); 250 #endif 251 retval = pthread_mutex_unlock(p_mtx); 252 253 if ((ret = sem_post(&semB))) { 254 UNRESOLVED(errno, 255 "Sem B post failed for unlock issue."); 256 } 257 258 if ((ret = pthread_join(thr, &th_ret))) { 259 UNRESOLVED(ret, "Join thread"); 260 } 261 #if VERBOSE >1 262 output("Thread joined successfully...\n"); 263 #endif 264 265 tab_res[i][0] = retval; 266 } 267 #if VERBOSE >0 268 output 269 ("Results for unlock issue #2:\n mutex 1 returned %i\n mutex 2 returned %i\n", 270 tab_res[0][0], tab_res[1][0]); 271 #endif 272 273 if (tab_res[0][0] != tab_res[1][0]) { 274 FAILED("Unlocking an unowned mutex behaves differently."); 275 } 276 277 /* We now are going to test the deadlock issue 278 */ 279 280 /* We start with testing the NULL mutex features */ 281 for (i = 0; i < 2; i++) { 282 p_mtx = tab_mutex[i]; 283 tab_res[i][0] = 0; 284 tab_res[i][1] = 0; 285 tab_res[i][2] = 0; 286 287 #if VERBOSE >1 288 output("Creating thread (deadlk)...\n"); 289 #endif 290 291 if ((ret = pthread_create(&thr, NULL, deadlk_issue, NULL))) { 292 UNRESOLVED(ret, "Deadlk_issue thread create"); 293 } 294 295 /* Now we are waiting the thread is ready to relock the mutex. */ 296 if ((ret = sem_wait(&semA))) { 297 UNRESOLVED(errno, "Sem wait"); 298 } 299 300 /* To ensure thread runs until second lock, we yield here */ 301 sched_yield(); 302 303 /* OK, now we cancel the thread */ 304 canceled = 0; 305 #if VERBOSE >1 306 output("Cancel thread...\n"); 307 #endif 308 if (returned == 0) 309 if ((ret = pthread_cancel(thr))) { 310 UNRESOLVED(ret, "Cancel thread (deadlk_issue)"); 311 } 312 #if VERBOSE >1 313 output("Thread canceled...\n"); 314 #endif 315 316 if ((ret = pthread_join(thr, &th_ret))) { 317 UNRESOLVED(ret, "Join thread"); 318 } 319 #if VERBOSE >1 320 output("Thread joined successfully...\n"); 321 #endif 322 323 tab_res[i][2] = retval; 324 tab_res[i][1] = returned; 325 tab_res[i][0] = canceled; 326 } 327 328 /* Now we parse the results */ 329 #if VERBOSE >0 330 output 331 ("Results for deadlock issue:\n mutex 1 \t%s\t%s%i\n mutex 2 \t%s\t%s%i\n", 332 tab_res[0][0] ? "deadlock" : "no deadlock", 333 tab_res[0][1] ? "returned " : "did not return ", tab_res[0][2], 334 tab_res[1][0] ? "deadlock" : "no deadlock", 335 tab_res[1][1] ? "returned " : "did not return ", tab_res[1][2]); 336 #endif 337 338 if (tab_res[0][0] != tab_res[1][0]) { 339 FAILED("One mutex deadlocks, not the other"); 340 } 341 342 if (tab_res[0][1] != tab_res[1][1]) { 343 UNRESOLVED(tab_res[0][1], "Abnormal situation!"); 344 } 345 346 if ((tab_res[0][1] == 1) && (tab_res[0][2] != tab_res[1][2])) { 347 FAILED("The locks returned different error codes."); 348 } 349 350 PASSED; 351 } 352