1 /* 2 * Copyright (c) 2000-2001, 2005, 2008 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: sem.c,v 1.14 2008/05/30 16:26:38 ca Exp $") 12 13 #if SM_CONF_SEM 14 # include <stdlib.h> 15 # include <unistd.h> 16 # include <sm/string.h> 17 # include <sm/sem.h> 18 # include <sm/heap.h> 19 # include <errno.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, err; 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 err = errno; 73 if (semvals != NULL) 74 sm_free(semvals); 75 if (semid >= 0) 76 sm_sem_stop(semid); 77 return (err > 0) ? (0 - err) : -1; 78 } 79 80 /* 81 ** SM_SEM_STOP -- stop using semaphores. 82 ** 83 ** Parameters: 84 ** semid -- id for semaphores. 85 ** 86 ** Returns: 87 ** 0 on success. 88 ** < 0 on failure. 89 */ 90 91 int 92 sm_sem_stop(semid) 93 int semid; 94 { 95 return semctl(semid, 0, IPC_RMID, NULL); 96 } 97 98 /* 99 ** SM_SEM_ACQ -- acquire semaphore. 100 ** 101 ** Parameters: 102 ** semid -- id for semaphores. 103 ** semnum -- number of semaphore. 104 ** timeout -- how long to wait for operation to succeed. 105 ** 106 ** Returns: 107 ** 0 on success. 108 ** < 0 on failure. 109 */ 110 111 int 112 sm_sem_acq(semid, semnum, timeout) 113 int semid; 114 int semnum; 115 int timeout; 116 { 117 int r; 118 struct sembuf semops[1]; 119 120 semops[0].sem_num = semnum; 121 semops[0].sem_op = -1; 122 semops[0].sem_flg = SEM_UNDO | 123 (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT); 124 if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER) 125 return semop(semid, semops, 1); 126 do 127 { 128 r = semop(semid, semops, 1); 129 if (r == 0) 130 return r; 131 sleep(1); 132 --timeout; 133 } while (timeout > 0); 134 return r; 135 } 136 137 /* 138 ** SM_SEM_REL -- release semaphore. 139 ** 140 ** Parameters: 141 ** semid -- id for semaphores. 142 ** semnum -- number of semaphore. 143 ** timeout -- how long to wait for operation to succeed. 144 ** 145 ** Returns: 146 ** 0 on success. 147 ** < 0 on failure. 148 */ 149 150 int 151 sm_sem_rel(semid, semnum, timeout) 152 int semid; 153 int semnum; 154 int timeout; 155 { 156 int r; 157 struct sembuf semops[1]; 158 159 #if PARANOID 160 /* XXX should we check whether the value is already 0 ? */ 161 SM_REQUIRE(sm_get_sem(semid, semnum) > 0); 162 #endif /* PARANOID */ 163 164 semops[0].sem_num = semnum; 165 semops[0].sem_op = 1; 166 semops[0].sem_flg = SEM_UNDO | 167 (timeout != SM_TIME_FOREVER ? 0 : IPC_NOWAIT); 168 if (timeout == SM_TIME_IMMEDIATE || timeout == SM_TIME_FOREVER) 169 return semop(semid, semops, 1); 170 do 171 { 172 r = semop(semid, semops, 1); 173 if (r == 0) 174 return r; 175 sleep(1); 176 --timeout; 177 } while (timeout > 0); 178 return r; 179 } 180 181 /* 182 ** SM_SEM_GET -- get semaphore value. 183 ** 184 ** Parameters: 185 ** semid -- id for semaphores. 186 ** semnum -- number of semaphore. 187 ** 188 ** Returns: 189 ** value of semaphore on success. 190 ** < 0 on failure. 191 */ 192 193 int 194 sm_sem_get(semid, semnum) 195 int semid; 196 int semnum; 197 { 198 int semval; 199 200 if ((semval = semctl(semid, semnum, GETVAL, NULL)) < 0) 201 return -1; 202 return semval; 203 } 204 205 /* 206 ** SM_SEMSETOWNER -- set owner/group/mode of semaphores. 207 ** 208 ** Parameters: 209 ** semid -- id for semaphores. 210 ** uid -- uid to use 211 ** gid -- gid to use 212 ** mode -- mode to use 213 ** 214 ** Returns: 215 ** 0 on success. 216 ** < 0 on failure. 217 */ 218 219 int 220 sm_semsetowner(semid, uid, gid, mode) 221 int semid; 222 uid_t uid; 223 gid_t gid; 224 mode_t mode; 225 { 226 int r; 227 struct semid_ds semidds; 228 union semun { 229 int val; 230 struct semid_ds *buf; 231 ushort *array; 232 } arg; 233 234 memset(&semidds, 0, sizeof(semidds)); 235 arg.buf = &semidds; 236 if ((r = semctl(semid, 1, IPC_STAT, arg)) < 0) 237 return r; 238 semidds.sem_perm.uid = uid; 239 semidds.sem_perm.gid = gid; 240 semidds.sem_perm.mode = mode; 241 if ((r = semctl(semid, 1, IPC_SET, arg)) < 0) 242 return r; 243 return 0; 244 } 245 #endif /* SM_CONF_SEM */ 246