1 /* 2 * Copyright (c) 2000-2001, 2005-2007 Sendmail, Inc. and its suppliers. 3 * All rights reserved. 4 * 5 * By using this file, you agree to the terms and conditions set 6 * forth in the LICENSE file which can be found at the top level of 7 * the sendmail distribution. 8 */ 9 10 #include <sm/gen.h> 11 SM_RCSID("@(#)$Id: t-sem.c,v 1.16 2007/03/21 23:22:10 ca Exp $") 12 13 #include <stdio.h> 14 15 #if SM_CONF_SEM 16 # include <stdlib.h> 17 # include <unistd.h> 18 # include <sysexits.h> 19 # include <sm/heap.h> 20 # include <sm/string.h> 21 # include <sm/signal.h> 22 # include <sm/test.h> 23 # include <sm/sem.h> 24 25 # define T_SM_SEM_KEY (4321L) 26 27 static void 28 delay(t, s) 29 int t; 30 char *s; 31 { 32 if (t > 0) 33 { 34 #if DEBUG 35 fprintf(stderr, "sleep(%d) before %s\n", t, s); 36 #endif /* DEBUG */ 37 sleep(t); 38 } 39 #if DEBUG 40 fprintf(stderr, "%s\n", s); 41 #endif /* DEBUG */ 42 } 43 44 45 /* 46 ** SEMINTER -- interactive testing of semaphores. 47 ** 48 ** Parameters: 49 ** owner -- create semaphores. 50 ** 51 ** Returns: 52 ** 0 on success 53 ** < 0 on failure. 54 */ 55 56 static int 57 seminter(owner) 58 bool owner; 59 { 60 int semid; 61 int t; 62 63 semid = sm_sem_start(T_SM_SEM_KEY, SM_NSEM, 0, owner); 64 if (semid < 0) 65 { 66 perror("sm_sem_start failed"); 67 return 1; 68 } 69 70 while ((t = getchar()) != EOF) 71 { 72 switch (t) 73 { 74 case 'a': 75 delay(0, "try to acq"); 76 if (sm_sem_acq(semid, 0, 2) < 0) 77 { 78 perror("sm_sem_acq failed"); 79 return 1; 80 } 81 delay(0, "acquired"); 82 break; 83 84 case 'r': 85 delay(0, "try to rel"); 86 if (sm_sem_rel(semid, 0, 2) < 0) 87 { 88 perror("sm_sem_rel failed"); 89 return 1; 90 } 91 delay(0, "released"); 92 break; 93 94 case 'v': 95 if ((t = sm_sem_get(semid, 0)) < 0) 96 { 97 perror("get_sem failed"); 98 return 1; 99 } 100 printf("semval: %d\n", t); 101 break; 102 103 } 104 } 105 if (owner) 106 return sm_sem_stop(semid); 107 return 0; 108 } 109 110 /* 111 ** SEM_CLEANUP -- cleanup if something breaks 112 ** 113 ** Parameters: 114 ** sig -- signal. 115 ** 116 ** Returns: 117 ** none. 118 */ 119 120 static int semid_c = -1; 121 void 122 sem_cleanup(sig) 123 int sig; 124 { 125 if (semid_c >= 0) 126 (void) sm_sem_stop(semid_c); 127 exit(EX_UNAVAILABLE); 128 } 129 130 /* 131 ** SEMTEST -- test of semaphores 132 ** 133 ** Parameters: 134 ** owner -- create semaphores. 135 ** 136 ** Returns: 137 ** 0 on success 138 ** < 0 on failure. 139 */ 140 141 # define MAX_CNT 10 142 143 static int 144 semtest(owner) 145 int owner; 146 { 147 int semid, r; 148 int cnt = 0; 149 150 semid = sm_sem_start(T_SM_SEM_KEY, 1, 0, owner); 151 if (semid < 0) 152 { 153 perror("sm_sem_start failed"); 154 return -1; 155 } 156 157 if (owner) 158 { 159 /* just in case someone kills the program... */ 160 semid_c = semid; 161 (void) sm_signal(SIGHUP, sem_cleanup); 162 (void) sm_signal(SIGINT, sem_cleanup); 163 (void) sm_signal(SIGTERM, sem_cleanup); 164 165 delay(1, "parent: acquire 1"); 166 cnt = 0; 167 do 168 { 169 r = sm_sem_acq(semid, 0, 0); 170 if (r < 0) 171 { 172 sleep(1); 173 ++cnt; 174 } 175 } while (r < 0 && cnt <= MAX_CNT); 176 SM_TEST(r >= 0); 177 if (r < 0) 178 return r; 179 180 delay(3, "parent: release 1"); 181 cnt = 0; 182 do 183 { 184 r = sm_sem_rel(semid, 0, 0); 185 if (r < 0) 186 { 187 sleep(1); 188 ++cnt; 189 } 190 } while (r < 0 && cnt <= MAX_CNT); 191 SM_TEST(r >= 0); 192 if (r < 0) 193 return r; 194 195 delay(1, "parent: getval"); 196 cnt = 0; 197 do 198 { 199 r = sm_sem_get(semid, 0); 200 if (r <= 0) 201 { 202 sleep(1); 203 ++cnt; 204 } 205 } while (r <= 0 && cnt <= MAX_CNT); 206 SM_TEST(r > 0); 207 if (r <= 0) 208 return r; 209 210 delay(1, "parent: acquire 2"); 211 cnt = 0; 212 do 213 { 214 r = sm_sem_acq(semid, 0, 0); 215 if (r < 0) 216 { 217 sleep(1); 218 ++cnt; 219 } 220 } while (r < 0 && cnt <= MAX_CNT); 221 SM_TEST(r >= 0); 222 if (r < 0) 223 return r; 224 225 cnt = 0; 226 do 227 { 228 r = sm_sem_rel(semid, 0, 0); 229 if (r < 0) 230 { 231 sleep(1); 232 ++cnt; 233 } 234 } while (r < 0 && cnt <= MAX_CNT); 235 SM_TEST(r >= 0); 236 if (r < 0) 237 return r; 238 } 239 else 240 { 241 delay(1, "child: acquire 1"); 242 cnt = 0; 243 do 244 { 245 r = sm_sem_acq(semid, 0, 0); 246 if (r < 0) 247 { 248 sleep(1); 249 ++cnt; 250 } 251 } while (r < 0 && cnt <= MAX_CNT); 252 SM_TEST(r >= 0); 253 if (r < 0) 254 return r; 255 256 delay(1, "child: release 1"); 257 cnt = 0; 258 do 259 { 260 r = sm_sem_rel(semid, 0, 0); 261 if (r < 0) 262 { 263 sleep(1); 264 ++cnt; 265 } 266 } while (r < 0 && cnt <= MAX_CNT); 267 SM_TEST(r >= 0); 268 if (r < 0) 269 return r; 270 271 } 272 if (owner) 273 return sm_sem_stop(semid); 274 return 0; 275 } 276 277 int 278 main(argc, argv) 279 int argc; 280 char *argv[]; 281 { 282 bool interactive = false; 283 bool owner = false; 284 int ch; 285 int r = 0; 286 287 # define OPTIONS "io" 288 while ((ch = getopt(argc, argv, OPTIONS)) != -1) 289 { 290 switch ((char) ch) 291 { 292 case 'i': 293 interactive = true; 294 break; 295 296 case 'o': 297 owner = true; 298 break; 299 300 default: 301 break; 302 } 303 } 304 305 if (interactive) 306 r = seminter(owner); 307 else 308 { 309 pid_t pid; 310 311 printf("This test takes about 8 seconds.\n"); 312 printf("If it takes longer than 30 seconds, please interrupt it\n"); 313 printf("and compile again without semaphore support, i.e.,"); 314 printf("-DSM_CONF_SEM=0\n"); 315 if ((pid = fork()) < 0) 316 { 317 perror("fork failed\n"); 318 return -1; 319 } 320 321 sm_test_begin(argc, argv, "test semaphores"); 322 if (pid == 0) 323 { 324 /* give the parent the chance to setup data */ 325 sleep(1); 326 r = semtest(false); 327 } 328 else 329 { 330 r = semtest(true); 331 } 332 SM_TEST(r == 0); 333 return sm_test_end(); 334 } 335 return r; 336 } 337 #else /* SM_CONF_SEM */ 338 int 339 main(argc, argv) 340 int argc; 341 char *argv[]; 342 { 343 printf("No support for semaphores configured on this machine\n"); 344 return 0; 345 } 346 #endif /* SM_CONF_SEM */ 347