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