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