1 /* 2 * Copyright (c) 2000-2001, 2005, 2008 Proofpoint, 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: sem.c,v 1.15 2013-11-22 20:51:43 ca Exp $") 12 13 #if SM_CONF_SEM 14 # include <stdlib.h> 15 # include <unistd.h> 16 # include <errno.h> 17 # include <sm/string.h> 18 # include <sm/heap.h> 19 # include <sm/conf.h> 20 # include <sm/sem.h> 21 22 /* 23 ** SM_SEM_START -- initialize semaphores 24 ** 25 ** Parameters: 26 ** key -- key for semaphores. 27 ** nsem -- number of semaphores. 28 ** semflg -- flag for semget(), if 0, use a default. 29 ** owner -- create semaphores. 30 ** 31 ** Returns: 32 ** id for semaphores. 33 ** < 0 on failure. 34 */ 35 36 int 37 sm_sem_start(key, nsem, semflg, owner) 38 key_t key; 39 int nsem; 40 int semflg; 41 bool owner; 42 { 43 int semid, i, err; 44 unsigned short *semvals; 45 46 semvals = NULL; 47 if (semflg == 0) 48 semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3); 49 if (owner) 50 semflg |= IPC_CREAT|IPC_EXCL; 51 semid = semget(key, nsem, semflg); 52 if (semid < 0) 53 goto error; 54 55 if (owner) 56 { 57 union semun semarg; 58 59 semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals); 60 if (semvals == NULL) 61 goto error; 62 semarg.array = semvals; 63 64 /* initialize semaphore values to be available */ 65 for (i = 0; i < nsem; i++) 66 semvals[i] = 1; 67 if (semctl(semid, 0, SETALL, semarg) < 0) 68 goto error; 69 } 70 return semid; 71 72 error: 73 err = errno; 74 if (semvals != NULL) 75 sm_free(semvals); 76 if (semid >= 0) 77 sm_sem_stop(semid); 78 return (err > 0) ? (0 - err) : -1; 79 } 80 81 /* 82 ** SM_SEM_STOP -- stop using semaphores. 83 ** 84 ** Parameters: 85 ** semid -- id for semaphores. 86 ** 87 ** Returns: 88 ** 0 on success. 89 ** < 0 on failure. 90 */ 91 92 int 93 sm_sem_stop(semid) 94 int semid; 95 { 96 return semctl(semid, 0, IPC_RMID, NULL); 97 } 98 99 /* 100 ** SM_SEM_ACQ -- acquire semaphore. 101 ** 102 ** Parameters: 103 ** semid -- id for semaphores. 104 ** semnum -- number of semaphore. 105 ** timeout -- how long to wait for operation to succeed. 106 ** 107 ** Returns: 108 ** 0 on success. 109 ** < 0 on failure. 110 */ 111 112 int 113 sm_sem_acq(semid, semnum, timeout) 114 int semid; 115 int semnum; 116 int timeout; 117 { 118 int r; 119 struct sembuf semops[1]; 120 121 semops[0].sem_num = semnum; 122 semops[0].sem_op = -1; 123 semops[0].sem_flg = SEM_UNDO | 124 (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT); 125 if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER) 126 return semop(semid, semops, 1); 127 do 128 { 129 r = semop(semid, semops, 1); 130 if (r == 0) 131 return r; 132 sleep(1); 133 --timeout; 134 } while (timeout > 0); 135 return r; 136 } 137 138 /* 139 ** SM_SEM_REL -- release semaphore. 140 ** 141 ** Parameters: 142 ** semid -- id for semaphores. 143 ** semnum -- number of semaphore. 144 ** timeout -- how long to wait for operation to succeed. 145 ** 146 ** Returns: 147 ** 0 on success. 148 ** < 0 on failure. 149 */ 150 151 int 152 sm_sem_rel(semid, semnum, timeout) 153 int semid; 154 int semnum; 155 int timeout; 156 { 157 int r; 158 struct sembuf semops[1]; 159 160 # if PARANOID 161 /* XXX should we check whether the value is already 0 ? */ 162 SM_REQUIRE(sm_get_sem(semid, semnum) > 0); 163 # endif 164 165 semops[0].sem_num = semnum; 166 semops[0].sem_op = 1; 167 semops[0].sem_flg = SEM_UNDO | 168 (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT); 169 if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER) 170 return semop(semid, semops, 1); 171 do 172 { 173 r = semop(semid, semops, 1); 174 if (r == 0) 175 return r; 176 sleep(1); 177 --timeout; 178 } while (timeout > 0); 179 return r; 180 } 181 182 /* 183 ** SM_SEM_GET -- get semaphore value. 184 ** 185 ** Parameters: 186 ** semid -- id for semaphores. 187 ** semnum -- number of semaphore. 188 ** 189 ** Returns: 190 ** value of semaphore on success. 191 ** < 0 on failure. 192 */ 193 194 int 195 sm_sem_get(semid, semnum) 196 int semid; 197 int semnum; 198 { 199 int semval; 200 201 if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0) 202 return -1; 203 return semval; 204 } 205 206 /* 207 ** SM_SEMSETOWNER -- set owner/group/mode of semaphores. 208 ** 209 ** Parameters: 210 ** semid -- id for semaphores. 211 ** uid -- uid to use 212 ** gid -- gid to use 213 ** mode -- mode to use 214 ** 215 ** Returns: 216 ** 0 on success. 217 ** < 0 on failure. 218 */ 219 220 #ifdef __STDC__ 221 int 222 sm_semsetowner(int semid, uid_t uid, gid_t gid, MODE_T mode) 223 #else /* __STDC__ */ 224 int 225 sm_semsetowner(semid, uid, gid, mode) 226 int semid; 227 uid_t uid; 228 gid_t gid; 229 MODE_T mode; 230 #endif /* __STDC__ */ 231 { 232 int r; 233 struct semid_ds semidds; 234 union semun { 235 int val; 236 struct semid_ds *buf; 237 ushort *array; 238 } arg; 239 240 memset(&semidds, 0, sizeof(semidds)); 241 arg.buf = &semidds; 242 if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0) 243 return r; 244 semidds.sem_perm.uid = uid; 245 semidds.sem_perm.gid = gid; 246 semidds.sem_perm.mode = mode; 247 if ((r = semctl(semid, 1, IPC_SET, arg)) < 0) 248 return r; 249 return 0; 250 } 251 #endif /* SM_CONF_SEM */ 252