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> 11SM_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 <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 35int 36sm_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 71error: 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 91int 92sm_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 111int 112sm_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 150int 151sm_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 193int 194sm_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 219int 220sm_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