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