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 #include <sm/gen.h> 11 SM_RCSID("@(#)$Id: sem.c,v 1.13 2005/08/12 20:39:59 ca Exp $") 12 13 #if SM_CONF_SEM 14 # include <stdlib.h> 15 # include <unistd.h> 16 # include <sm/sem.h> 17 # include <sm/heap.h> 18 # include <errno.h> 19 20 /* 21 ** SM_SEM_START -- initialize semaphores 22 ** 23 ** Parameters: 24 ** key -- key for semaphores. 25 ** nsem -- number of semaphores. 26 ** semflg -- flag for semget(), if 0, use a default. 27 ** owner -- create semaphores. 28 ** 29 ** Returns: 30 ** id for semaphores. 31 ** < 0 on failure. 32 */ 33 34 int 35 sm_sem_start(key, nsem, semflg, owner) 36 key_t key; 37 int nsem; 38 int semflg; 39 bool owner; 40 { 41 int semid, i, err; 42 unsigned short *semvals; 43 44 semvals = NULL; 45 if (semflg == 0) 46 semflg = (SEM_A|SEM_R)|((SEM_A|SEM_R) >> 3); 47 if (owner) 48 semflg |= IPC_CREAT|IPC_EXCL; 49 semid = semget(key, nsem, semflg); 50 if (semid < 0) 51 goto error; 52 53 if (owner) 54 { 55 union semun semarg; 56 57 semvals = (unsigned short *) sm_malloc(nsem * sizeof semvals); 58 if (semvals == NULL) 59 goto error; 60 semarg.array = semvals; 61 62 /* initialize semaphore values to be available */ 63 for (i = 0; i < nsem; i++) 64 semvals[i] = 1; 65 if (semctl(semid, 0, SETALL, semarg) < 0) 66 goto error; 67 } 68 return semid; 69 70 error: 71 err = errno; 72 if (semvals != NULL) 73 sm_free(semvals); 74 if (semid >= 0) 75 sm_sem_stop(semid); 76 return (err > 0) ? (0 - err) : -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