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