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 type is PTHREAD_MUTEX_RECURSIVE, 20 * then the mutex maintains the concept of a lock count. 21 * When a thread successfully acquires a mutex for the first time, 22 * the lock count is set to one. Every time a thread relocks this mutex, 23 * the lock count is incremented by one. 24 * Each time the thread unlocks the mutex, 25 * the lock count is decremented by one. 26 * When the lock count reaches zero, 27 * the mutex becomes available and others threads can acquire it. 28 29 * The steps are: 30 * ->Create a mutex with recursive attribute 31 * ->Create a threads 32 * ->Parent locks the mutex twice, unlocks once. 33 * ->Child attempts to lock the mutex. 34 * ->Parent unlocks the mutex. 35 * ->Parent unlocks the mutex (shall fail) 36 * ->Child unlocks the mutex. 37 */ 38 39 /* 40 * - adam.li (at) intel.com 2004-05-13 41 * Add to PTS. Please refer to http://nptl.bullopensource.org/phpBB/ 42 * for general information 43 */ 44 45 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 46 #define _POSIX_C_SOURCE 200112L 47 48 /* We need the setrlimit() function from X/OPEN standard */ 49 #ifndef WITHOUT_XOPEN 50 #define _XOPEN_SOURCE 600 51 52 /********************************************************************************************/ 53 /****************************** standard includes *****************************************/ 54 /********************************************************************************************/ 55 #include <pthread.h> 56 #include <unistd.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <stdarg.h> 60 #include <semaphore.h> /* for synchronization */ 61 #include <errno.h> 62 63 /********************************************************************************************/ 64 /****************************** Test framework *****************************************/ 65 /********************************************************************************************/ 66 #include "../testfrmw/testfrmw.h" 67 #include "../testfrmw/testfrmw.c" 68 /* This header is responsible for defining the following macros: 69 * UNRESOLVED(ret, descr); 70 * where descr is a description of the error and ret is an int (error code for example) 71 * FAILED(descr); 72 * where descr is a short text saying why the test has failed. 73 * PASSED(); 74 * No parameter. 75 * 76 * Both three macros shall terminate the calling process. 77 * The testcase shall not terminate in any other maneer. 78 * 79 * The other file defines the functions 80 * void output_init() 81 * void output(char * string, ...) 82 * 83 * Those may be used to output information. 84 */ 85 86 /********************************************************************************************/ 87 /********************************** Configuration ******************************************/ 88 /********************************************************************************************/ 89 #ifndef VERBOSE 90 #define VERBOSE 1 91 #endif 92 93 /********************************************************************************************/ 94 /*********************************** Test case *****************************************/ 95 /********************************************************************************************/ 96 pthread_mutex_t mtx; 97 sem_t sem; 98 99 /** child thread function **/ 100 void *threaded(void *arg) 101 { 102 int ret; 103 /* Try to lock the mutex once. The call must fail here. */ 104 ret = pthread_mutex_trylock(&mtx); 105 if (ret == 0) { 106 FAILED("Child first trylock succeeded"); 107 } 108 #if VERBOSE >1 109 output("[thrd] Try to lock the mutex.... failed (normal)\n"); 110 #endif 111 112 /* Free the parent thread and lock the mutex (must success) */ 113 if ((ret = sem_post(&sem))) { 114 UNRESOLVED(errno, "1st post sem in child failed"); 115 } 116 117 if ((ret = pthread_mutex_lock(&mtx))) { 118 UNRESOLVED(ret, "Child lock failed"); 119 } 120 #if VERBOSE >1 121 output("[thrd] Successfully locked the mutex\n"); 122 #endif 123 124 /* Wait for the parent to let us go on */ 125 if ((ret = sem_post(&sem))) { 126 UNRESOLVED(errno, "2nd post sem in child failed"); 127 } 128 129 /* Unlock and exit */ 130 if ((ret = pthread_mutex_unlock(&mtx))) { 131 UNRESOLVED(ret, "Unlock in child failed"); 132 } 133 #if VERBOSE >1 134 output("[thrd] Unlocked the mutex, ready to terminate.\n"); 135 #endif 136 137 return NULL; 138 } 139 140 /** parent thread function **/ 141 int main(void) 142 { 143 int ret; 144 int i; 145 pthread_mutexattr_t ma; 146 pthread_t child; 147 148 output_init(); 149 150 #if VERBOSE >1 151 output("Initialize the PTHREAD_MUTEX_RECURSIVE mutex\n"); 152 #endif 153 154 /* Initialize the semaphore */ 155 if ((ret = sem_init(&sem, 0, 0))) { 156 UNRESOLVED(ret, "Sem init failed"); 157 } 158 159 /* We initialize the recursive mutex */ 160 if ((ret = pthread_mutexattr_init(&ma))) { 161 UNRESOLVED(ret, "Mutex attribute init failed"); 162 } 163 164 if ((ret = pthread_mutexattr_settype(&ma, PTHREAD_MUTEX_RECURSIVE))) { 165 UNRESOLVED(ret, "Set type RECURSIVE failed"); 166 } 167 168 if ((ret = pthread_mutex_init(&mtx, &ma))) { 169 UNRESOLVED(ret, "Recursive mutex init failed"); 170 } 171 172 if ((ret = pthread_mutexattr_destroy(&ma))) { 173 UNRESOLVED(ret, "Mutex attribute destroy failed"); 174 } 175 176 /* -- The mutex is now ready for testing -- */ 177 178 /* First, we lock it twice and unlock once */ 179 if ((ret = pthread_mutex_lock(&mtx))) { 180 UNRESOLVED(ret, "First lock failed"); 181 } 182 183 if ((ret = pthread_mutex_lock(&mtx))) { 184 FAILED("Second lock failed"); 185 } 186 187 if ((ret = pthread_mutex_unlock(&mtx))) { 188 FAILED("First unlock failed"); 189 } 190 #if VERBOSE >1 191 output 192 ("The mutex has been locked twice and unlocked once, start the thread now.\n"); 193 #endif 194 195 /* Here this thread owns the mutex and the internal count is "1" */ 196 197 /* We create the child thread */ 198 if ((ret = pthread_create(&child, NULL, threaded, NULL))) { 199 UNRESOLVED(ret, "Unable to create child thread"); 200 } 201 202 /* then wait for child to be ready */ 203 if ((ret = sem_wait(&sem))) { 204 UNRESOLVED(errno, "Wait sem in child failed"); 205 } 206 #if VERBOSE >1 207 output("[main] unlock the mutex.\n"); 208 #endif 209 210 /* We can now unlock the mutex */ 211 if ((ret = pthread_mutex_unlock(&mtx))) { 212 FAILED("Second unlock failed"); 213 } 214 215 /* We wait for the child to lock the mutex */ 216 if ((ret = sem_wait(&sem))) { 217 UNRESOLVED(errno, "Wait sem in child failed"); 218 } 219 220 /* Then, try to unlock the mutex (owned by the child or unlocked) */ 221 ret = pthread_mutex_unlock(&mtx); 222 if (ret == 0) { 223 FAILED("Unlock of unowned mutex succeeds"); 224 } 225 226 /* Everything seems OK here */ 227 if ((ret = pthread_join(child, NULL))) { 228 UNRESOLVED(ret, "Child join failed"); 229 } 230 231 /* Simple loop to double-check */ 232 #if VERBOSE >1 233 output("[main] joined the thread.\n"); 234 output("Lock & unlock the mutex 50 times.\n"); 235 #endif 236 237 for (i = 0; i < 50; i++) { 238 if ((ret = pthread_mutex_lock(&mtx))) { 239 FAILED("Lock failed in loop"); 240 } 241 } 242 for (i = 0; i < 50; i++) { 243 if ((ret = pthread_mutex_unlock(&mtx))) { 244 FAILED("Unlock failed in loop"); 245 } 246 } 247 248 ret = pthread_mutex_unlock(&mtx); 249 if (ret == 0) { 250 FAILED("Unlock succeeds after the loop"); 251 } 252 #if VERBOSE >1 253 output("Everything went OK; destroy the mutex.\n"); 254 #endif 255 /* The test passed, we destroy the mutex */ 256 if ((ret = pthread_mutex_destroy(&mtx))) { 257 UNRESOLVED(ret, "Final mutex destroy failed"); 258 } 259 260 PASSED; 261 } 262 #else /* WITHOUT_XOPEN */ 263 int main(void) 264 { 265 output_init(); 266 UNTESTED("This test requires XSI features"); 267 } 268 #endif 269