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 file is a stress test for the pthread_cond_init function. 19 20 * The steps are: 21 * -> Create some threads 22 * -> each thread loops on initializing and destroying a condition variable 23 * -> the whole process stop when receiving signal SIGUSR1 24 */ 25 26 /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */ 27 #define _POSIX_C_SOURCE 200112L 28 29 /********************************************************************************************/ 30 /****************************** standard includes *****************************************/ 31 /********************************************************************************************/ 32 #include <pthread.h> 33 #include <errno.h> 34 #include <signal.h> 35 #include <unistd.h> 36 #include <stdio.h> 37 #include <stdlib.h> 38 #include <stdarg.h> 39 40 #include <time.h> 41 42 /********************************************************************************************/ 43 /****************************** Test framework *****************************************/ 44 /********************************************************************************************/ 45 #include "testfrmw.h" 46 #include "testfrmw.c" 47 /* This header is responsible for defining the following macros: 48 * UNRESOLVED(ret, descr); 49 * where descr is a description of the error and ret is an int (error code for example) 50 * FAILED(descr); 51 * where descr is a short text saying why the test has failed. 52 * PASSED(); 53 * No parameter. 54 * 55 * Both three macros shall terminate the calling process. 56 * The testcase shall not terminate in any other maneer. 57 * 58 * The other file defines the functions 59 * void output_init() 60 * void output(char * string, ...) 61 * 62 * Those may be used to output information. 63 */ 64 65 /********************************************************************************************/ 66 /********************************** Configuration ******************************************/ 67 /********************************************************************************************/ 68 #ifndef SCALABILITY_FACTOR 69 #define SCALABILITY_FACTOR 1 70 #endif 71 #ifndef VERBOSE 72 #define VERBOSE 1 73 #endif 74 #define N 20 75 76 /********************************************************************************************/ 77 /*********************************** Test case *****************************************/ 78 /********************************************************************************************/ 79 char do_it = 1; 80 pthread_mutex_t cnt_mtx = PTHREAD_MUTEX_INITIALIZER; 81 unsigned long long cnt = 0; 82 83 /******** Threads function *********/ 84 void *threaded(void *arg) 85 { 86 int me = (int)arg; 87 pthread_cond_t cnd; 88 pthread_cond_t *pcnd; 89 pthread_condattr_t ca; 90 pthread_condattr_t *pca; 91 struct timespec now; 92 pthread_mutex_t mtx, *pmtx; 93 int ret; 94 int sz = 4; 95 /* We will use mutex from the stack or from malloc'ed memory */ 96 char loc = ((me % 5) % 2); 97 98 pmtx = &mtx; 99 100 if (loc) { 101 pcnd = &cnd; 102 } else { 103 pcnd = malloc(sizeof(pthread_cond_t)); 104 if (pcnd == NULL) { 105 UNRESOLVED(errno, 106 "Memory allocation for condvar failed"); 107 } 108 } 109 110 me %= sz; 111 112 ret = clock_gettime(CLOCK_REALTIME, &now); 113 if (ret != 0) { 114 UNRESOLVED(errno, "Clock get time (realtime) failed."); 115 } 116 117 switch (me) { 118 case 0: /* We will initialize the cond with NULL pointer attribute */ 119 pca = NULL; 120 break; 121 122 default: /* We will initialize the cond with an attribute object */ 123 if ((ret = pthread_condattr_init(&ca))) { 124 UNRESOLVED(ret, "Cond attribute init failed"); 125 } 126 pca = &ca; 127 128 if ((me == 1) || (me == 3)) { 129 ret = 130 pthread_condattr_setpshared(&ca, 131 PTHREAD_PROCESS_SHARED); 132 if (ret != 0) { 133 UNRESOLVED(ret, 134 "Unable to set PShared condvar"); 135 } 136 } 137 138 if ((sysconf(_SC_MONOTONIC_CLOCK) > 0) 139 && ((me == 1) || (me == 2))) { 140 ret = pthread_condattr_setclock(&ca, CLOCK_MONOTONIC); 141 if (ret != 0) { 142 UNRESOLVED(ret, 143 "Unable to attribute monotonic clock to condvar"); 144 } 145 146 ret = clock_gettime(CLOCK_MONOTONIC, &now); 147 if (ret != 0) { 148 UNRESOLVED(errno, 149 "Clock get time (realtime) failed."); 150 } 151 } 152 153 } 154 155 ret = pthread_mutex_init(pmtx, NULL); 156 if (ret != 0) { 157 UNRESOLVED(ret, "Unable to initialize a mutex"); 158 } 159 ret = pthread_mutex_lock(pmtx); 160 if (ret != 0) { 161 UNRESOLVED(ret, "Unable to lock a mutex"); 162 } 163 164 while (do_it) { 165 ret = pthread_cond_init(pcnd, pca); 166 if (ret != 0) { 167 FAILED("Cond init failed"); 168 } 169 /* We use the mutex to check everything is OK */ 170 ret = pthread_cond_timedwait(pcnd, pmtx, &now); 171 if (ret != ETIMEDOUT) { 172 if (ret == 0) { 173 FAILED(""); 174 } else { 175 UNRESOLVED(ret, 176 "Cond timedwait returned unexpected error code"); 177 } 178 } 179 ret = pthread_cond_signal(pcnd); 180 if (ret != 0) { 181 FAILED("Cond signal failed"); 182 } 183 ret = pthread_cond_broadcast(pcnd); 184 if (ret != 0) { 185 FAILED("Cond broadcast failed"); 186 } 187 ret = pthread_cond_destroy(pcnd); 188 if (ret != 0) { 189 FAILED("Cond destroy failed"); 190 } 191 ret = pthread_mutex_lock(&cnt_mtx); 192 if (ret != 0) { 193 UNRESOLVED(ret, "Unable to lock counter mutex"); 194 } 195 cnt++; 196 ret = pthread_mutex_unlock(&cnt_mtx); 197 if (ret != 0) { 198 UNRESOLVED(ret, "Unable to unlock counter mutex"); 199 } 200 } 201 202 if (!loc) /* cond was malloc'ed */ 203 free(pcnd); 204 205 if (me) 206 if ((ret = pthread_condattr_destroy(pca))) { 207 FAILED("Cond attribute destroy failed at the end"); 208 } 209 210 return NULL; 211 } 212 213 /******** Signal handler ************/ 214 void sighdl(int sig) 215 { 216 do { 217 do_it = 0; 218 } 219 while (do_it); 220 } 221 222 /******** Parent thread *************/ 223 int main(int argc, char *argv[]) 224 { 225 struct sigaction sa; 226 pthread_t threads[N * SCALABILITY_FACTOR]; 227 int i; 228 int ret; 229 230 output_init(); 231 232 sigemptyset(&sa.sa_mask); 233 sa.sa_flags = 0; 234 sa.sa_handler = sighdl; 235 if ((ret = sigaction(SIGUSR1, &sa, NULL))) { 236 UNRESOLVED(ret, "Unable to register signal handler"); 237 } 238 239 for (i = 0; (i < (N * SCALABILITY_FACTOR) && (ret == 0)); i++) { 240 ret = pthread_create(&threads[i], NULL, threaded, (void *)i); 241 } 242 if (ret != 0) { /* A thread creation failed */ 243 /* Stop the started threads */ 244 do { 245 do_it = 0; 246 } 247 while (do_it); 248 for (; i > 0; i--) 249 pthread_join(threads[i - 1], NULL); 250 251 UNRESOLVED(ret, "Unable to create enough threads"); 252 } 253 254 /* Every threads were created; we now just wait */ 255 for (i = 0; i < (N * SCALABILITY_FACTOR); i++) { 256 if ((ret = pthread_join(threads[i], NULL))) { 257 FAILED("Unable to join a thread"); 258 } 259 } 260 #if VERBOSE > 0 261 output("pthread_cond_init stress test passed (%llu iterations)\n", cnt); 262 #endif 263 264 /* Everything went OK */ 265 PASSED; 266 } 267