1 /* 2 * Copyright (c) 2000-2001, 2005 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 #pragma ident "%Z%%M% %I% %E% SMI" 11 12 #include <sm/gen.h> 13 SM_RCSID("@(#)$Id: sem.c,v 1.12 2005/03/25 21:27:02 ca Exp $") 14 15 #if SM_CONF_SEM 16 # include <stdlib.h> 17 # include <unistd.h> 18 # include <sm/sem.h> 19 # include <sm/heap.h> 20 21 /* 22 ** SM_SEM_START -- initialize semaphores 23 ** 24 ** Parameters: 25 ** key -- key for semaphores. 26 ** nsem -- number of semaphores. 27 ** semflg -- flag for semget(), if 0, use a default. 28 ** owner -- create semaphores. 29 ** 30 ** Returns: 31 ** id for semaphores. 32 ** < 0 on failure. 33 */ 34 35 int 36 sm_sem_start(key, nsem, semflg, owner) 37 key_t key; 38 int nsem; 39 int semflg; 40 bool owner; 41 { 42 int semid, i; 43 unsigned short *semvals; 44 45 semvals = NULL; 46 if (semflg == 0) 47 semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3); 48 if (owner) 49 semflg |= IPC_CREAT|IPC_EXCL; 50 semid = semget(key, nsem, semflg); 51 if (semid < 0) 52 goto error; 53 54 if (owner) 55 { 56 union semun semarg; 57 58 semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals); 59 if (semvals == NULL) 60 goto error; 61 semarg.array = semvals; 62 63 /* initialize semaphore values to be available */ 64 for (i = 0; i < nsem; i++) 65 semvals[i] = 1; 66 if (semctl(semid, 0, SETALL, semarg) < 0) 67 goto error; 68 } 69 return semid; 70 71 error: 72 if (semvals != NULL) 73 sm_free(semvals); 74 if (semid >= 0) 75 sm_sem_stop(semid); 76 return -1; 77 } 78 79 /* 80 ** SM_SEM_STOP -- stop using semaphores. 81 ** 82 ** Parameters: 83 ** semid -- id for semaphores. 84 ** 85 ** Returns: 86 ** 0 on success. 87 ** < 0 on failure. 88 */ 89 90 int 91 sm_sem_stop(semid) 92 int semid; 93 { 94 return semctl(semid, 0, IPC_RMID, NULL); 95 } 96 97 /* 98 ** SM_SEM_ACQ -- acquire semaphore. 99 ** 100 ** Parameters: 101 ** semid -- id for semaphores. 102 ** semnum -- number of semaphore. 103 ** timeout -- how long to wait for operation to succeed. 104 ** 105 ** Returns: 106 ** 0 on success. 107 ** < 0 on failure. 108 */ 109 110 int 111 sm_sem_acq(semid, semnum, timeout) 112 int semid; 113 int semnum; 114 int timeout; 115 { 116 int r; 117 struct sembuf semops[1]; 118 119 semops[0].sem_num = semnum; 120 semops[0].sem_op = -1; 121 semops[0].sem_flg = SEM_UNDO | 122 (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT); 123 if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER) 124 return semop(semid, semops, 1); 125 do 126 { 127 r = semop(semid, semops, 1); 128 if (r == 0) 129 return r; 130 sleep(1); 131 --timeout; 132 } while (timeout > 0); 133 return r; 134 } 135 136 /* 137 ** SM_SEM_REL -- release semaphore. 138 ** 139 ** Parameters: 140 ** semid -- id for semaphores. 141 ** semnum -- number of semaphore. 142 ** timeout -- how long to wait for operation to succeed. 143 ** 144 ** Returns: 145 ** 0 on success. 146 ** < 0 on failure. 147 */ 148 149 int 150 sm_sem_rel(semid, semnum, timeout) 151 int semid; 152 int semnum; 153 int timeout; 154 { 155 int r; 156 struct sembuf semops[1]; 157 158 #if PARANOID 159 /* XXX should we check whether the value is already 0 ? */ 160 SM_REQUIRE(sm_get_sem(semid, semnum) > 0); 161 #endif /* PARANOID */ 162 163 semops[0].sem_num = semnum; 164 semops[0].sem_op = 1; 165 semops[0].sem_flg = SEM_UNDO | 166 (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT); 167 if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER) 168 return semop(semid, semops, 1); 169 do 170 { 171 r = semop(semid, semops, 1); 172 if (r == 0) 173 return r; 174 sleep(1); 175 --timeout; 176 } while (timeout > 0); 177 return r; 178 } 179 180 /* 181 ** SM_SEM_GET -- get semaphore value. 182 ** 183 ** Parameters: 184 ** semid -- id for semaphores. 185 ** semnum -- number of semaphore. 186 ** 187 ** Returns: 188 ** value of semaphore on success. 189 ** < 0 on failure. 190 */ 191 192 int 193 sm_sem_get(semid, semnum) 194 int semid; 195 int semnum; 196 { 197 int semval; 198 199 if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0) 200 return -1; 201 return semval; 202 } 203 #endif /* SM_CONF_SEM */ 204