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